diff --git a/Sources/AWSLambdaRuntime/Lambda+Codable.swift b/Sources/AWSLambdaRuntime/Lambda+Codable.swift index b46cac0e..81445c43 100644 --- a/Sources/AWSLambdaRuntime/Lambda+Codable.swift +++ b/Sources/AWSLambdaRuntime/Lambda+Codable.swift @@ -82,31 +82,51 @@ internal struct CodableVoidLambdaClosureWrapper: LambdaHandler { } } -/// Implementation of a`ByteBuffer` to `In` and `Out` to `ByteBuffer` codec -/// Using Foundation's JSONEncoder and JSONDecoder -/// Advanced users that want to inject their own codec can do it by overriding these functions. -public extension EventLoopLambdaHandler where In: Decodable, Out: Encodable { +/// Implementation of a`ByteBuffer` to `In` decoding +public extension EventLoopLambdaHandler where In: Decodable { + func decode(buffer: ByteBuffer) throws -> In { + try self.decoder.decode(In.self, from: buffer) + } +} + +/// Implementation of `Out` to `ByteBuffer` encoding +public extension EventLoopLambdaHandler where Out: Encodable { func encode(allocator: ByteBufferAllocator, value: Out) throws -> ByteBuffer? { // nio will resize the buffer if necessary - // FIXME: reusable JSONEncoder and buffer var buffer = allocator.buffer(capacity: 1024) - try JSONEncoder().encode(value, into: &buffer) + try self.encoder.encode(value, into: &buffer) return buffer } +} - func decode(buffer: ByteBuffer) throws -> In { - // FIXME: reusable JSONDecoder - try JSONDecoder().decode(In.self, from: buffer) +/// Default `ByteBuffer` to `In` decoder using Foundation's JSONDecoder +/// Advanced users that want to inject their own codec can do it by overriding these functions. +public extension EventLoopLambdaHandler where In: Decodable { + var decoder: LambdaCodableDecoder { + Lambda.defaultJSONDecoder } } -public extension EventLoopLambdaHandler where In: Decodable, Out == Void { - func encode(allocator: ByteBufferAllocator, value: Void) throws -> ByteBuffer? { - nil +/// Default `Out` to `ByteBuffer` encoder using Foundation's JSONEncoder +/// Advanced users that want to inject their own codec can do it by overriding these functions. +public extension EventLoopLambdaHandler where Out: Encodable { + var encoder: LambdaCodableEncoder { + Lambda.defaultJSONEncoder } +} - func decode(buffer: ByteBuffer) throws -> In { - // FIXME: reusable JSONDecoder - try JSONDecoder().decode(In.self, from: buffer) - } +public protocol LambdaCodableDecoder { + func decode(_ type: T.Type, from buffer: ByteBuffer) throws -> T +} + +public protocol LambdaCodableEncoder { + func encode(_ value: T, into buffer: inout ByteBuffer) throws +} + +private extension Lambda { + static let defaultJSONDecoder = JSONDecoder() + static let defaultJSONEncoder = JSONEncoder() } + +extension JSONDecoder: LambdaCodableDecoder {} +extension JSONEncoder: LambdaCodableEncoder {} diff --git a/Sources/AWSLambdaRuntime/Lambda+String.swift b/Sources/AWSLambdaRuntime/Lambda+String.swift index f315e0e0..aff8ff19 100644 --- a/Sources/AWSLambdaRuntime/Lambda+String.swift +++ b/Sources/AWSLambdaRuntime/Lambda+String.swift @@ -78,15 +78,8 @@ internal struct StringVoidLambdaClosureWrapper: LambdaHandler { } } -/// Implementation of a`ByteBuffer` to `String` and `String` to `ByteBuffer` codec -public extension EventLoopLambdaHandler where In == String, Out == String { - func encode(allocator: ByteBufferAllocator, value: String) throws -> ByteBuffer? { - // FIXME: reusable buffer - var buffer = allocator.buffer(capacity: value.utf8.count) - buffer.writeString(value) - return buffer - } - +/// Implementation of a`ByteBuffer` to `String` encoding +public extension EventLoopLambdaHandler where In == String { func decode(buffer: ByteBuffer) throws -> String { var buffer = buffer guard let string = buffer.readString(length: buffer.readableBytes) else { @@ -96,16 +89,12 @@ public extension EventLoopLambdaHandler where In == String, Out == String { } } -public extension EventLoopLambdaHandler where In == String, Out == Void { - func encode(allocator: ByteBufferAllocator, value: Void) throws -> ByteBuffer? { - nil - } - - func decode(buffer: ByteBuffer) throws -> String { - var buffer = buffer - guard let string = buffer.readString(length: buffer.readableBytes) else { - fatalError("buffer.readString(length: buffer.readableBytes) failed") - } - return string +/// Implementation of `String` to `ByteBuffer` decoding +public extension EventLoopLambdaHandler where Out == String { + func encode(allocator: ByteBufferAllocator, value: String) throws -> ByteBuffer? { + // FIXME: reusable buffer + var buffer = allocator.buffer(capacity: value.utf8.count) + buffer.writeString(value) + return buffer } } diff --git a/Sources/AWSLambdaRuntime/LambdaHandler.swift b/Sources/AWSLambdaRuntime/LambdaHandler.swift index c47a74df..f9bbcdc6 100644 --- a/Sources/AWSLambdaRuntime/LambdaHandler.swift +++ b/Sources/AWSLambdaRuntime/LambdaHandler.swift @@ -107,6 +107,13 @@ public extension EventLoopLambdaHandler { } } +/// Implementation of `ByteBuffer` to `Void` decoding +public extension EventLoopLambdaHandler where Out == Void { + func encode(allocator: ByteBufferAllocator, value: Void) throws -> ByteBuffer? { + nil + } +} + // MARK: - ByteBufferLambdaHandler /// An `EventLoopFuture` based processing protocol for a Lambda that takes a `ByteBuffer` and returns a `ByteBuffer?` asynchronously.