diff --git a/support-lib/swift/DJData.swift b/support-lib/swift/DJData.swift index c9a0fcc8..6a99b499 100644 --- a/support-lib/swift/DJData.swift +++ b/support-lib/swift/DJData.swift @@ -1,6 +1,10 @@ import DjinniSupportCxx import Foundation +// DataView and DataRef are bridged to `NSData` instead of `Data` because `Data` +// uses small buffer optimization and it does not always provide a stable +// pointer that can be safely accessed in C++ (the pointer we can get from a +// small Data object will only work within the scope of `withUnsafeBytes` block) public enum DataViewMarshaller: Marshaller { public typealias SwiftType = NSData public static func fromCpp(_ v: djinni.swift.AnyValue) -> SwiftType { @@ -11,7 +15,8 @@ public enum DataViewMarshaller: Marshaller { return djinni.swift.makeRangeValue(s.bytes, s.length) } } - +// The C++ side implementation of DataRef uses CFData which is toll-free bridged +// to NSData. public enum DataRefMarshaller: Marshaller { public typealias SwiftType = NSData public static func fromCpp(_ v: djinni.swift.AnyValue) -> SwiftType { diff --git a/support-lib/swift/DJFuture.swift b/support-lib/swift/DJFuture.swift index 382abe63..b267f28f 100644 --- a/support-lib/swift/DJFuture.swift +++ b/support-lib/swift/DJFuture.swift @@ -2,12 +2,15 @@ import DjinniSupportCxx import Foundation import Combine +// DJinni future<> maps to Combine.Future<> in Swift public typealias DJFuture = Future +// Type erased interface for PromiseHolder because in futureCb() we don't have +// the type parameter. protocol AbstractPromiseHolder: AnyObject { func fulfillPromise(value: UnsafePointer) } - +// The Swift Future wrapper object that can be fulfilled by a C++ call class PromiseHolder: AbstractPromiseHolder { var promise: DJFuture.Promise init(marshaller: T.Type, promise: @escaping DJFuture.Promise) { @@ -21,7 +24,9 @@ class PromiseHolder: AbstractPromiseHolder { } } } - +// A C++ friendly function. This is passed to C++ as the continuation routine of +// the C++ future. It calls the PromiseHolder and forwards the C++ future's +// result or error to the Swift future. public func futureCb( ptr: UnsafeMutableRawPointer?, result: UnsafeMutablePointer?) @@ -31,6 +36,8 @@ public func futureCb( promiseHolder.fulfillPromise(value:result!) } +// A C++ friendly function to release the subscription token stored with the C++ +// future value. public func cleanupCb(psubscription: UnsafeMutableRawPointer?) -> Void { let _ = Unmanaged.fromOpaque(psubscription!).takeRetainedValue() } @@ -39,15 +46,19 @@ public enum FutureMarshaller: Marshaller { public typealias SwiftType = DJFuture public static func fromCpp(_ v: djinni.swift.AnyValue) -> SwiftType { return Future() { promise in + // Allocate the Swift future wrapper let promiseHolder = PromiseHolder(marshaller: T.self, promise: promise) let promiseHolderPtr = Unmanaged.passRetained(promiseHolder).toOpaque() + // And connect it with the C++ future withUnsafePointer(to: v) { p in djinni.swift.setFutureCb(p, futureCb, promiseHolderPtr) } } } public static func toCpp(_ s: SwiftType) -> djinni.swift.AnyValue { + // Create a C++ future var futureValue = djinni.swift.makeFutureValue(cleanupCb) + // Connect it with the Swift future let subscription = s.sink { completion in if case let .failure(e) = completion { var errorValue = djinni.swift.makeVoidValue() @@ -58,6 +69,7 @@ public enum FutureMarshaller: Marshaller { var cppValue = T.toCpp(v) djinni.swift.setFutureResult(&futureValue, &cppValue) } + // Store the subscription token so that the connection remains alive. let pSubscription = Unmanaged.passRetained(subscription).toOpaque() djinni.swift.storeSubscription(&futureValue, pSubscription) return futureValue diff --git a/support-lib/swift/DJMarshal.swift b/support-lib/swift/DJMarshal.swift index d5d8f574..905f097d 100644 --- a/support-lib/swift/DJMarshal.swift +++ b/support-lib/swift/DJMarshal.swift @@ -1,12 +1,14 @@ import DjinniSupportCxx import Foundation +// Common interface for all Swift type marshallers +// The C++ type is always djinni.swift.AnyValue public protocol Marshaller { associatedtype SwiftType static func fromCpp(_ v: djinni.swift.AnyValue) -> SwiftType static func toCpp(_ s: SwiftType) -> djinni.swift.AnyValue } - +// Djinni generated enums are always backed by Int32 public enum EnumMarshaller: Marshaller where T.RawValue == Int32 { public typealias SwiftType = T public static func fromCpp(_ v: djinni.swift.AnyValue) -> SwiftType { @@ -16,7 +18,7 @@ public enum EnumMarshaller: Marshaller where T.RawValue == return djinni.swift.I32.fromCpp(s.rawValue) } } - +// All integer types smaller than 32-bit are handled by this public enum SmallIntMarshaller: Marshaller { public typealias SwiftType = T public static func fromCpp(_ v: djinni.swift.AnyValue) -> SwiftType { @@ -26,6 +28,7 @@ public enum SmallIntMarshaller: Marshaller { return djinni.swift.I32.fromCpp(Int32(s)) } } +// 64-bit integer public enum I64Marshaller: Marshaller { public typealias SwiftType = Int64 public static func fromCpp(_ v: djinni.swift.AnyValue) -> SwiftType { @@ -35,6 +38,7 @@ public enum I64Marshaller: Marshaller { return djinni.swift.I64.fromCpp(s) } } +// Both float and double are marshalled to double values public enum FloatMarshaller: Marshaller { public typealias SwiftType = T public static func fromCpp(_ v: djinni.swift.AnyValue) -> SwiftType { @@ -44,6 +48,7 @@ public enum FloatMarshaller: Marshaller { return djinni.swift.F64.fromCpp(Double(s)) } } +// Bool is marshalled as Int32 (0 or 1) public enum BoolMarshaller: Marshaller { public typealias SwiftType = Bool public static func fromCpp(_ v: djinni.swift.AnyValue) -> SwiftType { @@ -53,7 +58,7 @@ public enum BoolMarshaller: Marshaller { return djinni.swift.I32.fromCpp(s ? 1 : 0) } } - +// Aliases for number types public typealias I8Marshaller = SmallIntMarshaller public typealias I16Marshaller = SmallIntMarshaller public typealias I32Marshaller = SmallIntMarshaller @@ -158,6 +163,7 @@ public enum ListMarshaller: Marshaller { } } +// Swift don't need to box primitive types in arrays so they are identical to list public typealias ArrayMarshaller = ListMarshaller public enum SetMarshaller: Marshaller where T.SwiftType: Hashable { diff --git a/support-lib/swift/DJOutcome.swift b/support-lib/swift/DJOutcome.swift index dbc2ca1e..2ce143dc 100644 --- a/support-lib/swift/DJOutcome.swift +++ b/support-lib/swift/DJOutcome.swift @@ -1,6 +1,11 @@ import DjinniSupportCxx import Foundation +// `outcome` is marshalled as a composite value +// 1. If the `outcome` object contains a successful value, then it's the [0] +// element in the composite value +// 2. If the `outcome` object contains an error value, then element [0] is void, +// and element [1] is the error value. public enum OutcomeMarshaller: Marshaller where Err.SwiftType: Error { public typealias SwiftType = Result diff --git a/support-lib/swift/DjinniSupport.swift b/support-lib/swift/DjinniSupport.swift index 09ad6e08..379e90c2 100644 --- a/support-lib/swift/DjinniSupport.swift +++ b/support-lib/swift/DjinniSupport.swift @@ -1,25 +1,39 @@ import DjinniSupportCxx import Foundation +// Define a C++ vtable like data structure for dispatching proxy methods to +// protocol methods. Each entry in the table is function pointer that takes 3 +// parameters +// - The object instance (that conforms to the protocol) +// - The parameter list +// - The return value (output parameter) +// The return value has to be an output parameter instead of the function's +// return type, otherwise the Swift compiler will crash (if this crash is fixed +// in a later version of the compiler, we may change this). public typealias Vtbl = [(T, UnsafePointer?, UnsafeMutablePointer?) throws -> Void] -public class GenericProtocolWrapperContext { - public func dispatch(idx: Int32, params: UnsafePointer?, ret: UnsafeMutablePointer?) -> Void { - fatalError("pure virtual") - } - public func getInst() -> AnyObject { - fatalError("pure virtual") - } +// Type erased interface for ProtocolWrapperContext. We don't have the type +// parameter T for ProtocolWrapperContext inside dispatcherProtocalCall (called +// by C++ code) +protocol GenericProtocolWrapperContext: AnyObject { + func dispatch(idx: Int32, params: UnsafePointer?, ret: UnsafeMutablePointer?) -> Void + func getInst() -> AnyObject } -public final class ProtocolWrapperContext: GenericProtocolWrapperContext { +// The bridge between C++ caller and Swift protocol. We store +// - The object instance (that conforms to our protocol) +// - The dispatch table for each callable method in the protocol +final class ProtocolWrapperContext: GenericProtocolWrapperContext { var inst: T var vtbl: Vtbl - public init(inst: T, vtbl: Vtbl) { + init(inst: T, vtbl: Vtbl) { self.inst = inst self.vtbl = vtbl } - public override func dispatch(idx: Int32, params: UnsafePointer?, ret: UnsafeMutablePointer?) -> Void { + func dispatch(idx: Int32, params: UnsafePointer?, ret: UnsafeMutablePointer?) -> Void { + // No Swift error will cross the language boundary. They are converted + // to `ErrorValue`s which will be translated into C++ exceptions on the + // other side. do { try vtbl[Int(idx)](inst, params, ret) } catch let error as DjinniError { @@ -28,71 +42,85 @@ public final class ProtocolWrapperContext: GenericProtocolWrapperContext { djinni.swift.setErrorMessage(ret, std.string(String(describing: error))) } } - public override func getInst() -> AnyObject { + func getInst() -> AnyObject { return inst as AnyObject } } +// This function has a C++ friendly signature. It is passed to C++ and will be +// used by proxy objects to dispatch protocol calls. public func dispatcherProtocalCall( - ptr: UnsafeMutableRawPointer?, - idx: Int32, - params: UnsafePointer?, - ret: UnsafeMutablePointer?) + ptr: UnsafeMutableRawPointer?, // The Swift protocol wrapper object as an opaque pointer + idx: Int32, // The method index (starting from 0) + params: UnsafePointer?, // Input parameters from C++ caller + ret: UnsafeMutablePointer?) // Return value that will be passed back to C++ -> Void { guard let pctx = ptr else { return } - if (idx < 0) { - // release and destroy the context - let ctx = Unmanaged.fromOpaque(pctx).takeRetainedValue() - print("swift proxy cache before destroy", SwiftProxyCache.shared.mapPtrToProxy) + let ctx = Unmanaged.fromOpaque(pctx).takeUnretainedValue() as! GenericProtocolWrapperContext + if (idx >= 0) { + // Dynamic dispatch on the vtbl. We use `takeUnretainedValue` here + // because we want to keep the wrapper object alive inside the C++ side + // proxy (inherits ProtocolWrapper). + ctx.dispatch(idx: idx, params: params, ret: ret) + } else { + // If the index is negative, release and destroy the context. We do + // this when the C++ side proxy (ProtocolWrapper) is destroyed. let key = Unmanaged.passUnretained(ctx.getInst()).toOpaque() SwiftProxyCache.shared.mapPtrToProxy.removeValue(forKey: key) - print("swift proxy cache after destroy", SwiftProxyCache.shared.mapPtrToProxy) - } else { - // dynamic dispatch on the vtbl - let ctx = Unmanaged.fromOpaque(pctx).takeUnretainedValue() - ctx.dispatch(idx: idx, params: params, ret: ret) } } +// Base class for a Swift callable proxy of a C++ object open class CppProxy { + // Stores a C++ interface. A C++ interface value is a double pointer: + // 1. A shared_ptr<> that keeps the C++ implementation object alive + // 2. A shared_ptr<> to a ProtocolWrapper that facilitates dispatching public var inst: djinni.swift.AnyValue public init(inst: djinni.swift.AnyValue) { self.inst = inst } deinit { - destroyCppProxy(inst) + // Remove the C++ proxy pointer from the proxy cache + withUnsafePointer(to: inst) { p in + let info = djinni.swift.getInterfaceInfo(p) + CppProxyCache.shared.mapPtrToProxy.removeValue(forKey: info.cppPointer) + } } } class CppProxyCache { static let shared = CppProxyCache() - // c++ objects in swift + // C++ objects in swift. + // Key: raw C++ implementation object pointer + // Value: Swift callable proxy converted to an *Unretained* (weak) opaque pointer var mapPtrToProxy: [UnsafeRawPointer: UnsafeMutableRawPointer] = [:] } class SwiftProxyCache { static let shared = SwiftProxyCache() - // swift objects in c++ + // Swift objects in c++ + // Key: Swift implementation object converted to an *Unretained* opaque pointer + // Value : Weak proxy, no ownership, but can be converted to a C++ callable strong proxy var mapPtrToProxy: [UnsafeMutableRawPointer: djinni.swift.WeakSwiftProxy] = [:] } -// 1. object is a an existing cpp proxy : return cpp proxy -// 2. object is a an existing swift proxy: unwrap the original swift object -// 3. need to create a new proxy : call newProxyFunc +// 1. Object is a an existing cpp proxy : return cpp proxy +// 2. Object is a an existing swift proxy: unwrap the original swift object +// 3. Need to create a new proxy : call newProxyFunc public func cppInterfaceToSwift(_ c: djinni.swift.AnyValue, _ newProxyFunc: ()->I) -> I { return withUnsafePointer(to: c) { p in let info = djinni.swift.getInterfaceInfo(p) - // for 1. check the cpp proxy cache + // 1. Check the CppProxyCache if let s = CppProxyCache.shared.mapPtrToProxy[info.cppPointer] { return Unmanaged.fromOpaque(s).takeUnretainedValue() as! I } - // for 2. check if c++ ptr exists in SwiftProxyCache.mapCPtrToSwift + // 2. Check if c++ ptr exists in SwiftProxyCache if let pctx = info.ctxPointer { - let ctx = Unmanaged.fromOpaque(pctx).takeUnretainedValue() + let ctx = Unmanaged.fromOpaque(pctx).takeUnretainedValue() as! GenericProtocolWrapperContext return ctx.getInst() as! I } - // 3. + // 3. Create new proxy and store unretained (weak) pointer in CppProxyCache let newProxy = newProxyFunc() CppProxyCache.shared.mapPtrToProxy[info.cppPointer] = Unmanaged.passUnretained(newProxy as AnyObject).toOpaque() return newProxy @@ -104,35 +132,31 @@ public func cppInterfaceToSwift(_ c: djinni.swift.AnyValue, // 3. need to create a new proxy : call newProxyFunc public func swiftInterfaceToCpp(_ s: I, _ newProxyFunc: ()->djinni.swift.AnyValue) -> djinni.swift.AnyValue { - // 1. try cast to CppProxy and unwrap + // 1. Try cast to CppProxy and unwrap if let cppproxy = s as? CppProxy { return cppproxy.inst } - // 2. check swift proxy cache + // 2. Check swift proxy cache let key = Unmanaged.passUnretained(s as AnyObject).toOpaque() if let weakProxy = SwiftProxyCache.shared.mapPtrToProxy[key] { return djinni.swift.strongify(weakProxy) } - // 3. + // 3. Create new proxy and store weak reference in SwiftProxyCache let newProxy = newProxyFunc() SwiftProxyCache.shared.mapPtrToProxy[key] = djinni.swift.weakify(newProxy) return newProxy } +// Shortcut function to create a Swift protocol wrapper context and return its +// *Retained* pointer. The returned pointer is owned by the C++ side +// ProtocolWrapper, and released in ProtocolWrapper::~ProtocolWrapper() by +// sending a dispatch request with index -1. public func ctxPtr (_ s: I, _ vtbl: Vtbl) -> UnsafeMutableRawPointer { let ctx = ProtocolWrapperContext(inst: s, vtbl: vtbl) return Unmanaged.passRetained(ctx).toOpaque() } -public func destroyCppProxy(_ inst: djinni.swift.AnyValue) { - withUnsafePointer(to: inst) { p in - let info = djinni.swift.getInterfaceInfo(p) - print("before destroy cppproxycache entry", CppProxyCache.shared.mapPtrToProxy) - CppProxyCache.shared.mapPtrToProxy.removeValue(forKey: info.cppPointer) - print("after destroy cppproxycache entry", CppProxyCache.shared.mapPtrToProxy) - } -} - +// Wraps C++ ErrorValue as a Swift throwable Error public class DjinniError: Error { var wrapped: djinni.swift.ErrorValue init(_ wrapped: djinni.swift.ErrorValue) { @@ -144,6 +168,7 @@ public class DjinniError: Error { public var errorMessage: String { return String(wrapped.msg) } } +// Called by stubs to convert C++ exceptions stored as ErrorValue to Swift errors public func handleCppErrors(_ ret: UnsafePointer) throws { if (djinni.swift.isError(ret)) { throw DjinniError(djinni.swift.getError(ret)) diff --git a/support-lib/swiftxx/Future_swift.cpp b/support-lib/swiftxx/Future_swift.cpp index 160e0b27..8fa74d50 100644 --- a/support-lib/swiftxx/Future_swift.cpp +++ b/support-lib/swiftxx/Future_swift.cpp @@ -3,22 +3,22 @@ namespace djinni::swift { void setFutureCb(const AnyValue* futureValue, FutureCb cb, void* ctx) { - auto holder = std::dynamic_pointer_cast(std::get(*futureValue)); + auto holder = std::dynamic_pointer_cast(std::get(*futureValue)); holder->setFutureCb(cb, ctx); } AnyValue makeFutureValue(CleanupCb cleanup) { - OpaqueValuePtr holder = std::make_shared>(cleanup); + OpaqueValuePtr holder = std::make_shared(cleanup); return {holder}; } void setFutureResult(const AnyValue* futureValue, const AnyValue* futureResult) { - auto holder = std::dynamic_pointer_cast>(std::get(*futureValue)); + auto holder = std::dynamic_pointer_cast(std::get(*futureValue)); holder->setValue(futureResult); } void storeSubscription(const AnyValue* futureValue, void* subscription) { - auto holder = std::dynamic_pointer_cast>(std::get(*futureValue)); + auto holder = std::dynamic_pointer_cast(std::get(*futureValue)); holder->subscription = subscription; } diff --git a/support-lib/swiftxx/Future_swift.hpp b/support-lib/swiftxx/Future_swift.hpp index 5d04316a..93ab028d 100644 --- a/support-lib/swiftxx/Future_swift.hpp +++ b/support-lib/swiftxx/Future_swift.hpp @@ -5,41 +5,38 @@ namespace djinni::swift { +// Swift function prototypes called by C++ typedef void (*FutureCb)(void* ctx, AnyValue* result); typedef void (*CleanupCb)(void* subscription); -struct AbstractFutureHolder: OpaqueValue { - virtual ~AbstractFutureHolder() = default; +// C++ function declarations called by Swift +void setFutureCb(const AnyValue* futureValue, FutureCb cb, void* ctx); +AnyValue makeFutureValue(CleanupCb cleanup); +void setFutureResult(const AnyValue* futureValue, const AnyValue* futureResult); +void storeSubscription(const AnyValue* futureValue, void* subscription); + +// Common interface for a Swift accessible C++ future +struct AbstractCppFutureHolder: OpaqueValue { + virtual ~AbstractCppFutureHolder() = default; virtual void setFutureCb(FutureCb cb, void* ctx) = 0; }; +// Holds a C++ future that returns a RESULT type template -struct FutureHolder: AbstractFutureHolder { +struct CppFutureHolder: AbstractCppFutureHolder { using CppResType = typename RESULT::CppType; djinni::Future future; - explicit FutureHolder(djinni::Future f) : future(std::move(f)) {} + explicit CppFutureHolder(djinni::Future f) : future(std::move(f)) {} - void setFutureCb(FutureCb cb, void* ctx) override { - future.then([cb, ctx] (Future f) { - try { - auto v = RESULT::fromCpp(f.get()); - cb(ctx, &v); - } catch (ErrorValue& e) { - AnyValue errorValue = e; - cb(ctx, &errorValue); - } - }); - } -}; -template<> -struct FutureHolder: AbstractFutureHolder { - djinni::Future future; - explicit FutureHolder(djinni::Future f) : future(std::move(f)) {} + template + static AnyValue getFutureResult(Future& f) {return RESULT::fromCpp(f.get());} + template<> + static AnyValue getFutureResult(Future& f) {return makeVoidValue();} void setFutureCb(FutureCb cb, void* ctx) override { - future.then([cb, ctx] (Future f) { + future.then([cb, ctx] (Future f) { try { - auto v = makeVoidValue(); + auto v = getFutureResult(f); cb(ctx, &v); } catch (ErrorValue& e) { AnyValue errorValue = e; @@ -49,30 +46,19 @@ struct FutureHolder: AbstractFutureHolder { } }; -void setFutureCb(const AnyValue* futureValue, FutureCb cb, void* ctx); -AnyValue makeFutureValue(CleanupCb cleanup); -void setFutureResult(const AnyValue* futureValue, const AnyValue* futureResult); -void storeSubscription(const AnyValue* futureValue, void* subscription); - -struct AnyValueFutureAdapter { - using CppType = AnyValue; - static AnyValue fromCpp(CppType c) {return c;} -}; - -template<> -struct FutureHolder: AbstractFutureHolder { +// Maintains the link from a Swift future to a C++ accessible future +struct SwiftFutureHolder: OpaqueValue { djinni::Promise promise; std::shared_ptr> future; void* subscription = nullptr; CleanupCb cleanup; - FutureHolder(CleanupCb cleanup) { + SwiftFutureHolder(CleanupCb cleanup) { this->cleanup = cleanup; this->future = std::make_shared>(promise.getFuture()); } - ~FutureHolder() { + ~SwiftFutureHolder() override { cleanup(subscription); } - void setFutureCb(FutureCb cb, void* ctx) override {} void setValue(const AnyValue* futureValue) { promise.setValue(*futureValue); } @@ -82,61 +68,38 @@ template class FutureAdaptor { using CppResType = typename RESULT::CppType; + + template + static void setValue(Promise& p, const AnyValue& res) {p.setValue(RESULT::toCpp(res));} + template<> + static void setValue(Promise& p, const AnyValue& res) {p.setValue();} public: using CppType = Future; static CppType toCpp(const AnyValue& o) { - auto holder = std::dynamic_pointer_cast>(std::get(o)); + // If already a C++ future (can this happen?), just return the wrapped future + auto holder = std::dynamic_pointer_cast>(std::get(o)); if (holder) { return std::move(holder->future); } - auto anyHolder = std::dynamic_pointer_cast>(std::get(o)); + // Acquire the holder for Swift future + auto swiftHolder = std::dynamic_pointer_cast(std::get(o)); Promise p; auto f = p.getFuture(); - anyHolder->future->then([p = std::move(p)] (Future f) mutable { - auto res = f.get(); - if (std::holds_alternative(res)) { - const auto& e = std::get(res); - p.setException(e); - } else { - p.setValue(RESULT::toCpp(res)); - } - }); - return f; - } - static AnyValue fromCpp(CppType c) { - OpaqueValuePtr holder = std::make_shared>(std::move(c)); - return {holder}; - } -}; - -template <> -class FutureAdaptor -{ -public: - using CppType = Future; - - static CppType toCpp(const AnyValue& o) { - auto holder = std::dynamic_pointer_cast>(std::get(o)); - if (holder) { - return std::move(holder->future); - } - auto anyHolder = std::dynamic_pointer_cast>(std::get(o)); - Promise p; - auto f = p.getFuture(); - anyHolder->future->then([p = std::move(p)] (Future f) mutable { + // And return a C++ future connected to it + swiftHolder->future->then([p = std::move(p)] (Future f) mutable { auto res = f.get(); if (std::holds_alternative(res)) { const auto& e = std::get(res); p.setException(e); } else { - p.setValue(); + setValue(p, res); } }); return f; } static AnyValue fromCpp(CppType c) { - OpaqueValuePtr holder = std::make_shared>(std::move(c)); + OpaqueValuePtr holder = std::make_shared>(std::move(c)); return {holder}; } }; diff --git a/support-lib/swiftxx/djinni_support.cpp b/support-lib/swiftxx/djinni_support.cpp index 683aa5e2..ca97a656 100644 --- a/support-lib/swiftxx/djinni_support.cpp +++ b/support-lib/swiftxx/djinni_support.cpp @@ -69,7 +69,6 @@ AnyValue strongify(const WeakSwiftProxy& v) { InterfaceInfo getInterfaceInfo(const AnyValue* v) { auto i = std::get(*v); - // return {i.ptr.get(), i.sptr.get()}; return {i.ptr.get(), i.sptr ? i.sptr->ctx() : nullptr }; } diff --git a/support-lib/swiftxx/djinni_support.hpp b/support-lib/swiftxx/djinni_support.hpp index 1ad2af37..0045e2b3 100644 --- a/support-lib/swiftxx/djinni_support.hpp +++ b/support-lib/swiftxx/djinni_support.hpp @@ -79,6 +79,7 @@ struct CompositeValue { struct ParameterList: CompositeValue {}; +// Swift callable functions AnyValue makeStringValue(const char* bytes, size_t size); AnyValue makeBinaryValue(const void* bytes, size_t size); RangeValue getBinaryRange(const AnyValue& v);