| 
 | 1 | +//  | 
 | 2 | +//  JSON+ByteBuffer.swift  | 
 | 3 | +//  swift-aws-lambda-runtime  | 
 | 4 | +//  | 
 | 5 | +//  Created by Fabian Fett on 06.09.24.  | 
 | 6 | +//  | 
 | 7 | + | 
 | 8 | +//===----------------------------------------------------------------------===//  | 
 | 9 | +//  | 
 | 10 | +// This source file is part of the SwiftNIO open source project  | 
 | 11 | +//  | 
 | 12 | +// Copyright (c) 2019-2021 Apple Inc. and the SwiftNIO project authors  | 
 | 13 | +// Licensed under Apache License v2.0  | 
 | 14 | +//  | 
 | 15 | +// See LICENSE.txt for license information  | 
 | 16 | +// See CONTRIBUTORS.txt for the list of SwiftNIO project authors  | 
 | 17 | +//  | 
 | 18 | +// SPDX-License-Identifier: Apache-2.0  | 
 | 19 | +//  | 
 | 20 | +//===----------------------------------------------------------------------===//  | 
 | 21 | + | 
 | 22 | +#if canImport(FoundationEssentials)  | 
 | 23 | +import FoundationEssentials  | 
 | 24 | +#else  | 
 | 25 | +import Foundation  | 
 | 26 | +#endif  | 
 | 27 | +import NIOCore  | 
 | 28 | + | 
 | 29 | +extension ByteBuffer {  | 
 | 30 | +    /// Attempts to decode the `length` bytes from `index` using the `JSONDecoder` `decoder` as `T`.  | 
 | 31 | +    ///  | 
 | 32 | +    /// - parameters:  | 
 | 33 | +    ///    - type: The type type that is attempted to be decoded.  | 
 | 34 | +    ///    - decoder: The `JSONDecoder` that is used for the decoding.  | 
 | 35 | +    ///    - index: The index of the first byte to decode.  | 
 | 36 | +    ///    - length: The number of bytes to decode.  | 
 | 37 | +    /// - returns: The decoded value if successful or `nil` if there are not enough readable bytes available.  | 
 | 38 | +    @inlinable  | 
 | 39 | +    func getJSONDecodable<T: Decodable>(  | 
 | 40 | +        _ type: T.Type,  | 
 | 41 | +        decoder: JSONDecoder = JSONDecoder(),  | 
 | 42 | +        at index: Int,  | 
 | 43 | +        length: Int  | 
 | 44 | +    ) throws -> T? {  | 
 | 45 | +        guard let data = self.getData(at: index, length: length, byteTransferStrategy: .noCopy) else {  | 
 | 46 | +            return nil  | 
 | 47 | +        }  | 
 | 48 | +        return try decoder.decode(T.self, from: data)  | 
 | 49 | +    }  | 
 | 50 | + | 
 | 51 | +    /// Encodes `value` using the `JSONEncoder` `encoder` and set the resulting bytes into this `ByteBuffer` at the  | 
 | 52 | +    /// given `index`.  | 
 | 53 | +    ///  | 
 | 54 | +    /// - note: The `writerIndex` remains unchanged.  | 
 | 55 | +    ///  | 
 | 56 | +    /// - parameters:  | 
 | 57 | +    ///     - value: An `Encodable` value to encode.  | 
 | 58 | +    ///     - encoder: The `JSONEncoder` to encode `value` with.  | 
 | 59 | +    /// - returns: The number of bytes written.  | 
 | 60 | +    @inlinable  | 
 | 61 | +    @discardableResult  | 
 | 62 | +    mutating func setJSONEncodable<T: Encodable>(  | 
 | 63 | +        _ value: T,  | 
 | 64 | +        encoder: JSONEncoder = JSONEncoder(),  | 
 | 65 | +        at index: Int  | 
 | 66 | +    ) throws -> Int {  | 
 | 67 | +        let data = try encoder.encode(value)  | 
 | 68 | +        return self.setBytes(data, at: index)  | 
 | 69 | +    }  | 
 | 70 | + | 
 | 71 | +    /// Encodes `value` using the `JSONEncoder` `encoder` and writes the resulting bytes into this `ByteBuffer`.  | 
 | 72 | +    ///  | 
 | 73 | +    /// If successful, this will move the writer index forward by the number of bytes written.  | 
 | 74 | +    ///  | 
 | 75 | +    /// - parameters:  | 
 | 76 | +    ///     - value: An `Encodable` value to encode.  | 
 | 77 | +    ///     - encoder: The `JSONEncoder` to encode `value` with.  | 
 | 78 | +    /// - returns: The number of bytes written.  | 
 | 79 | +    @inlinable  | 
 | 80 | +    @discardableResult  | 
 | 81 | +    mutating func writeJSONEncodable<T: Encodable>(  | 
 | 82 | +        _ value: T,  | 
 | 83 | +        encoder: JSONEncoder = JSONEncoder()  | 
 | 84 | +    ) throws -> Int {  | 
 | 85 | +        let result = try self.setJSONEncodable(value, encoder: encoder, at: self.writerIndex)  | 
 | 86 | +        self.moveWriterIndex(forwardBy: result)  | 
 | 87 | +        return result  | 
 | 88 | +    }  | 
 | 89 | +}  | 
 | 90 | + | 
 | 91 | +extension JSONDecoder {  | 
 | 92 | +    /// Returns a value of the type you specify, decoded from a JSON object inside the readable bytes of a `ByteBuffer`.  | 
 | 93 | +    ///  | 
 | 94 | +    /// If the `ByteBuffer` does not contain valid JSON, this method throws the  | 
 | 95 | +    /// `DecodingError.dataCorrupted(_:)` error. If a value within the JSON  | 
 | 96 | +    /// fails to decode, this method throws the corresponding error.  | 
 | 97 | +    ///  | 
 | 98 | +    /// - note: The provided `ByteBuffer` remains unchanged, neither the `readerIndex` nor the `writerIndex` will move.  | 
 | 99 | +    ///         If you would like the `readerIndex` to move, consider using `ByteBuffer.readJSONDecodable(_:length:)`.  | 
 | 100 | +    ///  | 
 | 101 | +    /// - parameters:  | 
 | 102 | +    ///     - type: The type of the value to decode from the supplied JSON object.  | 
 | 103 | +    ///     - buffer: The `ByteBuffer` that contains JSON object to decode.  | 
 | 104 | +    /// - returns: The decoded object.  | 
 | 105 | +    func decode<T: Decodable>(_ type: T.Type, from buffer: ByteBuffer) throws -> T {  | 
 | 106 | +        try buffer.getJSONDecodable(  | 
 | 107 | +            T.self,  | 
 | 108 | +            decoder: self,  | 
 | 109 | +            at: buffer.readerIndex,  | 
 | 110 | +            length: buffer.readableBytes  | 
 | 111 | +        )!  // must work, enough readable bytes// must work, enough readable bytes  | 
 | 112 | +    }  | 
 | 113 | +}  | 
 | 114 | + | 
 | 115 | +extension JSONEncoder {  | 
 | 116 | +    /// Writes a JSON-encoded representation of the value you supply into the supplied `ByteBuffer`.  | 
 | 117 | +    ///  | 
 | 118 | +    /// - parameters:  | 
 | 119 | +    ///     - value: The value to encode as JSON.  | 
 | 120 | +    ///     - buffer: The `ByteBuffer` to encode into.  | 
 | 121 | +    @inlinable  | 
 | 122 | +    func encode<T: Encodable>(  | 
 | 123 | +        _ value: T,  | 
 | 124 | +        into buffer: inout ByteBuffer  | 
 | 125 | +    ) throws {  | 
 | 126 | +        try buffer.writeJSONEncodable(value, encoder: self)  | 
 | 127 | +    }  | 
 | 128 | + | 
 | 129 | +    /// Writes a JSON-encoded representation of the value you supply into a `ByteBuffer` that is freshly allocated.  | 
 | 130 | +    ///  | 
 | 131 | +    /// - parameters:  | 
 | 132 | +    ///     - value: The value to encode as JSON.  | 
 | 133 | +    ///     - allocator: The `ByteBufferAllocator` which is used to allocate the `ByteBuffer` to be returned.  | 
 | 134 | +    /// - returns: The `ByteBuffer` containing the encoded JSON.  | 
 | 135 | +    func encodeAsByteBuffer<T: Encodable>(_ value: T, allocator: ByteBufferAllocator) throws -> ByteBuffer {  | 
 | 136 | +        let data = try self.encode(value)  | 
 | 137 | +        var buffer = allocator.buffer(capacity: data.count)  | 
 | 138 | +        buffer.writeBytes(data)  | 
 | 139 | +        return buffer  | 
 | 140 | +    }  | 
 | 141 | +}  | 
0 commit comments