Skip to content

Commit

Permalink
Port Ice Swift src to use async/await
Browse files Browse the repository at this point in the history
  • Loading branch information
externl committed Jul 19, 2024
1 parent 07788b2 commit 8cf6d20
Show file tree
Hide file tree
Showing 20 changed files with 241 additions and 275 deletions.
56 changes: 32 additions & 24 deletions cpp/src/slice2swift/Gen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,6 @@ Gen::ImportVisitor::visitModuleStart(const ModulePtr& p)
}
}

//
// Add PromiseKit import for interfaces and local interfaces which contain "async-oneway" metadata
//
if (p->contains<InterfaceDef>())
{
addImport("PromiseKit");
}

return true;
}

Expand Down Expand Up @@ -1470,45 +1462,61 @@ Gen::ObjectVisitor::visitInterfaceDefStart(const InterfaceDefPtr& p)

const OperationList allOps = p->allOperations();

StringList allOpNames;
vector<pair<string, bool>> allOpNamesAndAmdPairs;
transform(
allOps.begin(),
allOps.end(),
back_inserter(allOpNames),
[](const ContainedPtr& it) { return it->name(); });

allOpNames.push_back("ice_id");
allOpNames.push_back("ice_ids");
allOpNames.push_back("ice_isA");
allOpNames.push_back("ice_ping");
allOpNames.sort();
allOpNames.unique();
back_inserter(allOpNamesAndAmdPairs),
[](const OperationPtr& it) { return make_tuple(it->name(), operationIsAmd(it)); });

allOpNamesAndAmdPairs.emplace_back("ice_id", false);
allOpNamesAndAmdPairs.emplace_back("ice_ids", false);
allOpNamesAndAmdPairs.emplace_back("ice_isA", false);
allOpNamesAndAmdPairs.emplace_back("ice_ping", false);

// Sort the operations by name
sort(
allOpNamesAndAmdPairs.begin(),
allOpNamesAndAmdPairs.end(),
[](const auto& a, const auto& b) { return a.first < b.first; });

// Remove duplicates (we only need to check the name)
allOpNamesAndAmdPairs.erase(
unique(
allOpNamesAndAmdPairs.begin(),
allOpNamesAndAmdPairs.end(),
[](const auto& a, const auto& b) { return a.first == b.first; }),
allOpNamesAndAmdPairs.end());

out << sp;
out << nl;
out << "public func dispatch(_ request: Ice.IncomingRequest) -> PromiseKit.Promise<Ice.OutgoingResponse>";
out << "public func dispatch(_ request: Ice.IncomingRequest) async throws -> Ice.OutgoingResponse";
out << sb;
out << nl;
out << "switch request.current.operation";
out << sb;
out.dec(); // to align case with switch
for (const auto& opName : allOpNames)
for (const auto& [opName, isAmd] : allOpNamesAndAmdPairs)
{
out << nl << "case \"" << opName << "\":";
out.inc();
if (opName == "ice_id" || opName == "ice_ids" || opName == "ice_isA" || opName == "ice_ping")
{
out << nl << "(servant as? Ice.Object ?? " << disp << ".defaultObject)._iceD_" << opName << "(request)";
out << nl << "try (servant as? Ice.Object ?? " << disp << ".defaultObject)._iceD_" << opName << "(request)";
}
else if (isAmd)
{
out << nl << "try await servant._iceD_" << opName << "(request)";
}
else
{
out << nl << "servant._iceD_" << opName << "(request)";
out << nl << "try servant._iceD_" << opName << "(request)";
}
out.dec();
}
out << nl << "default:";
out.inc();
out << nl << "PromiseKit.Promise(error: Ice.OperationNotExistException())";
out << nl << "throw Ice.OperationNotExistException()";
// missing dec to compensate for the extra dec after switch sb
out << eb;
out << eb;
Expand Down Expand Up @@ -1591,7 +1599,7 @@ Gen::ObjectVisitor::visitOperation(const OperationPtr& op)

if (isAmd)
{
out << " -> PromiseKit.Promise<" << (allOutParams.size() > 0 ? operationReturnType(op) : "Swift.Void") << ">";
out << " async throws -> " << (allOutParams.size() > 0 ? operationReturnType(op) : "Swift.Void");
}
else
{
Expand Down
49 changes: 23 additions & 26 deletions cpp/src/slice2swift/SwiftUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -725,8 +725,7 @@ SwiftGenerator::writeOpDocSummary(IceInternal::Output& out, const OperationPtr&
}

out << nl << "///";
out << nl << "/// - returns: `PromiseKit.Promise<" << operationReturnType(p, typeCtx)
<< ">` - The result of the operation";
out << nl << "/// - returns: `" << operationReturnType(p, typeCtx) << "` - The result of the operation";
}
else
{
Expand Down Expand Up @@ -2510,7 +2509,7 @@ SwiftGenerator::writeProxyAsyncOperation(::IceInternal::Output& out, const Opera
out << "sent: ((Swift.Bool) -> Swift.Void)? = nil";

out << epar;
out << " -> PromiseKit.Promise<";
out << " async throws -> ";
if (allOutParams.empty())
{
out << "Swift.Void";
Expand All @@ -2519,15 +2518,14 @@ SwiftGenerator::writeProxyAsyncOperation(::IceInternal::Output& out, const Opera
{
out << operationReturnType(op);
}
out << ">";

out << sb;

//
// Invoke
//
out << sp;
out << nl << "return _impl._invokeAsync(";
out << nl << "return try await _impl._invokeAsync(";

out.useCurrentPosAsIndent();
out << "operation: \"" << op->name() << "\",";
Expand Down Expand Up @@ -2579,14 +2577,14 @@ SwiftGenerator::writeDispatchOperation(::IceInternal::Output& out, const Operati

const string swiftModule = getSwiftModule(getTopLevelModule(dynamic_pointer_cast<Contained>(op)));

out << sp;
out << nl << "public func _iceD_" << opName
<< "(_ request: Ice.IncomingRequest) -> PromiseKit.Promise<Ice.OutgoingResponse>";
const bool isAmd = operationIsAmd(op);

out << sb;
out << sp;
out << nl << "public func _iceD_" << opName << "(_ request: Ice.IncomingRequest)" << (isAmd ? " async" : "")
<< " throws -> Ice.OutgoingResponse";

out << nl << "do";
out << sb;
out << nl;

// TODO: check operation mode

Expand All @@ -2603,30 +2601,33 @@ SwiftGenerator::writeDispatchOperation(::IceInternal::Output& out, const Operati

if (operationIsAmd(op))
{
out << nl << "return self." << opName << "Async(";
out << nl;
if (!outParams.empty())
{
out << "let result = ";
}

out << "try await self." << opName << "Async(";
out << nl << " "; // inc/dec doesn't work for an unknown reason
for (const auto& q : inParams)
{
out << q.name << ": iceP_" << q.name << ", ";
}
out << "current: request.current";
out << nl;
out << ").map(on: nil)";
out << sb;
out << "current: request.current)";

if (outParams.empty())
{
out << nl << "request.current.makeEmptyOutgoingResponse()";
out << nl << "return request.current.makeEmptyOutgoingResponse()";
}
else
{
out << " result in ";
out << nl << "request.current.makeOutgoingResponse(result, formatType:" << opFormatTypeToString(op) << ")";
out << nl << "return request.current.makeOutgoingResponse(result, formatType:" << opFormatTypeToString(op)
<< ")";
out << sb;
out << " ostr, value in ";
writeMarshalAsyncOutParams(out, op);
out << eb;
}
out << eb;
}
else
{
Expand All @@ -2647,7 +2648,7 @@ SwiftGenerator::writeDispatchOperation(::IceInternal::Output& out, const Operati

if (outParams.empty())
{
out << nl << "return PromiseKit.Promise.value(request.current.makeEmptyOutgoingResponse())";
out << nl << "return request.current.makeEmptyOutgoingResponse()";
}
else
{
Expand All @@ -2657,14 +2658,10 @@ SwiftGenerator::writeDispatchOperation(::IceInternal::Output& out, const Operati
<< ")";
writeMarshalOutParams(out, op);
out << nl << "ostr.endEncapsulation()";
out << nl << "return PromiseKit.Promise.value(Ice.OutgoingResponse(ostr))";
out << nl << "return Ice.OutgoingResponse(ostr)";
}
}
out << eb;
out << " catch";
out << sb;
out << nl << "return PromiseKit.Promise(error: error)";
out << eb;

out << eb;
}

Expand Down
2 changes: 1 addition & 1 deletion cpp/src/slice2swift/SwiftUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ namespace Slice
std::string operationReturnDeclaration(const OperationPtr&);
std::string operationInParamsDeclaration(const OperationPtr&);

bool operationIsAmd(const OperationPtr&);
static bool operationIsAmd(const OperationPtr&);

ParamInfoList getAllInParams(const OperationPtr&, int = 0);
void getInParams(const OperationPtr&, ParamInfoList&, ParamInfoList&);
Expand Down
15 changes: 8 additions & 7 deletions swift/src/Ice/AdminFacetFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ class AdminFacetFacade: ICEDispatchAdapter {
requestId: Int32,
encodingMajor: UInt8,
encodingMinor: UInt8,
completionHandler: @escaping ICEOutgoingResponse
) {
outgoingResponseHandler: @escaping ICEOutgoingResponse
) async {
let objectAdapter = adapter.getSwiftObject(ObjectAdapterI.self) {
let oa = ObjectAdapterI(handle: adapter, communicator: communicator)

Expand Down Expand Up @@ -58,20 +58,21 @@ class AdminFacetFacade: ICEDispatchAdapter {

let request = IncomingRequest(current: current, inputStream: istr)

// Dispatch directly to the servant.
dispatcher.dispatch(request).map { response in
do {
// Dispatch directly to the servant.
let response = try await dispatcher.dispatch(request)
response.outputStream.finished().withUnsafeBytes {
completionHandler(
outgoingResponseHandler(
response.replyStatus.rawValue,
response.exceptionId,
response.exceptionMessage,
$0.baseAddress!,
$0.count)
}
}.catch { error in
} catch {
let response = current.makeOutgoingResponse(error: error)
response.outputStream.finished().withUnsafeBytes {
completionHandler(
outgoingResponseHandler(
response.replyStatus.rawValue,
response.exceptionId,
response.exceptionMessage,
Expand Down
14 changes: 4 additions & 10 deletions swift/src/Ice/Blobject.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) ZeroC, Inc.

import Foundation
import PromiseKit

/// Base protocol for dynamic dispatch servants.
public protocol Blobject {
Expand Down Expand Up @@ -31,14 +30,9 @@ public struct BlobjectDisp: Dispatcher {
self.servant = servant
}

public func dispatch(_ request: IncomingRequest) -> Promise<OutgoingResponse> {
do {
let (inEncaps, _) = try request.inputStream.readEncapsulation()
let result = try servant.ice_invoke(inEncaps: inEncaps, current: request.current)
return Promise.value(
request.current.makeOutgoingResponse(ok: result.ok, encapsulation: result.outParams))
} catch {
return Promise(error: error)
}
public func dispatch(_ request: IncomingRequest) async throws -> OutgoingResponse {
let (inEncaps, _) = try request.inputStream.readEncapsulation()
let result = try servant.ice_invoke(inEncaps: inEncaps, current: request.current)
return request.current.makeOutgoingResponse(ok: result.ok, encapsulation: result.outParams)
}
}
18 changes: 6 additions & 12 deletions swift/src/Ice/BlobjectAsync.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) ZeroC, Inc.

import Foundation
import PromiseKit

/// Base protocol for dynamic asynchronous dispatch servants.
public protocol BlobjectAsync {
Expand All @@ -11,7 +10,7 @@ public protocol BlobjectAsync {
///
/// - parameter current: `Ice.Current` - The Current object to pass to the operation.
///
/// - returns: `PromiseKit.Promise<(ok: Bool, outParams: Data)>` - The result of the operation.
/// - returns: `(ok: Bool, outParams: Data)` - The result of the operation.
///
/// - ok: `Bool` - True if the operation completed successfully, false if
/// the operation raised a user exception (in this case, outParams
Expand All @@ -20,7 +19,7 @@ public protocol BlobjectAsync {
///
/// - outParams: `Data` - The encoded out-parameters and return value
/// for the operation. The return value follows any out-parameters.
func ice_invokeAsync(inEncaps: Data, current: Current) -> Promise<(ok: Bool, outParams: Data)>
func ice_invokeAsync(inEncaps: Data, current: Current) async throws -> (ok: Bool, outParams: Data)
}

/// Request dispatcher for BlobjectAsync servants.
Expand All @@ -31,14 +30,9 @@ public struct BlobjectAsyncDisp: Dispatcher {
self.servant = servant
}

public func dispatch(_ request: IncomingRequest) -> Promise<OutgoingResponse> {
do {
let (inEncaps, _) = try request.inputStream.readEncapsulation()
return servant.ice_invokeAsync(inEncaps: inEncaps, current: request.current).map(on: nil) { result in
request.current.makeOutgoingResponse(ok: result.ok, encapsulation: result.outParams)
}
} catch {
return Promise(error: error)
}
public func dispatch(_ request: IncomingRequest) async throws -> OutgoingResponse {
let (inEncaps, _) = try request.inputStream.readEncapsulation()
let result = try await servant.ice_invokeAsync(inEncaps: inEncaps, current: request.current)
return request.current.makeOutgoingResponse(ok: result.ok, encapsulation: result.outParams)
}
}
5 changes: 1 addition & 4 deletions swift/src/Ice/Communicator.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) ZeroC, Inc.

import Foundation
import PromiseKit

/// The central object in Ice. One or more communicators can be instantiated for an Ice application. Communicator
/// instantiation is language-specific, and not specified in Slice code.
Expand Down Expand Up @@ -183,14 +182,12 @@ public protocol Communicator: AnyObject {
/// to dispatch the sent callback
///
/// - parameter sent: `((Bool) -> Void)` - Optional sent callback.
///
/// - returns: `PromiseKit.Promise<>` - The result of the operation
func flushBatchRequestsAsync(
_ compress: CompressBatch,
sentOn: Dispatch.DispatchQueue?,
sentFlags: Dispatch.DispatchWorkItemFlags?,
sent: ((Bool) -> Void)?
) -> PromiseKit.Promise<Void>
) async throws

/// Add the Admin object with all its facets to the provided object adapter. If Ice.Admin.ServerId is
/// set and the provided object adapter has a Locator, createAdmin registers the Admin's Process facet with
Expand Down
8 changes: 4 additions & 4 deletions swift/src/Ice/CommunicatorI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,15 @@ extension Communicator {
sentOn: DispatchQueue? = nil,
sentFlags: DispatchWorkItemFlags? = nil,
sent: ((Bool) -> Void)? = nil
) -> Promise<Void> {
) async throws {
let impl = self as! CommunicatorI
let sentCB = createSentCallback(sentOn: sentOn, sentFlags: sentFlags, sent: sent)
return Promise<Void> { seal in
return try await withCheckedThrowingContinuation { continuation in
impl.handle.flushBatchRequestsAsync(
compress.rawValue,
exception: { seal.reject($0) },
exception: { continuation.resume(throwing: $0) },
sent: {
seal.fulfill(())
continuation.resume(returning: ())
if let sentCB = sentCB {
sentCB($0)
}
Expand Down
Loading

0 comments on commit 8cf6d20

Please sign in to comment.