diff options
Diffstat (limited to 'swift/src')
-rw-r--r-- | swift/src/Ice/Globals.swift | 5 | ||||
-rw-r--r-- | swift/src/Ice/Proxy.swift | 219 | ||||
-rw-r--r-- | swift/src/IceObjc/IceObjcLocalObject.h | 5 | ||||
-rw-r--r-- | swift/src/IceObjc/IceObjcObjectPrx.h | 10 | ||||
-rw-r--r-- | swift/src/IceObjc/IceObjcUtil.h | 1 | ||||
-rw-r--r-- | swift/src/IceObjc/ObjectPrx.mm | 58 | ||||
-rw-r--r-- | swift/src/IceObjc/Util.mm | 14 |
7 files changed, 267 insertions, 45 deletions
diff --git a/swift/src/Ice/Globals.swift b/swift/src/Ice/Globals.swift index a493ef0863e..b5205a0f0c1 100644 --- a/swift/src/Ice/Globals.swift +++ b/swift/src/Ice/Globals.swift @@ -10,17 +10,18 @@ import IceObjc // Factories are registed once, when this file is loaded -let factoriesInitialized: Bool = { +private let initialized: Bool = { ICEUtil.registerFactories(localException: LocalExceptionFactory.self, connectionInfo: ConnectionInfoFactory.self, endpointInfo: EndpointInfoFactory.self) + return true }() public func initialize(args: StringSeq = [], initData userInitData: InitializationData? = nil, configFile: String? = nil) throws -> Communicator { // Ensure factores are initialized - precondition(factoriesInitialized) + precondition(initialized) return try autoreleasepool { var initData = userInitData ?? InitializationData() diff --git a/swift/src/Ice/Proxy.swift b/swift/src/Ice/Proxy.swift index 1342325f496..d98e5663781 100644 --- a/swift/src/Ice/Proxy.swift +++ b/swift/src/Ice/Proxy.swift @@ -97,49 +97,104 @@ public extension ObjectPrx { hasOutParams: false) } + func ice_pingAsync() -> Promise<Void> { + return impl._invokeAsync(operation: "ice_ping", + mode: OperationMode.Nonmutating, + twowayOnly: false, + inParams: nil, + hasOutParams: false) { _ in } + } + func ice_isA(id: String, context: Context? = nil) throws -> Bool { let impl = self as! _ObjectPrxI let os = impl._createOutputStream() os.startEncapsulation() os.write(id) os.endEncapsulation() - let ins = try impl._invoke(operation: "ice_isA", + let istr = try impl._invoke(operation: "ice_isA", mode: .Nonmutating, twowayOnly: true, inParams: os, hasOutParams: true, context: context) - try ins.startEncapsulation() - let r: Bool = try ins.read() - try ins.endEncapsulation() + try istr.startEncapsulation() + let r: Bool = try istr.read() + try istr.endEncapsulation() return r } + func ice_isAAsync(id: String, context: Context? = nil) -> Promise<Bool> { + let impl = self as! _ObjectPrxI + let os = impl._createOutputStream() + os.startEncapsulation() + os.write(id) + os.endEncapsulation() + return impl._invokeAsync(operation: "ice_isA", + mode: .Nonmutating, + twowayOnly: true, + inParams: os, + hasOutParams: true, + context: context) { istr in + try istr.startEncapsulation() + let r: Bool = try istr.read() + try istr.endEncapsulation() + return r + } + } + func ice_id(context: Context? = nil) throws -> String { - let ins = try impl._invoke(operation: "ice_id", + let istr = try impl._invoke(operation: "ice_id", mode: .Nonmutating, twowayOnly: true, inParams: nil, hasOutParams: true, context: context) - try ins.startEncapsulation() - let id: String = try ins.read() - try ins.endEncapsulation() + try istr.startEncapsulation() + let id: String = try istr.read() + try istr.endEncapsulation() return id } + func ice_idAsync(context: Context? = nil) -> Promise<String> { + return impl._invokeAsync(operation: "ice_id", + mode: .Nonmutating, + twowayOnly: true, + inParams: nil, + hasOutParams: true, + context: context) { istr in + try istr.startEncapsulation() + let id: String = try istr.read() + try istr.endEncapsulation() + return id + } + } + func ice_ids(context: Context? = nil) throws -> StringSeq { - let ins = try impl._invoke(operation: "ice_ids", + let istr = try impl._invoke(operation: "ice_ids", mode: .Nonmutating, twowayOnly: true, inParams: nil, hasOutParams: true, context: context) - try ins.startEncapsulation() - let id: StringSeq = try ins.read() - try ins.endEncapsulation() + try istr.startEncapsulation() + let id: StringSeq = try istr.read() + try istr.endEncapsulation() return id } + + func ice_idsAsync(context: Context? = nil) -> Promise<StringSeq> { + return impl._invokeAsync(operation: "ice_ids", + mode: .Nonmutating, + twowayOnly: true, + inParams: nil, + hasOutParams: true, + context: context) { istr in + try istr.startEncapsulation() + let id: StringSeq = try istr.read() + try istr.endEncapsulation() + return id + } + } } open class _ObjectPrxI: ObjectPrx { @@ -456,7 +511,7 @@ open class _ObjectPrxI: ObjectPrx { return try fromICEObjectPrx(handle.ice_collocationOptimized(collocated)) } - public static func ice_read(from ins: InputStream) throws -> Self? { + public static func ice_read(from istr: InputStream) throws -> Self? { // // Unmarshaling of proxies is done in C++. Since we don't know how big this proxy will // be we pass the current buffer position and remaining buffer capacity. @@ -465,9 +520,9 @@ open class _ObjectPrxI: ObjectPrx { // The number of bytes consumed reading the proxy var bytesRead: Int = 0 - let buf = ins.getBuffer() - let encoding = ins.getEncoding() - let communicator = ins.getCommunicator() + let buf = istr.getBuffer() + let encoding = istr.getEncoding() + let communicator = istr.getCommunicator() // // Returns Any which is either NSNull or ICEObjectPrx @@ -507,38 +562,122 @@ open class _ObjectPrxI: ObjectPrx { } var ok = Bool() - let ins = try InputStream(communicator: self.communicator, - inputStream: handle.iceInvoke(op, mode: Int(mode.rawValue), - inParams: inParams?.getBytes(), - inSize: inParams?.getCount() ?? 0, - context: context, - returnValue: &ok)) + let istrHandle = try handle.iceInvoke(op, mode: Int(mode.rawValue), + inParams: inParams?.getBytes(), + inSize: inParams?.getCount() ?? 0, + context: context, + returnValue: &ok) + + let istr = InputStream(communicator: self.communicator, inputStream: istrHandle) + if self.isTwoway { - if !ok { - do { - try ins.startEncapsulation() - try ins.throwException() - } catch let error as UserException { - try ins.endEncapsulation() - for exceptionType in exceptions { - if exceptionType.isBase(of: type(of: error)) { - throw error - } - } - throw UnknownUserException(unknown: error.ice_id()) - } - // - // We let any all other error types propagate - // + guard ok else { + throw try _ObjectPrxI.unmarshalUserException(stream: istr, exceptions: exceptions) } if !hasOutParams { - try ins.skipEmptyEncapsulation() + try istr.skipEmptyEncapsulation() } } + return istr + } + } + + public func _invokeAsync<T>(operation op: String, + mode: OperationMode, + twowayOnly: Bool, + inParams: OutputStream?, + hasOutParams: Bool, + exceptions: [UserException.Type] = [], + context: Context? = nil, + sent sendCallback: ((Bool) -> Void)? = nil, + unmarshalResult: @escaping ((InputStream) throws -> T)) -> Promise<T> { - return ins + if twowayOnly, !self.isTwoway { + return Promise(error: TwowayOnlyException(operation: op)) } + // + // Create a pending promise. This way we can call into ObjC++ using the current thread + // + let (promise, resolver) = Promise<T>.pending() + + // + // Response callback + // + func response(ok: Bool, inputStream istrHandle: ICEInputStream) { + do { + let istr = InputStream(communicator: self.communicator, inputStream: istrHandle) + if self.isTwoway { + guard ok else { + throw try _ObjectPrxI.unmarshalUserException(stream: istr, exceptions: exceptions) + } + if !hasOutParams { + try istr.skipEmptyEncapsulation() + } + } + try resolver.fulfill(unmarshalResult(istr)) + } catch let error { + resolver.reject(error) + } + } + + // + // Exception callback + // + func exception(error: Error) { + resolver.reject(error) + } + + // + // Sent callback (optional) + // + var sent: ((Bool) -> Void)? + + if let s = sendCallback { + sent = { (sentSynchronously: Bool) -> Void in + // + // Use PromiseKit's return queue if not nil, otherwise use call with the current thread + // + if let queue = PromiseKit.conf.Q.return { + queue.async { + s(sentSynchronously) + } + } + s(sentSynchronously) + } + } + + do { + try autoreleasepool { + try handle.iceInvokeAsync(op, mode: Int(mode.rawValue), + inParams: inParams?.getBytes(), + inSize: inParams?.getCount() ?? 0, + context: context, + response: response, exception: exception, sent: sent) + } + } catch let error { + resolver.reject(error) + } + + return promise + + } + + static func unmarshalUserException(stream istr: InputStream, + exceptions: [UserException.Type]) throws -> Error { + do { + try istr.startEncapsulation() + try istr.throwException() + } catch let error as UserException { + try istr.endEncapsulation() + for exceptionType in exceptions { + if exceptionType.isBase(of: type(of: error)) { + return error + } + } + return UnknownUserException(unknown: error.ice_id()) + } + return UnknownUserException(unknown: "") } public static func checkedCast<ProxyImpl>(prx: ObjectPrx, diff --git a/swift/src/IceObjc/IceObjcLocalObject.h b/swift/src/IceObjc/IceObjcLocalObject.h index 56c923a826d..6d01bbd4a16 100644 --- a/swift/src/IceObjc/IceObjcLocalObject.h +++ b/swift/src/IceObjc/IceObjcLocalObject.h @@ -13,9 +13,8 @@ NS_ASSUME_NONNULL_BEGIN @interface ICELocalObject : NSObject // -// We hold a weak referece the (possile) Swift class which has a handle to -// this local object. That way we can keep it in the cache and later recover -// the Swift object. +// We hold a weak referece to the (possile) Swift object which has a handle to +// this ICELocalObject. That way we can keep recover the Swift object later. // @property (weak, nonatomic, nullable) id swiftRef; -(instancetype) init ICE_SWIFT_UNAVAILABLE(""); diff --git a/swift/src/IceObjc/IceObjcObjectPrx.h b/swift/src/IceObjc/IceObjcObjectPrx.h index 50b0ec0b2af..f690fa7300d 100644 --- a/swift/src/IceObjc/IceObjcObjectPrx.h +++ b/swift/src/IceObjc/IceObjcObjectPrx.h @@ -101,6 +101,16 @@ NS_ASSUME_NONNULL_BEGIN returnValue:(bool*)returnValue error:(NSError* _Nullable * _Nullable)error; +-(BOOL) iceInvokeAsync:(NSString* _Nonnull)op + mode:(NSInteger)mode + inParams:(void* _Null_unspecified)inParams + inSize:(NSInteger)inSize + context:(NSDictionary* _Nullable)context + response:(void (^)(bool, ICEInputStream*))response + exception:(void (^)(NSError*))exception + sent:(void (^_Nullable)(bool))sent + error:(NSError* _Nullable * _Nullable)error; + -(bool) isEqual:(ICEObjectPrx* _Nullable)prx ; @end diff --git a/swift/src/IceObjc/IceObjcUtil.h b/swift/src/IceObjc/IceObjcUtil.h index 64231bab8ec..2de45743a78 100644 --- a/swift/src/IceObjc/IceObjcUtil.h +++ b/swift/src/IceObjc/IceObjcUtil.h @@ -21,6 +21,7 @@ namespace IceSSL class Certificate; }; +NSError* convertException(const std::exception_ptr&); NSError* convertException(const std::exception&); template<typename T> diff --git a/swift/src/IceObjc/ObjectPrx.mm b/swift/src/IceObjc/ObjectPrx.mm index f78e23fe2bc..c2d19673c7b 100644 --- a/swift/src/IceObjc/ObjectPrx.mm +++ b/swift/src/IceObjc/ObjectPrx.mm @@ -586,6 +586,64 @@ encodingMinor:(uint8_t)minor } } +-(BOOL) iceInvokeAsync:(NSString* _Nonnull)op + mode:(NSInteger)mode + inParams:(void* _Null_unspecified)inParams + inSize:(NSInteger)inSize + context:(NSDictionary* _Nullable)context + response:(void (^)(bool, ICEInputStream*))response + exception:(void (^)(NSError*))exception + sent:(void (^_Nullable)(bool))sent + error:(NSError* _Nullable * _Nullable)error +{ + std::pair<const Ice::Byte*, const Ice::Byte*> params(0, 0); + params.first = reinterpret_cast<Ice::Byte*>(inParams); + params.second = params.first + inSize; + + try + { + Ice::Context ctx; + if(context) + { + fromNSDictionary(context, ctx); + } + else + { + ctx = Ice::noExplicitContext; + } + + // + // It is possible to throw a CommunicatorDestroyedException + // + _prx->ice_invokeAsync(fromNSString(op), static_cast<Ice::OperationMode>(mode), params, + [response](bool ok, std::pair<const Ice::Byte*, const Ice::Byte*> outParams) + { + // Makes a copy + std::vector<Ice::Byte> r(outParams.first, outParams.second); + response(ok, [[ICEInputStream alloc] initWithBytes:std::move(r)]); + }, + [exception](std::exception_ptr e) + { + exception(convertException(e)); + }, + [sent](bool sentSynchronously) + { + if(sent) + { + sent(sentSynchronously); + } + }, + ctx); + + return YES; + } + catch(const std::exception& ex) + { + *error = convertException(ex); + return NO; + } +} + -(bool) isEqual:(ICEObjectPrx*)other { return Ice::targetEqualTo(_prx, other.prx); diff --git a/swift/src/IceObjc/Util.mm b/swift/src/IceObjc/Util.mm index d2d171b0412..7a2a88f1322 100644 --- a/swift/src/IceObjc/Util.mm +++ b/swift/src/IceObjc/Util.mm @@ -12,6 +12,20 @@ #import "IceObjcUtil.h" NSError* +convertException(const std::exception_ptr& excPtr) +{ + try + { + std::rethrow_exception(excPtr); + } + catch(const std::exception& exc) + { + return convertException(exc); + } + assert(false); +} + +NSError* convertException(const std::exception& exc) { if(dynamic_cast<const Ice::LocalException*>(&exc)) |