Skip to content

Commit e75c0d4

Browse files
authored
Revision: Remove ~Copyable from LambdaResponseStreamWriter and LambdaResponseWriter
Remove `~Copyable` from `LambdaResponseStreamWriter` and `LambdaResponseWriter`. Instead throw an error when `finish()` is called multiple times or when `write`/`writeAndFinish` is called after `finish()`.
1 parent b01eff8 commit e75c0d4

File tree

1 file changed

+27
-25
lines changed
  • Sources/AWSLambdaRuntimeCore/Documentation.docc/Proposals

1 file changed

+27
-25
lines changed

Sources/AWSLambdaRuntimeCore/Documentation.docc/Proposals/0001-v2-api.md

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ Versions:
2020
`LambdaWithBackgroundProcessingHandler`.
2121
- Update `LambdaCodableAdapter` to now be generic over any handler conforming to
2222
`LambdaWithBackgroundProcessingHandler` instead of `LambdaHandler`.
23+
- v1.2:
24+
- Remove `~Copyable` from `LambdaResponseStreamWriter` and `LambdaResponseWriter`. Instead throw an error when
25+
`finish()` is called multiple times or when `write`/`writeAndFinish` is called after `finish()`.
2326

2427
## Motivation
2528

@@ -144,8 +147,8 @@ of the `EventLoop` family of interfaces.
144147
- This allows the lifecycle of the `LambdaRuntime` to be managed with `swift-service-lifecycle` _alongside_ and in the
145148
same way the lifecycles of the required services are managed, e.g.
146149
`try await ServiceGroup(services: [postgresClient, ..., lambdaRuntime], ...).run()`.
147-
- Dependencies can now be injected into `LambdaRuntime` `swift-service-lifecycle` guarantees that the services will be
148-
initialized _before_ the `LambdaRuntime`'s `run()` function is called.
150+
- Dependencies can now be injected into `LambdaRuntime`. With `swift-service-lifecycle`, services will be initialized
151+
together with `LambdaRuntime`.
149152
- The required services can then be used within the handler in a structured concurrency manner.
150153
`swift-service-lifecycle` takes care of listening for termination signals and terminating the services as well as the
151154
`LambdaRuntime` in correct order.
@@ -196,22 +199,20 @@ below), which is the new base protocol for the `LambdaRuntime` (defined below as
196199

197200
```swift
198201
/// A writer object to write the Lambda response stream into
199-
public protocol LambdaResponseStreamWriter: ~Copyable {
202+
public protocol LambdaResponseStreamWriter {
200203
/// Write a response part into the stream. The HTTP response is started lazily before the first call to `write(_:)`.
201204
/// Bytes written to the writer are streamed continually.
202205
func write(_ buffer: ByteBuffer) async throws
203206
/// End the response stream and the underlying HTTP response.
204-
consuming func finish()
207+
func finish() async throws
205208
/// Write a response part into the stream and end the response stream as well as the underlying HTTP response.
206-
consuming func writeAndFinish(_ buffer: ByteBuffer) async throws
209+
func writeAndFinish(_ buffer: ByteBuffer) async throws
207210
}
208211
```
209212

210-
It is important to note that `LambdaResponseStreamWriter` will be non-copyable, with the `finish()` and
211-
`writeAndFinish(_:)` functions having the `consuming` ownership keyword. This is so that the compiler can enforce the
212-
restriction of not being able to call `write(_:)` after any of the finishing functions have been called. The compiler
213-
can also prevent the finishing functions from being called multiple times. If the user does not call `finish()`, the
214-
library will automatically finish the stream after the last `write` utilizing the writers `deinit`.
213+
If the user does not call `finish()`, the library will automatically finish the stream after the last `write`.
214+
Appropriate errors will be thrown if `finish()` is called multiple times, or if `write`/`writeAndFinish` is called after
215+
`finish()`.
215216

216217
### LambdaContext
217218

@@ -278,7 +279,7 @@ public protocol StreamingLambdaHandler {
278279
/// headers will be sent.
279280
/// - If ``LambdaResponseStreamWriter.finish()`` has already been called before the error is thrown, the
280281
/// error will be logged.
281-
mutating func handle(_ event: ByteBuffer, responseWriter: consuming some LambdaResponseStreamWriter, context: LambdaContext) async throws
282+
mutating func handle(_ event: ByteBuffer, responseWriter: some LambdaResponseStreamWriter, context: LambdaContext) async throws
282283
}
283284
```
284285

@@ -303,7 +304,7 @@ An implementation that sends the number 1 to 10 every 500ms could look like this
303304
struct SendNumbersWithPause: StreamingLambdaHandler {
304305
func handle(
305306
_ event: ByteBuffer,
306-
responseWriter: consuming some LambdaResponseStreamWriter,
307+
responseWriter: some LambdaResponseStreamWriter,
307308
context: LambdaContext
308309
) async throws {
309310
for i in 1...10 {
@@ -357,12 +358,13 @@ any background work after the result has been sent to the AWS Lambda control pla
357358
simply serves as a mechanism to return the output without explicitly returning from the `handle` function.
358359

359360
```swift
360-
public protocol LambdaResponseWriter<Output>: ~Copyable {
361+
public protocol LambdaResponseWriter<Output> {
361362
associatedtype Output
362363

363364
/// Sends the generic Output object (representing the computed result of the handler)
364365
/// to the AWS Lambda response endpoint.
365-
consuming func write(_: Output) async throws
366+
/// An error will be thrown if this function is called more than once.
367+
func write(_: Output) async throws
366368
}
367369

368370
public protocol LambdaWithBackgroundProcessingHandler {
@@ -377,7 +379,7 @@ public protocol LambdaWithBackgroundProcessingHandler {
377379
/// Agnostic to JSON encoding/decoding
378380
func handle(
379381
_ event: Event,
380-
outputWriter: consuming some LambdaResponseWriter<Output>,
382+
outputWriter: some LambdaResponseWriter<Output>,
381383
context: LambdaContext
382384
) async throws
383385
}
@@ -400,7 +402,7 @@ struct BackgroundProcessingHandler: LambdaWithBackgroundProcessingHandler {
400402

401403
func handle(
402404
_ event: Event,
403-
outputWriter: consuming some LambdaResponseWriter<Output>,
405+
outputWriter: some LambdaResponseWriter<Output>,
404406
context: LambdaContext
405407
) async throws {
406408
// Return result to the Lambda control plane
@@ -460,13 +462,13 @@ public final class LambdaRuntime<Handler>: ServiceLifecycle.Service, Sendable
460462
/// ``NIOSingletons.posixEventLoopGroup``.
461463
/// - Parameter logger: A logger
462464
public init(
463-
handler: consuming sending Handler,
465+
handler: sending Handler,
464466
eventLoop: EventLoop = Lambda.defaultEventLoop,
465467
logger: Logger = Logger(label: "Lambda")
466468
)
467469

468470
/// Create a LambdaRuntime by passing a ``StreamingLambdaHandler``.
469-
public convenience init(handler: consuming sending Handler)
471+
public convenience init(handler: sending Handler)
470472

471473
/// Starts the LambdaRuntime by connecting to the Lambda control plane to ask
472474
/// for events to process. If the environment variable AWS_LAMBDA_RUNTIME_API is
@@ -569,7 +571,7 @@ public struct LambdaHandlerAdapter<
569571
570572
/// 1. Call the `self.handler.handle(...)` with `event` and `context`.
571573
/// 2. Pass the generic `Output` object returned from `self.handler.handle(...)` to `outputWriter.write(_:)`
572-
public func handle(_ event: Event, outputWriter: consuming some LambdaResponseWriter<Output>, context: LambdaContext) async throws
574+
public func handle(_ event: Event, outputWriter: some LambdaResponseWriter<Output>, context: LambdaContext) async throws
573575
}
574576
```
575577
@@ -643,7 +645,7 @@ public struct LambdaCodableAdapter<
643645
/// and the `LambdaContext`.
644646
public mutating func handle(
645647
_ request: ByteBuffer,
646-
responseWriter: consuming some LambdaResponseStreamWriter,
648+
responseWriter: some LambdaResponseStreamWriter,
647649
context: LambdaContext
648650
) async throws
649651
}
@@ -721,19 +723,19 @@ handle encoding/decoding themselves:
721723
public struct StreamingClosureHandler: StreamingLambdaHandler {
722724

723725
public init(
724-
body: @escaping sending (ByteBuffer, consuming LambdaResponseStreamWriter, LambdaContext) async throws -> ()
726+
body: @escaping sending (ByteBuffer, LambdaResponseStreamWriter, LambdaContext) async throws -> ()
725727
)
726728

727729
public func handle(
728730
_ request: ByteBuffer,
729-
responseWriter: consuming LambdaResponseStreamWriter,
731+
responseWriter: LambdaResponseStreamWriter,
730732
context: LambdaContext
731733
) async throws
732734
}
733735

734736
extension LambdaRuntime {
735737
public init(
736-
body: @escaping sending (ByteBuffer, consuming LambdaResponseStreamWriter, LambdaContext) async throws -> ()
738+
body: @escaping sending (ByteBuffer, LambdaResponseStreamWriter, LambdaContext) async throws -> ()
737739
)
738740
}
739741
```
@@ -766,7 +768,7 @@ Its API would look like this:
766768
/// The response can be empty, a single ByteBuffer or a response stream.
767769
public struct LambdaResponse {
768770
/// A writer to be used when creating a streamed response.
769-
public struct Writer: ~Copyable {
771+
public struct Writer {
770772
/// Writes data to the response stream
771773
public func write(_ byteBuffer: ByteBuffer) async throws
772774
/// Closes off the response stream
@@ -840,7 +842,7 @@ For handlers conforming to the `LambdaHandler` protocol, we considered extending
840842
add background work can override this function in their `LambdaHandler` conforming object.
841843

842844
```swift
843-
public protocol LambdaHandler: ~Copyable {
845+
public protocol LambdaHandler {
844846
associatedtype Event
845847
associatedtype Output
846848

0 commit comments

Comments
 (0)