/* * Copyright 2024 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import Foundation enum FlatbuffersGRPCError: Error { case finishedNotCalledOnBuilder } public protocol GRPCVerifiableMessage { associatedtype Message init(pointer: UnsafeRawBufferPointer) init(byteBuffer: ByteBuffer) func decode() throws -> Message func withUnsafeReadableBytes( _ body: (UnsafeRawBufferPointer) throws -> Data) rethrows -> Data } public struct GRPCMessage< Table: FlatBufferVerifiableTable >: Sendable, GRPCVerifiableMessage { public typealias Message = Table private let buffer: ByteBuffer public var size: Int { Int(buffer.size) } public init(pointer: UnsafeRawBufferPointer) { buffer = ByteBuffer( copyingMemoryBound: pointer.baseAddress!, capacity: pointer.count) } public init(builder: inout FlatBufferBuilder) throws { guard builder.finished else { throw FlatbuffersGRPCError.finishedNotCalledOnBuilder } buffer = builder.sizedBuffer } public init(byteBuffer: ByteBuffer) { buffer = byteBuffer } public func decode() throws -> Table { var buf = buffer return try getCheckedRoot(byteBuffer: &buf) } @discardableResult @inline(__always) public func withUnsafeReadableBytes( _ body: (UnsafeRawBufferPointer) throws -> Data) rethrows -> Data { return try buffer.readWithUnsafeRawPointer(position: buffer.reader) { try body(UnsafeRawBufferPointer(start: $0, count: size)) } } } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public struct FlatBuffersMessageSerializer< Message: GRPCVerifiableMessage >: Sendable { public init() {} public func serialize( message: Message, _ completion: (UnsafeRawBufferPointer) throws -> Data) throws -> Data { return try message.withUnsafeReadableBytes { try completion($0) } } } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) public struct FlatBuffersMessageDeserializer< Message: GRPCVerifiableMessage >: Sendable { public init() {} public func deserialize(pointer: UnsafeRawBufferPointer) throws -> Message { Message.init(pointer: pointer) } }