Skip to content

Commit 3d0c107

Browse files
committed
async/await support
Motivation: The async/await proposal has entered the review phase, so we may want to start looking into NIO with async/await. Modifications: - Add `EventLoopFuture.get() throws await` - Add `ChannelOutboundInvoker` `async` methods Result: If async/await were actually implemented, you could use NIO together with async/wait. So far, you can only compile your projects.
1 parent 076fda1 commit 3d0c107

File tree

2 files changed

+94
-1
lines changed

2 files changed

+94
-1
lines changed

Package.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515

1616
import PackageDescription
1717

18+
let nioSwiftSettings: [SwiftSetting]
19+
20+
#if compiler(>=5.4)
21+
nioSwiftSettings = [.unsafeFlags(["-Xfrontend", "-enable-experimental-concurrency"])]
22+
#else
23+
nioSwiftSettings = []
24+
#endif
25+
1826
var targets: [PackageDescription.Target] = [
1927
.target(name: "_NIO1APIShims",
2028
dependencies: ["NIO", "NIOHTTP1", "NIOTLS", "NIOFoundationCompat", "NIOWebSocket"]),
@@ -24,7 +32,8 @@ var targets: [PackageDescription.Target] = [
2432
"CNIOWindows",
2533
"NIOConcurrencyHelpers",
2634
"CNIOAtomics",
27-
"CNIOSHA1"]),
35+
"CNIOSHA1"],
36+
swiftSettings: nioSwiftSettings),
2837
.target(name: "NIOFoundationCompat", dependencies: ["NIO"]),
2938
.target(name: "CNIOAtomics", dependencies: []),
3039
.target(name: "CNIOSHA1", dependencies: []),

Sources/NIO/AsyncAwaitSupport.swift

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#if compiler(>=5.4)
2+
extension EventLoopFuture {
3+
public func get() async throws -> Value {
4+
return await try Task.withUnsafeThrowingContinuation { cont in
5+
self.whenComplete { result in
6+
switch result {
7+
case .success(let value):
8+
cont.resume(returning: value)
9+
case .failure(let error):
10+
cont.resume(throwing: error)
11+
}
12+
}
13+
}
14+
}
15+
}
16+
17+
extension Channel {
18+
public func writeAndFlush<T>(_ any: T) async throws {
19+
await try self.writeAndFlush(any).get()
20+
}
21+
22+
/// Set `option` to `value` on this `Channel`.
23+
public func setOption<Option: ChannelOption>(_ option: Option, value: Option.Value) async throws {
24+
await try self.setOption(option, value: value).get()
25+
}
26+
27+
/// Get the value of `option` for this `Channel`.
28+
public func getOption<Option: ChannelOption>(_ option: Option) async throws -> Option.Value {
29+
return await try self.getOption(option).get()
30+
}
31+
}
32+
33+
extension ChannelOutboundInvoker {
34+
/// Register on an `EventLoop` and so have all its IO handled.
35+
///
36+
/// - returns: the future which will be notified once the operation completes.
37+
public func register(file: StaticString = #file, line: UInt = #line) async throws {
38+
await try self.register(file: file, line: line)
39+
}
40+
41+
/// Bind to a `SocketAddress`.
42+
/// - parameters:
43+
/// - to: the `SocketAddress` to which we should bind the `Channel`.
44+
/// - returns: the future which will be notified once the operation completes.
45+
public func bind(to address: SocketAddress, file: StaticString = #file, line: UInt = #line) async throws {
46+
await try self.bind(to: address, file: file, line: line)
47+
}
48+
49+
/// Connect to a `SocketAddress`.
50+
/// - parameters:
51+
/// - to: the `SocketAddress` to which we should connect the `Channel`.
52+
/// - returns: the future which will be notified once the operation completes.
53+
public func connect(to address: SocketAddress, file: StaticString = #file, line: UInt = #line) async throws {
54+
await try self.connect(to: address, file: file, line: line)
55+
}
56+
57+
/// Shortcut for calling `write` and `flush`.
58+
///
59+
/// - parameters:
60+
/// - data: the data to write
61+
/// - returns: the future which will be notified once the `write` operation completes.
62+
public func writeAndFlush(_ data: NIOAny, file: StaticString = #file, line: UInt = #line) async throws {
63+
await try self.writeAndFlush(data, file: file, line: line)
64+
}
65+
66+
/// Close the `Channel` and so the connection if one exists.
67+
///
68+
/// - parameters:
69+
/// - mode: the `CloseMode` that is used
70+
/// - returns: the future which will be notified once the operation completes.
71+
public func close(mode: CloseMode = .all, file: StaticString = #file, line: UInt = #line) async throws {
72+
await try self.close(mode: mode, file: file, line: line)
73+
}
74+
75+
/// Trigger a custom user outbound event which will flow through the `ChannelPipeline`.
76+
///
77+
/// - parameters:
78+
/// - event: the event itself.
79+
/// - returns: the future which will be notified once the operation completes.
80+
public func triggerUserOutboundEvent(_ event: Any, file: StaticString = #file, line: UInt = #line) async throws {
81+
await try self.triggerUserOutboundEvent(event, file: file, line: line).get()
82+
}
83+
}
84+
#endif

0 commit comments

Comments
 (0)