git » sdk » commit 35872f4

Initial support for Map and some array fixes

author Stephen Paul Weber
2025-05-12 13:16:34 UTC
committer Stephen Paul Weber
2025-05-12 13:36:16 UTC
parent 28fba16b8f675fb7228fb65cb3cb1b2bc7684ae3

Initial support for Map and some array fixes

HaxeCBridge.hx +41 -1
HaxeSwiftBridge.hx +56 -2

diff --git a/HaxeCBridge.hx b/HaxeCBridge.hx
index 8c105c8..741713e 100644
--- a/HaxeCBridge.hx
+++ b/HaxeCBridge.hx
@@ -257,8 +257,37 @@ class HaxeCBridge {
 					}
 			case FProp(get, set, t, e):
 					switch (t) {
+					case TPath(path) if (path.name == "Map"):
+						if (get != "null" && get != "never") {
+							final ptrTo = convertSecondaryType(TPath({ name: "Array", pack: [], params: [path.params[0]] })).args[0];
+							final ptrT = TPath({name: "RawPointer", pack: ["cpp"], params: [TPType(ptrTo)]});
+							fields.insert(insertTo, {
+								name: field.name + "_keys__fromC",
+								doc: field.doc + " (keys)",
+								meta: [{name: "HaxeCBridge.wrapper", params: [], pos: field.pos}],
+								access: field.access,
+								pos: field.pos,
+								kind: FFun({ret: TPath({name: "SizeT", pack: ["cpp"]}), params: [], args: [{name: "outPtr", type: ptrT}], expr: macro { final x = Lambda.array({iterator: $i{field.name}.keys }); if (outPtr != null) { cpp.Pointer.fromRaw(outPtr).set_ref(x); } return x.length; } })
+							});
+
+							final ptrToV = convertSecondaryType(TPath({ name: "Array", pack: [], params: [path.params[1]] })).args[0];
+							final ptrTV = TPath({name: "RawPointer", pack: ["cpp"], params: [TPType(ptrTo)]});
+							fields.insert(insertTo, {
+								name: field.name + "_keys__fromC",
+								doc: field.doc + " (values)",
+								meta: [{name: "HaxeCBridge.wrapper", params: [], pos: field.pos}],
+								access: field.access,
+								pos: field.pos,
+								kind: FFun({ret: TPath({name: "SizeT", pack: ["cpp"]}), params: [], args: [{name: "outPtr", type: ptrTV}], expr: macro { final x = Lambda.array($i{field.name}); if (outPtr != null) { cpp.Pointer.fromRaw(outPtr).set_ref(x); } return x.length; } })
+							});
+							insertTo++;
+						}
+						if (set != "null" && set != "never") {
+							throw "Cannot bridge Map<> setter to C";
+						}
 					case TPath(path) if (path.name == "Array"):
-						final ptrT = TPath({name: "RawPointer", pack: ["cpp"], params: [TPType(TPath({name: "HaxeArray", pack: [], params: path.params.map(t -> convertSecondaryTP(t))}))]});
+						final ptrTo = convertSecondaryType(t).args[0];
+						final ptrT = TPath({name: "RawPointer", pack: ["cpp"], params: [TPType(ptrTo)]});
 						fields.insert(insertTo, {
 							name: field.name + "__fromC",
 							doc: field.doc,
@@ -304,6 +333,17 @@ class HaxeCBridge {
 							pos: field.pos,
 							kind: FFun({ret: TPath({name: "SizeT", pack: ["cpp"]}), params: [], args: [{name: "outPtr", type: ptrT}], expr: macro { final x = $i{field.name}; if (outPtr != null) { cpp.Pointer.fromRaw(outPtr).set_ref(x); } return x.length; } })
 						});
+						if (!field.access.contains(AFinal)) {
+							final cptrT = TPath({name: "ConstPointer", pack: ["cpp"], params: path.params.map(tp -> convertSecondaryTP(tp))});
+							fields.insert(insertTo, {
+								name: "set_" + field.name + "__fromC",
+								doc: field.doc,
+								meta: [{name: "HaxeCBridge.wrapper", params: [], pos: field.pos}],
+								access: field.access,
+								pos: field.pos,
+								kind: FFun({ret: TPath({name: "Void", pack: []}), params: [], args: [{name: "inPtr", type: cptrT}, {name: "count", type: TPath({name: "SizeT", pack: ["cpp"]})}], expr: macro $i{field.name} = inPtr.reinterpret().toUnmanagedArray(count).copy() })
+							});
+						}
 						insertTo++;
 					default:
 						fields.insert(insertTo, {
diff --git a/HaxeSwiftBridge.hx b/HaxeSwiftBridge.hx
index 9867325..5de16d4 100644
--- a/HaxeSwiftBridge.hx
+++ b/HaxeSwiftBridge.hx
@@ -233,8 +233,8 @@ class HaxeSwiftBridge {
 		return switch type {
 		case TInst(_.get().name => "String", params):
 			return item;
-		case TInst(_.get().name => "Array", [TInst(_)]):
-			return item + ".map { $0.o }";
+		case TInst(_.get().name => "Array", [param = TInst(_)]):
+			return item + ".map { " + castToC("$0", param, canNull) + " }";
 		case TInst(_.get().name => "Array", [param]):
 			return item;
 		case TInst(_.get() => t, []):
@@ -344,6 +344,12 @@ class HaxeSwiftBridge {
 				builder.add(cFuncNameSet);
 				builder.add("(o, ");
 				builder.add(castToC("newValue", f.type));
+				switch TypeTools.followWithAbstracts(Context.resolveType(Context.toComplexType(f.type), Context.currentPos()), false) {
+				case TInst(_.get().name => "Array", [param]):
+					builder.add(", ");
+					builder.add("newValue.count");
+				default:
+				}
 				builder.add(")\n\t\t}\n");
 			}
 			builder.add("\t}\n\n");
@@ -572,6 +578,54 @@ class HaxeSwiftBridge {
 				return useString(UnsafePointer(mptr?.assumingMemoryBound(to: CChar.self)))
 			}
 
+			// From https://github.com/swiftlang/swift/blob/dfc3933a05264c0c19f7cd43ea0dca351f53ed48/stdlib/private/SwiftPrivate/SwiftPrivate.swift
+			public func scan<
+				S : Sequence, U
+			>(_ seq: S, _ initial: U, _ combine: (U, S.Iterator.Element) -> U) -> [U] {
+				var result: [U] = []
+				result.reserveCapacity(seq.underestimatedCount)
+				var runningResult = initial
+				for element in seq {
+					runningResult = combine(runningResult, element)
+					result.append(runningResult)
+				}
+				return result
+			}
+
+			// From https://github.com/swiftlang/swift/blob/dfc3933a05264c0c19f7cd43ea0dca351f53ed48/stdlib/private/SwiftPrivate/SwiftPrivate.swift
+			internal func withArrayOfCStrings<R>(
+				_ args: [String], _ body: ([UnsafePointer<CChar>?]) -> R
+			) -> R {
+				let argsCounts = Array(args.map { $0.utf8.count + 1 })
+				let argsOffsets = [ 0 ] + scan(argsCounts, 0, +)
+				let argsBufferSize = argsOffsets.last!
+
+				var argsBuffer: [UInt8] = []
+				argsBuffer.reserveCapacity(argsBufferSize)
+				for arg in args {
+					argsBuffer.append(contentsOf: arg.utf8)
+					argsBuffer.append(0)
+				}
+
+				return argsBuffer.withUnsafeMutableBufferPointer {
+					(argsBuffer) in
+					let ptr = UnsafeRawPointer(argsBuffer.baseAddress!).bindMemory(
+						to: CChar.self, capacity: argsBuffer.count)
+					var cStrings: [UnsafePointer<CChar>?] = argsOffsets.dropLast().map { ptr + $0 }
+					return body(cStrings)
+				}
+			}
+
+			internal func withOptionalArrayOfCStrings<R>(
+				_ args: [String]?, _ body: ([UnsafePointer<CChar>?]?) -> R
+			) -> R {
+				if let args = args {
+					return withArrayOfCStrings(args, body)
+				} else {
+					return body(nil)
+				}
+			}
+
 		')
 		+ queuedClasses.map(c -> convertQueuedClass(c.cls, c.namespace)).join("\n") + "\n"
 		+ { iterator: () -> knownEnums.keyValueIterator() }.map(e -> "public typealias " + e.key + " = " + e.value + "\n").join("\n")