Skip to content

Commit 0fe7b23

Browse files
committed
refactor API towards 1.0
motivation: define stable API in preperation 1.0 release changes: * require swift 5.7, remove redundant backwards compatibility code * make LambdaHandler, EventLoopLambdaHandler, and ByteBufferLambdaHandler disjointed protocols to reduce API surface area * create coding wrappers for LambdaHandler and EventLoopLambdaHandler to provide coding bridge * reuse output ByteBuffer to reduce allocationsi * add no-op initializer for simple landa use cases * update callsites and tests
1 parent 98a23b6 commit 0fe7b23

24 files changed

+470
-432
lines changed

Package@swift-5.4.swift

Lines changed: 0 additions & 55 deletions
This file was deleted.

Package@swift-5.5.swift

Lines changed: 0 additions & 55 deletions
This file was deleted.

Sources/AWSLambdaRuntime/Lambda+Codable.swift

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,45 @@ import class Foundation.JSONEncoder
1919
import NIOCore
2020
import NIOFoundationCompat
2121

22-
// MARK: - Codable support
22+
// MARK: - LambdaHandler Codable support
23+
24+
/// Implementation of a`ByteBuffer` to `Event` decoding.
25+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
26+
extension LambdaHandler where Event: Decodable {
27+
@inlinable
28+
public func decode(buffer: ByteBuffer) throws -> Event {
29+
try self.decoder.decode(Event.self, from: buffer)
30+
}
31+
}
32+
33+
/// Implementation of `Output` to `ByteBuffer` encoding.
34+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
35+
extension LambdaHandler where Output: Encodable {
36+
@inlinable
37+
public func encode(value: Output, into buffer: inout ByteBuffer) throws {
38+
try self.encoder.encode(value, into: &buffer)
39+
}
40+
}
41+
42+
/// Default `ByteBuffer` to `Event` decoder using Foundation's `JSONDecoder`.
43+
/// Advanced users that want to inject their own codec can do it by overriding these functions.
44+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
45+
extension LambdaHandler where Event: Decodable {
46+
public var decoder: LambdaCodableDecoder {
47+
Lambda.defaultJSONDecoder
48+
}
49+
}
50+
51+
/// Default `Output` to `ByteBuffer` encoder using Foundation's `JSONEncoder`.
52+
/// Advanced users that want to inject their own codec can do it by overriding these functions.
53+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
54+
extension LambdaHandler where Output: Encodable {
55+
public var encoder: LambdaCodableEncoder {
56+
Lambda.defaultJSONEncoder
57+
}
58+
}
59+
60+
// MARK: - EventLoopLambdaHandler Codable support
2361

2462
/// Implementation of a`ByteBuffer` to `Event` decoding.
2563
extension EventLoopLambdaHandler where Event: Decodable {
@@ -32,8 +70,8 @@ extension EventLoopLambdaHandler where Event: Decodable {
3270
/// Implementation of `Output` to `ByteBuffer` encoding.
3371
extension EventLoopLambdaHandler where Output: Encodable {
3472
@inlinable
35-
public func encode(allocator: ByteBufferAllocator, value: Output) throws -> ByteBuffer? {
36-
try self.encoder.encode(value, using: allocator)
73+
public func encode(value: Output, into buffer: inout ByteBuffer) throws {
74+
try self.encoder.encode(value, into: &buffer)
3775
}
3876
}
3977

@@ -58,7 +96,7 @@ public protocol LambdaCodableDecoder {
5896
}
5997

6098
public protocol LambdaCodableEncoder {
61-
func encode<T: Encodable>(_ value: T, using allocator: ByteBufferAllocator) throws -> ByteBuffer
99+
func encode<T: Encodable>(_ value: T, into buffer: inout ByteBuffer) throws
62100
}
63101

64102
extension Lambda {
@@ -68,11 +106,4 @@ extension Lambda {
68106

69107
extension JSONDecoder: LambdaCodableDecoder {}
70108

71-
extension JSONEncoder: LambdaCodableEncoder {
72-
public func encode<T>(_ value: T, using allocator: ByteBufferAllocator) throws -> ByteBuffer where T: Encodable {
73-
// nio will resize the buffer if necessary
74-
var buffer = allocator.buffer(capacity: 1024)
75-
try self.encode(value, into: &buffer)
76-
return buffer
77-
}
78-
}
109+
extension JSONEncoder: LambdaCodableEncoder {}

Sources/AWSLambdaRuntimeCore/Lambda+String.swift

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,46 @@
1313
//===----------------------------------------------------------------------===//
1414
import NIOCore
1515

16-
extension EventLoopLambdaHandler where Event == String {
16+
// MARK: - LambdaHandler String support
17+
18+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
19+
extension LambdaHandler where Event == String {
1720
/// Implementation of a `ByteBuffer` to `String` decoding.
1821
@inlinable
1922
public func decode(buffer: ByteBuffer) throws -> String {
20-
var buffer = buffer
21-
guard let string = buffer.readString(length: buffer.readableBytes) else {
22-
fatalError("buffer.readString(length: buffer.readableBytes) failed")
23+
guard let value = buffer.getString(at: buffer.readerIndex, length: buffer.readableBytes) else {
24+
throw CodecError.invalidString
2325
}
24-
return string
26+
return value
2527
}
2628
}
2729

28-
extension EventLoopLambdaHandler where Output == String {
30+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
31+
extension LambdaHandler where Output == String {
2932
/// Implementation of `String` to `ByteBuffer` encoding.
3033
@inlinable
31-
public func encode(allocator: ByteBufferAllocator, value: String) throws -> ByteBuffer? {
32-
// FIXME: reusable buffer
33-
var buffer = allocator.buffer(capacity: value.utf8.count)
34+
public func encode(value: String, into buffer: inout ByteBuffer) throws {
35+
buffer.writeString(value)
36+
}
37+
}
38+
39+
// MARK: - EventLoopLambdaHandler String support
40+
41+
extension EventLoopLambdaHandler where Event == String {
42+
/// Implementation of `String` to `ByteBuffer` encoding.
43+
@inlinable
44+
public func decode(buffer: ByteBuffer) throws -> String {
45+
guard let value = buffer.getString(at: buffer.readerIndex, length: buffer.readableBytes) else {
46+
throw CodecError.invalidString
47+
}
48+
return value
49+
}
50+
}
51+
52+
extension EventLoopLambdaHandler where Output == String {
53+
/// Implementation of a `ByteBuffer` to `String` decoding.
54+
@inlinable
55+
public func encode(value: String, into buffer: inout ByteBuffer) throws {
3456
buffer.writeString(value)
35-
return buffer
3657
}
3758
}

Sources/AWSLambdaRuntimeCore/Lambda.swift

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,22 @@ public enum Lambda {
3333
/// - handlerType: The Handler to create and invoke.
3434
///
3535
/// - note: This is a blocking operation that will run forever, as its lifecycle is managed by the AWS Lambda Runtime Engine.
36+
37+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
38+
internal static func run<Handler: LambdaHandler>(
39+
configuration: LambdaConfiguration = .init(),
40+
handlerType: Handler.Type
41+
) -> Result<Int, Error> {
42+
Self.run(configuration: configuration, handlerType: CodableLambdaHandler<Handler, Handler.Event, Handler.Output>.self)
43+
}
44+
45+
internal static func run<Handler: EventLoopLambdaHandler>(
46+
configuration: LambdaConfiguration = .init(),
47+
handlerType: Handler.Type
48+
) -> Result<Int, Error> {
49+
Self.run(configuration: configuration, handlerType: CodableEventLoopLambdaHandler<Handler, Handler.Event, Handler.Output>.self)
50+
}
51+
3652
internal static func run<Handler: ByteBufferLambdaHandler>(
3753
configuration: LambdaConfiguration = .init(),
3854
handlerType: Handler.Type
@@ -44,7 +60,7 @@ public enum Lambda {
4460

4561
var result: Result<Int, Error>!
4662
MultiThreadedEventLoopGroup.withCurrentThreadAsEventLoop { eventLoop in
47-
let runtime = LambdaRuntime<Handler>(eventLoop: eventLoop, logger: logger, configuration: configuration)
63+
let runtime = LambdaRuntime(handlerType, eventLoop: eventLoop, logger: logger, configuration: configuration)
4864
#if DEBUG
4965
let signalSource = trap(signal: configuration.lifecycle.stopSignal) { signal in
5066
logger.info("intercepted signal: \(signal)")
@@ -66,7 +82,6 @@ public enum Lambda {
6682
result = lifecycleResult
6783
}
6884
}
69-
7085
logger.info("shutdown completed")
7186
return result
7287
}

Sources/AWSLambdaRuntimeCore/LambdaContext.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,17 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15-
#if compiler(>=5.6)
1615
@preconcurrency import Dispatch
17-
@preconcurrency import Logging
18-
@preconcurrency import NIOCore
19-
#else
20-
import Dispatch
2116
import Logging
2217
import NIOCore
23-
#endif
2418

2519
// MARK: - InitializationContext
2620

2721
/// Lambda runtime initialization context.
2822
/// The Lambda runtime generates and passes the `LambdaInitializationContext` to the Handlers
2923
/// ``ByteBufferLambdaHandler/makeHandler(context:)`` or ``LambdaHandler/init(context:)``
3024
/// as an argument.
31-
public struct LambdaInitializationContext: _AWSLambdaSendable {
25+
public struct LambdaInitializationContext: Sendable {
3226
/// `Logger` to log with.
3327
///
3428
/// - note: The `LogLevel` can be configured using the `LOG_LEVEL` environment variable.
@@ -71,8 +65,8 @@ public struct LambdaInitializationContext: _AWSLambdaSendable {
7165

7266
/// Lambda runtime context.
7367
/// The Lambda runtime generates and passes the `LambdaContext` to the Lambda handler as an argument.
74-
public struct LambdaContext: CustomDebugStringConvertible, _AWSLambdaSendable {
75-
final class _Storage: _AWSLambdaSendable {
68+
public struct LambdaContext: CustomDebugStringConvertible, Sendable {
69+
final class _Storage: Sendable {
7670
let requestID: String
7771
let traceID: String
7872
let invokedFunctionARN: String

0 commit comments

Comments
 (0)