diff --git a/.gitignore b/.gitignore index bfe065bc4..89e208b34 100644 --- a/.gitignore +++ b/.gitignore @@ -123,3 +123,4 @@ Cargo.lock .corpus** .seed** grpc/google/ +**/Package.resolved \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 00c409ef6..f288bc561 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,6 +117,8 @@ set(FlatBuffers_Compiler_SRCS grpc/src/compiler/python_generator.h grpc/src/compiler/python_private_generator.h grpc/src/compiler/python_generator.cc + grpc/src/compiler/swift_generator.h + grpc/src/compiler/swift_generator.cc ) set(FlatHash_SRCS diff --git a/grpc/src/compiler/BUILD b/grpc/src/compiler/BUILD index e17bdfab7..96a785842 100644 --- a/grpc/src/compiler/BUILD +++ b/grpc/src/compiler/BUILD @@ -89,3 +89,19 @@ cc_library( "//:flatbuffers", ], ) + +cc_library( + name = "swift_generator", + srcs = [ + "swift_generator.cc", + ], + hdrs = [ + "swift_generator.h", + ":common_headers", + ], + include_prefix = "src/compiler", + strip_include_prefix = "/grpc/src/compiler", + deps = [ + "//:flatbuffers", + ], +) \ No newline at end of file diff --git a/grpc/src/compiler/swift_generator.cc b/grpc/src/compiler/swift_generator.cc new file mode 100644 index 000000000..7997278b3 --- /dev/null +++ b/grpc/src/compiler/swift_generator.cc @@ -0,0 +1,308 @@ +/* + * Copyright 2020 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. + */ + +/* + * NOTE: The following implementation is a translation for the Swift-grpc + * generator since flatbuffers doesnt allow plugins for now. if an issue arises + * please open an issue in the flatbuffers repository. This file should always + * be maintained according to the Swift-grpc repository + */ +#include +#include + +#include "flatbuffers/util.h" +#include "src/compiler/schema_interface.h" +#include "src/compiler/swift_generator.h" + +namespace grpc_swift_generator { + +grpc::string GenerateMessage(const grpc::string &name) { + return "Message<" + name + ">"; +} + +// MARK: - Client + +grpc::string GenerateClientFuncName(const grpc_generator::Method *method) { + if (method->NoStreaming()) { + return "$GenAccess$ func $MethodName$(_ request: $Input$" + ", callOptions: CallOptions?$isNil$) -> UnaryCall<$Input$,$Output$>"; + } + + if (method->ClientStreaming()) { + return "$GenAccess$ func $MethodName$" + "(callOptions: CallOptions?$isNil$) -> " + "ClientStreamingCall<$Input$,$Output$>"; + } + + if (method->ServerStreaming()) { + return "$GenAccess$ func $MethodName$(_ request: $Input$" + ", callOptions: CallOptions?$isNil$, handler: @escaping ($Output$" + ") -> Void) -> ServerStreamingCall<$Input$, $Output$>"; + } + return "$GenAccess$ func $MethodName$" + "(callOptions: CallOptions?$isNil$, handler: @escaping ($Output$" + ") -> Void) -> BidirectionalStreamingCall<$Input$, $Output$>"; +} + +grpc::string GenerateClientFuncBody(const grpc_generator::Method *method) { + if (method->NoStreaming()) { + return "return self.makeUnaryCall(path: " + "\"/$PATH$$ServiceName$/$MethodName$\", request: request, " + "callOptions: callOptions ?? self.defaultCallOptions)"; + } + + if (method->ClientStreaming()) { + return "return self.makeClientStreamingCall(path: " + "\"/$PATH$$ServiceName$/$MethodName$\", callOptions: callOptions ?? " + "self.defaultCallOptions)"; + } + + if (method->ServerStreaming()) { + return "return self.makeServerStreamingCall(path: " + "\"/$PATH$$ServiceName$/$MethodName$\", request: request, " + "callOptions: callOptions ?? self.defaultCallOptions, handler: " + "handler)"; + } + return "return self.makeBidirectionalStreamingCall(path: " + "\"/$PATH$$ServiceName$/$MethodName$\", callOptions: callOptions ?? " + "self.defaultCallOptions, handler: handler)"; +} + +void GenerateClientProtocol(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "$ACCESS$ protocol $ServiceName$Service {\n"); + vars["GenAccess"] = ""; + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_type_name()); + vars["MethodName"] = method->name(); + vars["isNil"] = ""; + printer->Print("\t"); + auto func = GenerateClientFuncName(method.get()); + printer->Print(vars, func.c_str()); + printer->Print("\n"); + } + printer->Print("}\n\n"); +} + +void GenerateClientClass(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, + "$ACCESS$ final class $ServiceName$ServiceClient: GRPCClient, " + "$ServiceName$Service {\n"); + printer->Print(vars, "\t$ACCESS$ let connection: ClientConnection\n"); + printer->Print(vars, "\t$ACCESS$ var defaultCallOptions: CallOptions\n"); + printer->Print("\n"); + printer->Print(vars, + "\t$ACCESS$ init(connection: ClientConnection, " + "defaultCallOptions: CallOptions = CallOptions()) {\n"); + printer->Print("\t\tself.connection = connection\n"); + printer->Print("\t\tself.defaultCallOptions = defaultCallOptions\n"); + printer->Print("\t}"); + printer->Print("\n"); + vars["GenAccess"] = "public"; + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_type_name()); + vars["MethodName"] = method->name(); + vars["isNil"] = " = nil"; + printer->Print("\n\t"); + auto func = GenerateClientFuncName(method.get()); + printer->Print(vars, func.c_str()); + printer->Print(" {\n"); + auto body = GenerateClientFuncBody(method.get()); + printer->Print("\t\t"); + printer->Print(vars, body.c_str()); + printer->Print("\n\t}\n"); + } + printer->Print("}\n"); +} + +// MARK: - Server + +grpc::string GenerateServerFuncName(const grpc_generator::Method *method) { + if (method->NoStreaming()) { + return "func $MethodName$(_ request: $Input$" + ", context: StatusOnlyCallContext) -> EventLoopFuture<$Output$>"; + } + + if (method->ClientStreaming()) { + return "func $MethodName$(context: UnaryResponseCallContext<$Output$>) -> " + "EventLoopFuture<(StreamEvent<$Input$" + ">) -> Void>"; + } + + if (method->ServerStreaming()) { + return "func $MethodName$(request: $Input$" + ", context: StreamingResponseCallContext<$Output$>) -> " + "EventLoopFuture"; + } + return "func $MethodName$(context: StreamingResponseCallContext<$Output$>) " + "-> EventLoopFuture<(StreamEvent<$Input$>) -> Void>"; +} + +grpc::string GenerateServerExtensionBody(const grpc_generator::Method *method) { + grpc::string start = "\t\tcase \"$MethodName$\":\n\t\t"; + if (method->NoStreaming()) { + return start + + "return UnaryCallHandler(callHandlerContext: callHandlerContext) { " + "context in" + "\n\t\t\t" + "return { request in" + "\n\t\t\t\t" + "self.$MethodName$(request, context: context)" + "\n\t\t\t}" + "\n\t\t}"; + } + if (method->ClientStreaming()) { + return start + + "return ClientStreamingCallHandler(callHandlerContext: " + "callHandlerContext) { context in" + "\n\t\t\t" + "return { request in" + "\n\t\t\t\t" + "self.$MethodName$(request: request, context: context)" + "\n\t\t\t}" + "\n\t\t}"; + } + if (method->ServerStreaming()) { + return start + + "return ServerStreamingCallHandler(callHandlerContext: " + "callHandlerContext) { context in" + "\n\t\t\t" + "return { request in" + "\n\t\t\t\t" + "self.$MethodName$(request: request, context: context)" + "\n\t\t\t}" + "\n\t\t}"; + } + if (method->BidiStreaming()) { + return start + + "return BidirectionalStreamingCallHandler(callHandlerContext: " + "callHandlerContext) { context in" + "\n\t\t\t" + "return { request in" + "\n\t\t\t\t" + "self.$MethodName$(request: request, context: context)" + "\n\t\t\t}" + "\n\t\t}"; + } + return ""; +} + +void GenerateServerProtocol(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print( + vars, "$ACCESS$ protocol $ServiceName$Provider: CallHandlerProvider {\n"); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_type_name()); + vars["MethodName"] = method->name(); + printer->Print("\t"); + auto func = GenerateServerFuncName(method.get()); + printer->Print(vars, func.c_str()); + printer->Print("\n"); + } + printer->Print("}\n\n"); + + printer->Print(vars, "$ACCESS$ extension $ServiceName$Provider {\n"); + printer->Print(vars, + "\tvar serviceName: String { return " + "\"$PATH$$ServiceName$\" }\n"); + printer->Print( + "\tfunc handleMethod(_ methodName: String, callHandlerContext: " + "CallHandlerContext) -> GRPCCallHandler? {\n"); + printer->Print("\t\tswitch methodName {\n"); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_type_name()); + vars["MethodName"] = method->name(); + auto body = GenerateServerExtensionBody(method.get()); + printer->Print(vars, body.c_str()); + printer->Print("\n"); + } + printer->Print("\t\tdefault: return nil;\n"); + printer->Print("\t\t}\n"); + printer->Print("\t}\n\n"); + printer->Print("}\n\n"); +} + +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service) { + grpc::string output; + std::map vars; + vars["PATH"] = file->package(); + if (!file->package().empty()) { vars["PATH"].append("."); } + vars["ServiceName"] = service->name(); + vars["ACCESS"] = "public"; + auto printer = file->CreatePrinter(&output); + printer->Print(vars, + "/// Usage: instantiate $ServiceName$ServiceClient, then call " + "methods of this protocol to make API calls.\n"); + GenerateClientProtocol(service, &*printer, &vars); + GenerateClientClass(service, &*printer, &vars); + printer->Print("\n"); + GenerateServerProtocol(service, &*printer, &vars); + return output; +} + +grpc::string GenerateHeader() { + grpc::string code; + code += + "/// The following code is generated by the Flatbuffers library which " + "might not be in sync with grpc-swift\n"; + code += + "/// in case of an issue please open github issue, though it would be " + "maintained\n"; + code += "import Foundation\n"; + code += "import GRPC\n"; + code += "import NIO\n"; + code += "import NIOHTTP1\n"; + code += "import FlatBuffers\n"; + code += "\n"; + code += + "public protocol GRPCFlatBufPayload: GRPCPayload, FlatBufferGRPCMessage " + "{}\n"; + + code += "public extension GRPCFlatBufPayload {\n"; + code += " init(serializedByteBuffer: inout NIO.ByteBuffer) throws {\n"; + code += + " self.init(byteBuffer: FlatBuffers.ByteBuffer(contiguousBytes: " + "serializedByteBuffer.readableBytesView, count: " + "serializedByteBuffer.readableBytes))\n"; + code += " }\n"; + + code += " func serialize(into buffer: inout NIO.ByteBuffer) throws {\n"; + code += + " let buf = UnsafeRawBufferPointer(start: self.rawPointer, count: " + "Int(self.size))\n"; + code += " buffer.writeBytes(buf)\n"; + code += " }\n"; + code += "}\n"; + code += "extension Message: GRPCFlatBufPayload {}\n"; + return code; +} +} // namespace grpc_swift_generator diff --git a/grpc/src/compiler/swift_generator.h b/grpc/src/compiler/swift_generator.h new file mode 100644 index 000000000..1639cb07c --- /dev/null +++ b/grpc/src/compiler/swift_generator.h @@ -0,0 +1,55 @@ +/* + * + * Copyright 2020, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include "src/compiler/config.h" +#include "src/compiler/schema_interface.h" + +#ifndef GRPC_CUSTOM_STRING +# include +# define GRPC_CUSTOM_STRING std::string +#endif + +namespace grpc { + +typedef GRPC_CUSTOM_STRING string; + +} // namespace grpc + +namespace grpc_swift_generator { +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service); +grpc::string GenerateHeader(); +} // namespace grpc_swift_generator diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index dbdacc8e4..3c25f2ca7 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -1124,6 +1124,12 @@ bool GenerateJavaGRPC(const Parser &parser, const std::string &path, bool GeneratePythonGRPC(const Parser &parser, const std::string &path, const std::string &file_name); +// Generate GRPC Swift interfaces. +// See idl_gen_grpc.cpp. +extern bool GenerateSwiftGRPC(const Parser &parser, + const std::string &path, + const std::string &file_name); + } // namespace flatbuffers #endif // FLATBUFFERS_IDL_H_ diff --git a/src/BUILD b/src/BUILD index f50727a0b..cf1bd2f6c 100644 --- a/src/BUILD +++ b/src/BUILD @@ -70,5 +70,6 @@ cc_library( "//grpc/src/compiler:go_generator", "//grpc/src/compiler:java_generator", "//grpc/src/compiler:python_generator", + "//grpc/src/compiler:swift_generator", ], ) diff --git a/src/flatc_main.cpp b/src/flatc_main.cpp index b8a771ff3..724d88d5e 100644 --- a/src/flatc_main.cpp +++ b/src/flatc_main.cpp @@ -106,7 +106,7 @@ int main(int argc, const char *argv[]) { true, nullptr, flatbuffers::IDLOptions::kJsonSchema, "Generate Json schema", nullptr }, { flatbuffers::GenerateSwift, nullptr, "--swift", "swift", - true, nullptr, flatbuffers::IDLOptions::kSwift, + true, flatbuffers::GenerateSwiftGRPC, flatbuffers::IDLOptions::kSwift, "Generate Swift files for tables/structs", nullptr }, }; diff --git a/src/idl_gen_grpc.cpp b/src/idl_gen_grpc.cpp index 84d6dba61..c0ab94bf3 100644 --- a/src/idl_gen_grpc.cpp +++ b/src/idl_gen_grpc.cpp @@ -25,6 +25,7 @@ #include "src/compiler/java_generator.h" #include "src/compiler/python_generator.h" #include "src/compiler/python_private_generator.h" +#include "src/compiler/swift_generator.h" #if defined(_MSC_VER) # pragma warning(push) @@ -79,9 +80,7 @@ class FlatBufMethod : public grpc_generator::Method { return true; } - std::string get_fb_builder() const { - return "builder"; - } + std::string get_fb_builder() const { return "builder"; } std::string input_type_name() const { return GRPCType(*method_->request); } @@ -186,7 +185,11 @@ class FlatBufPrinter : public grpc_generator::Printer { class FlatBufFile : public grpc_generator::File { public: enum Language { - kLanguageGo, kLanguageCpp, kLanguageJava, kLanguagePython + kLanguageGo, + kLanguageCpp, + kLanguageJava, + kLanguagePython, + kLanguageSwift }; FlatBufFile(const Parser &parser, const std::string &file_name, @@ -235,6 +238,9 @@ class FlatBufFile : public grpc_generator::File { case kLanguagePython: { return ""; } + case kLanguageSwift: { + return ""; + } } return ""; } @@ -373,7 +379,6 @@ bool GenerateJavaGRPC(const Parser &parser, const std::string &path, bool GeneratePythonGRPC(const Parser &parser, const std::string & /*path*/, const std::string &file_name) { - int nservices = 0; for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end(); ++it) { @@ -403,6 +408,46 @@ bool GeneratePythonGRPC(const Parser &parser, const std::string & /*path*/, return flatbuffers::SaveFile(grpc_py_filename.c_str(), code, false); } +class SwiftGRPCGenerator : public flatbuffers::BaseGenerator { + private: + CodeWriter code_; + + public: + SwiftGRPCGenerator(const Parser &parser, const std::string &path, + const std::string &filename) + : BaseGenerator(parser, path, filename, "", "" /*Unused*/) {} + + bool generate() { + code_.Clear(); + code_ += "// Generated GRPC code for FlatBuffers swift!"; + code_ += grpc_swift_generator::GenerateHeader(); + FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageSwift); + for (int i = 0; i < file.service_count(); i++) { + auto service = file.service(i); + code_ += grpc_swift_generator::Generate(&file, service.get()); + } + const auto final_code = code_.ToString(); + const auto filename = GeneratedFileName(path_, file_name_); + return SaveFile(filename.c_str(), final_code, false); + } + + static std::string GeneratedFileName(const std::string &path, + const std::string &file_name) { + return path + file_name + ".grpc.swift"; + } +}; + +bool GenerateSwiftGRPC(const Parser &parser, const std::string &path, + const std::string &file_name) { + int nservices = 0; + for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end(); + ++it) { + if (!(*it)->generated) nservices++; + } + if (!nservices) return true; + return SwiftGRPCGenerator(parser, path, file_name).generate(); +} + } // namespace flatbuffers #if defined(_MSC_VER) diff --git a/src/idl_gen_swift.cpp b/src/idl_gen_swift.cpp index b5225cf20..884a2b5c1 100644 --- a/src/idl_gen_swift.cpp +++ b/src/idl_gen_swift.cpp @@ -1,3 +1,19 @@ +/* + * Copyright 2020 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. + */ + #include #include "flatbuffers/code_generators.h" @@ -244,6 +260,7 @@ class SwiftGenerator : public BaseGenerator { code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table"); code_ += "public struct {{STRUCTNAME}}: {{PROTOCOL}} {\n"; code_ += ValidateFunc(); + code_ += "\tpublic var __buffer: ByteBuffer! { return {{ACCESS}}.bb }"; code_ += "\n\tprivate var {{ACCESS}}: {{OBJECTTYPE}}"; if (struct_def.fixed) { code_.SetValue("BYTESIZE", NumToString(struct_def.bytesize)); diff --git a/swift/FlatBuffers.podspec b/swift/FlatBuffers.podspec index a2eaf11d0..db8778787 100644 --- a/swift/FlatBuffers.podspec +++ b/swift/FlatBuffers.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FlatBuffers' - s.version = '0.1.0' + s.version = '0.2.0' s.summary = 'FlatBuffers: Memory Efficient Serialization Library' s.description = "FlatBuffers is a cross platform serialization library architected for diff --git a/swift/Sources/FlatBuffers/ByteBuffer.swift b/swift/Sources/FlatBuffers/ByteBuffer.swift index cbe3cd057..0c5231788 100644 --- a/swift/Sources/FlatBuffers/ByteBuffer.swift +++ b/swift/Sources/FlatBuffers/ByteBuffer.swift @@ -51,6 +51,35 @@ public final class ByteBuffer { _memory.initializeMemory(as: UInt8.self, repeating: 0, count: size) _capacity = size } + +#if swift(>=5.0) + /// Constructor that creates a Flatbuffer object from a ContiguousBytes + /// - Parameters: + /// - contiguousBytes: Binary stripe to use as the buffer + /// - count: amount of readable bytes + public init( + contiguousBytes: Bytes, + count: Int + ) { + _memory = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: alignment) + _capacity = count + _writerSize = _capacity + contiguousBytes.withUnsafeBytes { buf in + _memory.copyMemory(from: buf.baseAddress!, byteCount: buf.count) + } + } +#endif + + /// Creates a copy of the buffer that's being built by calling sizedBuffer + /// - Parameters: + /// - memory: Current memory of the buffer + /// - count: count of bytes + internal init(memory: UnsafeMutableRawPointer, count: Int) { + _memory = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: alignment) + _memory.copyMemory(from: memory, byteCount: count) + _capacity = count + _writerSize = _capacity + } /// Creates a copy of the existing flatbuffer, by copying it to a different memory. /// - Parameters: diff --git a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift index 9a4ed3d0e..cf479fd6b 100644 --- a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift +++ b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift @@ -50,6 +50,12 @@ public final class FlatBufferBuilder { /// Returns the buffer public var buffer: ByteBuffer { return _bb } + /// Returns A sized Buffer from the readable bytes + public var sizedBuffer: ByteBuffer { + assert(finished, "Data shouldn't be called before finish()") + return ByteBuffer(memory: _bb.memory.advanced(by: _bb.reader), count: _bb.reader) + } + // MARK: - Init /// initialize the buffer with a size diff --git a/swift/Sources/FlatBuffers/FlatBufferObject.swift b/swift/Sources/FlatBuffers/FlatBufferObject.swift index 6e405f5b2..a247b1420 100644 --- a/swift/Sources/FlatBuffers/FlatBufferObject.swift +++ b/swift/Sources/FlatBuffers/FlatBufferObject.swift @@ -2,6 +2,7 @@ import Foundation /// FlatbufferObject structures all the Flatbuffers objects public protocol FlatBufferObject { + var __buffer: ByteBuffer! { get } init(_ bb: ByteBuffer, o: Int32) } diff --git a/swift/Sources/FlatBuffers/Message.swift b/swift/Sources/FlatBuffers/Message.swift new file mode 100644 index 000000000..590d3d7fc --- /dev/null +++ b/swift/Sources/FlatBuffers/Message.swift @@ -0,0 +1,41 @@ +public protocol FlatBufferGRPCMessage { + + /// Raw pointer which would be pointing to the beginning of the readable bytes + var rawPointer: UnsafeMutableRawPointer { get } + + /// Size of readable bytes in the buffer + var size: Int { get } + + init(byteBuffer: ByteBuffer) +} + +/// Message is a wrapper around Buffers to to able to send Flatbuffers `Buffers` through the +/// GRPC library +public final class Message: FlatBufferGRPCMessage { + internal var buffer: ByteBuffer + + /// Returns the an object of type T that would be read from the buffer + public var object: T { + T.init(buffer, o: Int32(buffer.read(def: UOffset.self, position: buffer.reader)) + Int32(buffer.reader)) + } + + public var rawPointer: UnsafeMutableRawPointer { return buffer.memory.advanced(by: buffer.reader) } + + public var size: Int { return Int(buffer.size) } + + /// Initializes the message with the type Flatbuffer.Bytebuffer that is transmitted over + /// GRPC + /// - Parameter byteBuffer: Flatbuffer ByteBuffer object + public init(byteBuffer: ByteBuffer) { + buffer = byteBuffer + } + + /// Initializes the message by copying the buffer to the message to be sent. + /// from the builder + /// - Parameter builder: FlatbufferBuilder that has the bytes created in + /// - Note: Use `builder.finish(offset)` before passing the builder without prefixing anything to it + public init(builder: inout FlatBufferBuilder) { + buffer = builder.sizedBuffer + builder.clear() + } +} diff --git a/tests/FlatBuffers.GRPC.Swift/Package.swift b/tests/FlatBuffers.GRPC.Swift/Package.swift new file mode 100644 index 000000000..e9f3bbe46 --- /dev/null +++ b/tests/FlatBuffers.GRPC.Swift/Package.swift @@ -0,0 +1,49 @@ +// swift-tools-version:5.1 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "FlatBuffers.GRPC.Swift", + platforms: [ + .iOS(.v11), + .macOS(.v10_14), + ], + dependencies: [ + // Main SwiftNIO package + .package(path: "../../swift"), + .package(url: "https://github.com/grpc/grpc-swift.git", .branch("nio")) + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages which this package depends on. + .target( + name: "Model", + dependencies: [ + "GRPC", + "FlatBuffers" + ], + path: "Sources/Model" + ), + + // Client for the HelloWorld example + .target( + name: "Client", + dependencies: [ + "GRPC", + "Model", + ], + path: "Sources/client" + ), + + // Server for the HelloWorld example + .target( + name: "Server", + dependencies: [ + "GRPC", + "Model", + ], + path: "Sources/server" + ), + ] +) diff --git a/tests/FlatBuffers.GRPC.Swift/README.md b/tests/FlatBuffers.GRPC.Swift/README.md new file mode 100644 index 000000000..4a14f9e87 --- /dev/null +++ b/tests/FlatBuffers.GRPC.Swift/README.md @@ -0,0 +1,3 @@ +# FlatBuffers.GRPC.Swift + +The following is Swift example on how GRPC would be with Swift Flatbuffers diff --git a/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter.fbs b/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter.fbs new file mode 100644 index 000000000..811303c93 --- /dev/null +++ b/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter.fbs @@ -0,0 +1,17 @@ +table HelloReply { + message:string; +} + +table HelloRequest { + name:string; +} + +table ManyHellosRequest { + name:string; + num_greetings:int; +} + +rpc_service Greeter { + SayHello(HelloRequest):HelloReply; + SayManyHellos(ManyHellosRequest):HelloReply (streaming: "server"); +} diff --git a/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter.grpc.swift b/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter.grpc.swift new file mode 100644 index 000000000..6ad1f18dd --- /dev/null +++ b/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter.grpc.swift @@ -0,0 +1,73 @@ +// Generated GRPC code for FlatBuffers swift! +/// The following code is generated by the Flatbuffers library which might not be in sync with grpc-swift +/// in case of an issue please open github issue, though it would be maintained +import Foundation +import GRPC +import NIO +import NIOHTTP1 +import FlatBuffers + +public protocol GRPCFlatBufPayload: GRPCPayload, FlatBufferGRPCMessage {} +public extension GRPCFlatBufPayload { + init(serializedByteBuffer: inout NIO.ByteBuffer) throws { + self.init(byteBuffer: FlatBuffers.ByteBuffer(contiguousBytes: serializedByteBuffer.readableBytesView, count: serializedByteBuffer.readableBytes)) + } + func serialize(into buffer: inout NIO.ByteBuffer) throws { + let buf = UnsafeRawBufferPointer(start: self.rawPointer, count: Int(self.size)) + buffer.writeBytes(buf) + } +} +extension Message: GRPCFlatBufPayload {} + +/// Usage: instantiate GreeterServiceClient, then call methods of this protocol to make API calls. +public protocol GreeterService { + func SayHello(_ request: Message, callOptions: CallOptions?) -> UnaryCall,Message> + func SayManyHellos(_ request: Message, callOptions: CallOptions?, handler: @escaping (Message) -> Void) -> ServerStreamingCall, Message> +} + +public final class GreeterServiceClient: GRPCClient, GreeterService { + public let connection: ClientConnection + public var defaultCallOptions: CallOptions + + public init(connection: ClientConnection, defaultCallOptions: CallOptions = CallOptions()) { + self.connection = connection + self.defaultCallOptions = defaultCallOptions + } + + public func SayHello(_ request: Message, callOptions: CallOptions? = nil) -> UnaryCall,Message> { + return self.makeUnaryCall(path: "/Greeter/SayHello", request: request, callOptions: callOptions ?? self.defaultCallOptions) + } + + public func SayManyHellos(_ request: Message, callOptions: CallOptions? = nil, handler: @escaping (Message) -> Void) -> ServerStreamingCall, Message> { + return self.makeServerStreamingCall(path: "/Greeter/SayManyHellos", request: request, callOptions: callOptions ?? self.defaultCallOptions, handler: handler) + } +} + +public protocol GreeterProvider: CallHandlerProvider { + func SayHello(_ request: Message, context: StatusOnlyCallContext) -> EventLoopFuture> + func SayManyHellos(request: Message, context: StreamingResponseCallContext>) -> EventLoopFuture +} + +public extension GreeterProvider { + var serviceName: String { return "Greeter" } + func handleMethod(_ methodName: String, callHandlerContext: CallHandlerContext) -> GRPCCallHandler? { + switch methodName { + case "SayHello": + return UnaryCallHandler(callHandlerContext: callHandlerContext) { context in + return { request in + self.SayHello(request, context: context) + } + } + case "SayManyHellos": + return ServerStreamingCallHandler(callHandlerContext: callHandlerContext) { context in + return { request in + self.SayManyHellos(request: request, context: context) + } + } + default: return nil; + } + } + +} + + diff --git a/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter_generated.swift b/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter_generated.swift new file mode 100644 index 000000000..6db6cb4f9 --- /dev/null +++ b/tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter_generated.swift @@ -0,0 +1,80 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import FlatBuffers + +public struct HelloReply: FlatBufferObject { + + static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } + + private var _accessor: Table + public static func getRootAsHelloReply(bb: ByteBuffer) -> HelloReply { return HelloReply(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) } + + private init(_ t: Table) { _accessor = t } + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } + + public var message: String? { let o = _accessor.offset(4); return o == 0 ? nil : _accessor.string(at: o) } + public var messageSegmentArray: [UInt8]? { return _accessor.getVector(at: 4) } + public static func startHelloReply(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) } + public static func add(message: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: message, at: 0) } + public static func endHelloReply(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end } + public static func createHelloReply(_ fbb: FlatBufferBuilder, + offsetOfMessage message: Offset = Offset()) -> Offset { + let __start = HelloReply.startHelloReply(fbb) + HelloReply.add(message: message, fbb) + return HelloReply.endHelloReply(fbb, start: __start) + } +} + +public struct HelloRequest: FlatBufferObject { + + static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } + + private var _accessor: Table + public static func getRootAsHelloRequest(bb: ByteBuffer) -> HelloRequest { return HelloRequest(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) } + + private init(_ t: Table) { _accessor = t } + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } + + public var name: String? { let o = _accessor.offset(4); return o == 0 ? nil : _accessor.string(at: o) } + public var nameSegmentArray: [UInt8]? { return _accessor.getVector(at: 4) } + public static func startHelloRequest(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) } + public static func add(name: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: name, at: 0) } + public static func endHelloRequest(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end } + public static func createHelloRequest(_ fbb: FlatBufferBuilder, + offsetOfName name: Offset = Offset()) -> Offset { + let __start = HelloRequest.startHelloRequest(fbb) + HelloRequest.add(name: name, fbb) + return HelloRequest.endHelloRequest(fbb, start: __start) + } +} + +public struct ManyHellosRequest: FlatBufferObject { + + static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } + + private var _accessor: Table + public static func getRootAsManyHellosRequest(bb: ByteBuffer) -> ManyHellosRequest { return ManyHellosRequest(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) } + + private init(_ t: Table) { _accessor = t } + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } + + public var name: String? { let o = _accessor.offset(4); return o == 0 ? nil : _accessor.string(at: o) } + public var nameSegmentArray: [UInt8]? { return _accessor.getVector(at: 4) } + public var numGreetings: Int32 { let o = _accessor.offset(6); return o == 0 ? 0 : _accessor.readBuffer(of: Int32.self, at: o) } + public static func startManyHellosRequest(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 2) } + public static func add(name: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: name, at: 0) } + public static func add(numGreetings: Int32, _ fbb: FlatBufferBuilder) { fbb.add(element: numGreetings, def: 0, at: 1) } + public static func endManyHellosRequest(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end } + public static func createManyHellosRequest(_ fbb: FlatBufferBuilder, + offsetOfName name: Offset = Offset(), + numGreetings: Int32 = 0) -> Offset { + let __start = ManyHellosRequest.startManyHellosRequest(fbb) + ManyHellosRequest.add(name: name, fbb) + ManyHellosRequest.add(numGreetings: numGreetings, fbb) + return ManyHellosRequest.endManyHellosRequest(fbb, start: __start) + } +} + diff --git a/tests/FlatBuffers.GRPC.Swift/Sources/client/main.swift b/tests/FlatBuffers.GRPC.Swift/Sources/client/main.swift new file mode 100644 index 000000000..cc9374b22 --- /dev/null +++ b/tests/FlatBuffers.GRPC.Swift/Sources/client/main.swift @@ -0,0 +1,101 @@ +/* + * Copyright 2020, gRPC Authors 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 GRPC +import Model +import NIO +import Logging +import FlatBuffers + +// Quieten the logs. +LoggingSystem.bootstrap { + var handler = StreamLogHandler.standardOutput(label: $0) + handler.logLevel = .critical + return handler +} + +func greet(name: String, client greeter: GreeterServiceClient) { + // Form the request with the name, if one was provided. + var builder = FlatBufferBuilder() + let name = builder.create(string: name) + let root = HelloRequest.createHelloRequest(builder, offsetOfName: name) + builder.finish(offset: root) + + // Make the RPC call to the server. + let sayHello = greeter.SayHello(Message(builder: &builder)) + // wait() on the response to stop the program from exiting before the response is received. + do { + let response = try sayHello.response.wait() + print("Greeter received: \(response.object.message)") + } catch { + print("Greeter failed: \(error)") + } + + let surname = builder.create(string: "Name") + let manyRoot = ManyHellosRequest.createManyHellosRequest(builder, offsetOfName: surname, numGreetings: 2) + builder.finish(offset: manyRoot) + + let call = greeter.SayManyHellos(Message(builder: &builder)) { message in + print(message.object.message) + } + + let status = try! call.status.recover { _ in .processingError }.wait() + if status.code != .ok { + print("RPC failed: \(status)") + } +} + +func main(args: [String]) { + // arg0 (dropped) is the program name. We expect arg1 to be the port, and arg2 (optional) to be + // the name sent in the request. + let arg1 = args.dropFirst(1).first + let arg2 = args.dropFirst(2).first + + switch (arg1.flatMap(Int.init), arg2) { + case (.none, _): + print("Usage: PORT [NAME]") + exit(1) + + case let (.some(port), name): + // Setup an `EventLoopGroup` for the connection to run on. + // + // See: https://github.com/apple/swift-nio#eventloops-and-eventloopgroups + let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) + + // Make sure the group is shutdown when we're done with it. + defer { + try! group.syncShutdownGracefully() + } + + // Provide some basic configuration for the connection, in this case we connect to an endpoint on + // localhost at the given port. + let configuration = ClientConnection.Configuration( + target: .hostAndPort("localhost", port), + eventLoopGroup: group + ) + + // Create a connection using the configuration. + let connection = ClientConnection(configuration: configuration) + + // Provide the connection to the generated client. + let greeter = GreeterServiceClient(connection: connection) + + // Do the greeting. + greet(name: "Hello FlatBuffers!", client: greeter) + } +} + +main(args: CommandLine.arguments) diff --git a/tests/FlatBuffers.GRPC.Swift/Sources/server/main.swift b/tests/FlatBuffers.GRPC.Swift/Sources/server/main.swift new file mode 100644 index 000000000..5595b6407 --- /dev/null +++ b/tests/FlatBuffers.GRPC.Swift/Sources/server/main.swift @@ -0,0 +1,93 @@ +/* + * Copyright 2020, gRPC Authors 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 GRPC +import NIO +import FlatBuffers +import Logging +import Model + +class Greeter: GreeterProvider { + + var hellos: [Message] = [] + + init() { + let names = ["Stranger1", "Stranger2", "Stranger4", "Stranger3", "Stranger5", "Stranger6"] + for name in names { + var builder = FlatBufferBuilder() + let off = builder.create(string: name) + let root = HelloReply.createHelloReply(builder, offsetOfMessage: off) + builder.finish(offset: root) + hellos.append(Message(builder: &builder)) + } + } + + func SayHello( + _ request: Message, + context: StatusOnlyCallContext + ) -> EventLoopFuture> { + let recipient = request.object.name ?? "Stranger" + + var builder = FlatBufferBuilder() + let off = builder.create(string: recipient) + let root = HelloReply.createHelloReply(builder, offsetOfMessage: off) + builder.finish(offset: root) + return context.eventLoop.makeSucceededFuture(Message(builder: &builder)) + } + + func SayManyHellos( + request: Message, + context: StreamingResponseCallContext> + ) -> EventLoopFuture { + for _ in 0.. UnsafeMutableRawPoint } struct Vec: Readable { + var __buffer: ByteBuffer! { __p.bb } + static var size = 12 static var alignment = 4 private var __p: Struct @@ -144,6 +146,8 @@ func createVec2(x: Float32 = 0, y: Float32 = 0, z: Float32 = 0, color: Color2) - } struct Vec2: Readable { + var __buffer: ByteBuffer! { __p.bb } + static var size = 13 static var alignment = 4 private var __p: Struct diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift index b9e97574a..f4483f03b 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift @@ -115,6 +115,8 @@ enum RGB: Int32, Enum { } struct Monster: FlatBufferObject { + var __buffer: ByteBuffer! { _accessor.bb } + private var _accessor: Table static func getRootAsMonster(bb: ByteBuffer) -> Monster { return Monster(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) } @@ -189,8 +191,9 @@ struct Monster { } } - struct Weapon: FlatBufferObject { + + var __buffer: ByteBuffer! { __t.bb } static let offsets: (name: VOffset, dmg: VOffset) = (0, 1) private var __t: Table diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift index fe317d472..4edb77eb0 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift @@ -81,6 +81,7 @@ public enum AnyAmbiguousAliases: UInt8, Enum { public struct Test: Readable { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Struct public static var size = 4 @@ -96,6 +97,7 @@ public struct Test: Readable { public struct Vec3: Readable { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Struct public static var size = 32 @@ -117,6 +119,7 @@ public struct Vec3: Readable { public struct Ability: Readable { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Struct public static var size = 8 @@ -166,6 +169,7 @@ public static func createAbility(id: UInt32, distance: UInt32) -> UnsafeMutableR public struct InParentNamespace: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Table public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) } @@ -187,6 +191,7 @@ public enum Example2 { public struct Monster: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Table public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) } @@ -214,6 +219,7 @@ extension MyGame.Example { public struct TestSimpleTableWithEnum: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Table public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) } @@ -238,6 +244,7 @@ public struct TestSimpleTableWithEnum: FlatBufferObject { public struct Stat: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Table public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) } @@ -272,6 +279,7 @@ public struct Stat: FlatBufferObject { public struct Referrable: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Table public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) } @@ -321,6 +329,7 @@ public struct Referrable: FlatBufferObject { public struct Monster: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Table public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) } @@ -618,6 +627,7 @@ public struct Monster: FlatBufferObject { public struct TypeAliases: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Table public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) } diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift index c901729d0..197f1391d 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift @@ -22,6 +22,7 @@ public enum Character: UInt8, Enum { public struct Rapunzel: Readable { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Struct public static var size = 4 @@ -35,6 +36,7 @@ public struct Rapunzel: Readable { public struct BookReader: Readable { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Struct public static var size = 4 @@ -62,6 +64,7 @@ public func createBookReader(booksRead: Int32) -> UnsafeMutableRawPointer { public struct Attacker: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Table public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MOVI", addPrefix: prefix) } @@ -86,6 +89,7 @@ public struct Attacker: FlatBufferObject { public struct Movie: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_1_11_1() } + public var __buffer: ByteBuffer! { return _accessor.bb } private var _accessor: Table public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MOVI", addPrefix: prefix) }