| author | Stephen Paul Weber
<singpolyma@singpolyma.net> 2025-05-12 13:16:34 UTC |
| committer | Stephen Paul Weber
<singpolyma@singpolyma.net> 2025-05-12 13:36:16 UTC |
| parent | 28fba16b8f675fb7228fb65cb3cb1b2bc7684ae3 |
| 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")