diff --git a/Package.swift b/Package.swift index 96068884..0652d53b 100644 --- a/Package.swift +++ b/Package.swift @@ -36,8 +36,7 @@ let package = Package( .product(name: "NIOCore", package: "swift-nio"), .product(name: "NIOConcurrencyHelpers", package: "swift-nio"), .product(name: "NIOPosix", package: "swift-nio"), - ], - swiftSettings: [.swiftLanguageMode(.v5)] + ] ), .plugin( name: "AWSLambdaPackager", diff --git a/Sources/AWSLambdaRuntime/Lambda+Codable.swift b/Sources/AWSLambdaRuntime/Lambda+Codable.swift index fb6d2ca7..ccb37dd8 100644 --- a/Sources/AWSLambdaRuntime/Lambda+Codable.swift +++ b/Sources/AWSLambdaRuntime/Lambda+Codable.swift @@ -66,7 +66,7 @@ extension LambdaCodableAdapter { public init( encoder: JSONEncoder = JSONEncoder(), decoder: JSONDecoder = JSONDecoder(), - handler: Handler + handler: sending Handler ) where Output: Encodable, diff --git a/Sources/AWSLambdaRuntimeCore/Lambda+Codable.swift b/Sources/AWSLambdaRuntimeCore/Lambda+Codable.swift index 7a0a9a22..a77c0542 100644 --- a/Sources/AWSLambdaRuntimeCore/Lambda+Codable.swift +++ b/Sources/AWSLambdaRuntimeCore/Lambda+Codable.swift @@ -58,7 +58,7 @@ public struct LambdaHandlerAdapter< /// Initializes an instance given a concrete handler. /// - Parameter handler: The ``LambdaHandler`` conforming handler that is to be adapted to ``LambdaWithBackgroundProcessingHandler``. @inlinable - public init(handler: Handler) { + public init(handler: sending Handler) { self.handler = handler } @@ -98,7 +98,7 @@ public struct LambdaCodableAdapter< /// - decoder: The decoder object that will be used to decode the received `ByteBuffer` event into the generic `Event` type served to the `handler`. /// - handler: The handler object. @inlinable - public init(encoder: Encoder, decoder: Decoder, handler: Handler) where Output: Encodable { + public init(encoder: sending Encoder, decoder: sending Decoder, handler: sending Handler) where Output: Encodable { self.encoder = encoder self.decoder = decoder self.handler = handler @@ -109,7 +109,7 @@ public struct LambdaCodableAdapter< /// - decoder: The decoder object that will be used to decode the received `ByteBuffer` event into the generic `Event` type served to the `handler`. /// - handler: The handler object. @inlinable - public init(decoder: Decoder, handler: Handler) where Output == Void, Encoder == VoidEncoder { + public init(decoder: sending Decoder, handler: Handler) where Output == Void, Encoder == VoidEncoder { self.encoder = VoidEncoder() self.decoder = decoder self.handler = handler diff --git a/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift b/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift index fa907def..64a9acb7 100644 --- a/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift +++ b/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift @@ -174,13 +174,14 @@ private struct LambdaHttpServer { do { try await channel.executeThenClose { inbound, outbound in for try await inboundData in inbound { - if case .head(let head) = inboundData { + switch inboundData { + case .head(let head): requestHead = head - } - if case .body(let body) = inboundData { + + case .body(let body): requestBody = body - } - if case .end = inboundData { + + case .end: precondition(requestHead != nil, "Received .end without .head") // process the request let response = try await self.processRequest( diff --git a/Sources/AWSLambdaRuntimeCore/LambdaHandlers.swift b/Sources/AWSLambdaRuntimeCore/LambdaHandlers.swift index b76b453d..82a6eef3 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaHandlers.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaHandlers.swift @@ -154,7 +154,7 @@ public struct ClosureHandler: LambdaHandler { /// Initialize with a closure handler over generic `Input` and `Output` types. /// - Parameter body: The handler function written as a closure. - public init(body: @escaping (Event, LambdaContext) async throws -> Output) where Output: Encodable { + public init(body: sending @escaping (Event, LambdaContext) async throws -> Output) where Output: Encodable { self.body = body } @@ -192,8 +192,8 @@ extension LambdaRuntime { Encoder: LambdaOutputEncoder, Decoder: LambdaEventDecoder >( - encoder: Encoder, - decoder: Decoder, + encoder: sending Encoder, + decoder: sending Decoder, body: sending @escaping (Event, LambdaContext) async throws -> Output ) where @@ -205,13 +205,15 @@ extension LambdaRuntime { Encoder > { - let handler = LambdaCodableAdapter( + let closureHandler = ClosureHandler(body: body) + let streamingAdapter = LambdaHandlerAdapter(handler: closureHandler) + let codableWrapper = LambdaCodableAdapter( encoder: encoder, decoder: decoder, - handler: LambdaHandlerAdapter(handler: ClosureHandler(body: body)) + handler: streamingAdapter ) - self.init(handler: handler) + self.init(handler: codableWrapper) } /// Initialize an instance with a ``LambdaHandler`` defined in the form of a closure **with a `Void` return type**, an encoder, and a decoder. @@ -219,7 +221,7 @@ extension LambdaRuntime { /// - decoder: The decoder object that will be used to decode the incoming `ByteBuffer` event into the generic `Event` type. /// - body: The handler in the form of a closure. public convenience init( - decoder: Decoder, + decoder: sending Decoder, body: sending @escaping (Event, LambdaContext) async throws -> Void ) where diff --git a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift index bbd16efa..228dc471 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift @@ -49,9 +49,13 @@ final actor LambdaRuntimeClient: LambdaRuntimeClientProtocol { } } + private typealias ConnectionContinuation = CheckedContinuation< + NIOLoopBound>, any Error + > + private enum ConnectionState { case disconnected - case connecting([CheckedContinuation, any Error>]) + case connecting([ConnectionContinuation]) case connected(Channel, LambdaChannelHandler) } @@ -158,7 +162,6 @@ final actor LambdaRuntimeClient: LambdaRuntimeClientProtocol { .sentResponse: fatalError("Invalid state: \(self.lambdaState)") } - } private func write(_ buffer: NIOCore.ByteBuffer) async throws { @@ -284,11 +287,11 @@ final actor LambdaRuntimeClient: LambdaRuntimeClientProtocol { case .connecting(var array): // Since we do get sequential invocations this case normally should never be hit. // We'll support it anyway. - return try await withCheckedThrowingContinuation { - (continuation: CheckedContinuation, any Error>) in + let loopBound = try await withCheckedThrowingContinuation { (continuation: ConnectionContinuation) in array.append(continuation) self.connectionState = .connecting(array) } + return loopBound.value case .connected(_, let handler): return handler } @@ -339,8 +342,9 @@ final actor LambdaRuntimeClient: LambdaRuntimeClientProtocol { case .connecting(let array): self.connectionState = .connected(channel, handler) defer { + let loopBound = NIOLoopBound(handler, eventLoop: self.eventLoop) for continuation in array { - continuation.resume(returning: handler) + continuation.resume(returning: loopBound) } } return handler