[TS] GRPC Implementation (#6141)
authormustiikhalil <mustii@mmk.one>
Wed, 7 Oct 2020 16:56:30 +0000 (19:56 +0300)
committerGitHub <noreply@github.com>
Wed, 7 Oct 2020 16:56:30 +0000 (09:56 -0700)
* GRPC implementation for Typescript

* Fixes a couple of issues

* Finished implementing the typescript support for grpc

* Updated generated code

* Fixes CI

31 files changed:
CMakeLists.txt
grpc/flatbuffers-js-grpc/package.json [new file with mode: 0644]
grpc/flatbuffers-js-grpc/src/client.ts [new file with mode: 0644]
grpc/flatbuffers-js-grpc/src/greeter.fbs [new file with mode: 0644]
grpc/flatbuffers-js-grpc/src/greeter_generated.ts [new file with mode: 0644]
grpc/flatbuffers-js-grpc/src/greeter_grpc.d.ts [new file with mode: 0644]
grpc/flatbuffers-js-grpc/src/greeter_grpc.js [new file with mode: 0644]
grpc/flatbuffers-js-grpc/src/server.ts [new file with mode: 0644]
grpc/flatbuffers-js-grpc/tsconfig.json [new file with mode: 0644]
grpc/src/compiler/BUILD
grpc/src/compiler/swift_generator.cc
grpc/src/compiler/ts_generator.cc [new file with mode: 0644]
grpc/src/compiler/ts_generator.h [new file with mode: 0644]
include/flatbuffers/idl.h
src/BUILD
src/flatc_main.cpp
src/idl_gen_cpp.cpp
src/idl_gen_dart.cpp
src/idl_gen_grpc.cpp
src/idl_gen_js_ts.cpp
src/idl_gen_kotlin.cpp
src/idl_gen_rust.cpp
src/idl_parser.cpp
src/reflection.cpp
tests/FlatBuffers.GRPC.Swift/Sources/Model/greeter.grpc.swift
tests/FlatBuffers.GRPC.Swift/Sources/client/main.swift
tests/FlatBuffers.GRPC.Swift/Sources/server/main.swift
tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test.grpc.swift
tests/monster_test_generated.ts
tests/monster_test_grpc.d.ts [new file with mode: 0644]
tests/monster_test_grpc.js [new file with mode: 0644]

index 456d0bee0d7870498550095d2b3a549f993896a8..6e2b32b0d66ac35fce2f704df2c819a1e393c2e0 100644 (file)
@@ -124,6 +124,8 @@ set(FlatBuffers_Compiler_SRCS
   grpc/src/compiler/python_generator.cc
   grpc/src/compiler/swift_generator.h
   grpc/src/compiler/swift_generator.cc
+  grpc/src/compiler/ts_generator.h
+  grpc/src/compiler/ts_generator.cc
 )
 
 set(FlatHash_SRCS
diff --git a/grpc/flatbuffers-js-grpc/package.json b/grpc/flatbuffers-js-grpc/package.json
new file mode 100644 (file)
index 0000000..d827049
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "name": "flatbuffers-js-grpc",
+  "version": "1.0.0",
+  "author": "mustii@mmk.one",
+  "dependencies": {
+    "flatbuffers": "^1.12.0",
+    "grpc": "^1.24.3"
+  }
+}
diff --git a/grpc/flatbuffers-js-grpc/src/client.ts b/grpc/flatbuffers-js-grpc/src/client.ts
new file mode 100644 (file)
index 0000000..00d1009
--- /dev/null
@@ -0,0 +1,28 @@
+import grpc from 'grpc';
+import { HelloRequest } from './greeter_generated';
+import { GreeterClient } from './greeter_grpc';
+import { flatbuffers } from 'flatbuffers';
+
+async function main() {
+    const _server = new GreeterClient('localhost:3000', grpc.credentials.createInsecure());
+    const builder = new flatbuffers.Builder();
+    const offset = builder.createString('mustii');
+    const root = HelloRequest.createHelloRequest(builder, offset);
+    builder.finish(root);
+    const buffer = HelloRequest.getRootAsHelloRequest(new flatbuffers.ByteBuffer(builder.asUint8Array()));
+
+    _server.SayHello(buffer, (err, response) => {
+        console.log(response.message());
+    });
+
+    const data = _server.SayManyHellos(buffer, null);
+
+    data.on('data', (data) => {
+        console.log(data.message());
+    });
+    data.on('end', (data) => {
+        console.log('end');
+    });
+}
+
+main();
\ No newline at end of file
diff --git a/grpc/flatbuffers-js-grpc/src/greeter.fbs b/grpc/flatbuffers-js-grpc/src/greeter.fbs
new file mode 100644 (file)
index 0000000..b510884
--- /dev/null
@@ -0,0 +1,12 @@
+table HelloReply {
+  message:string;
+}
+
+table HelloRequest {
+  name:string;
+}
+
+rpc_service Greeter {
+  SayHello(HelloRequest):HelloReply;
+  SayManyHellos(HelloRequest):HelloReply (streaming: "server");
+}
diff --git a/grpc/flatbuffers-js-grpc/src/greeter_generated.ts b/grpc/flatbuffers-js-grpc/src/greeter_generated.ts
new file mode 100644 (file)
index 0000000..87113f9
--- /dev/null
@@ -0,0 +1,174 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * @constructor
+ */
+export class HelloReply {
+  bb: flatbuffers.ByteBuffer|null = null;
+
+  bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns HelloReply
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):HelloReply {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param HelloReply= obj
+ * @returns HelloReply
+ */
+static getRootAsHelloReply(bb:flatbuffers.ByteBuffer, obj?:HelloReply):HelloReply {
+  return (obj || new HelloReply()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param HelloReply= obj
+ * @returns HelloReply
+ */
+static getSizePrefixedRootAsHelloReply(bb:flatbuffers.ByteBuffer, obj?:HelloReply):HelloReply {
+  bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+  return (obj || new HelloReply()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.Encoding= optionalEncoding
+ * @returns string|Uint8Array|null
+ */
+message():string|null
+message(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
+message(optionalEncoding?:any):string|Uint8Array|null {
+  var offset = this.bb!.__offset(this.bb_pos, 4);
+  return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startHelloReply(builder:flatbuffers.Builder) {
+  builder.startObject(1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset messageOffset
+ */
+static addMessage(builder:flatbuffers.Builder, messageOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(0, messageOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endHelloReply(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+static createHelloReply(builder:flatbuffers.Builder, messageOffset:flatbuffers.Offset):flatbuffers.Offset {
+  HelloReply.startHelloReply(builder);
+  HelloReply.addMessage(builder, messageOffset);
+  return HelloReply.endHelloReply(builder);
+}
+
+serialize():Uint8Array {
+  return this.bb!.bytes();
+}
+
+static deserialize(buffer: Uint8Array):HelloReply {
+  return HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(buffer))
+}
+}
+/**
+ * @constructor
+ */
+export class HelloRequest {
+  bb: flatbuffers.ByteBuffer|null = null;
+
+  bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns HelloRequest
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):HelloRequest {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param HelloRequest= obj
+ * @returns HelloRequest
+ */
+static getRootAsHelloRequest(bb:flatbuffers.ByteBuffer, obj?:HelloRequest):HelloRequest {
+  return (obj || new HelloRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param HelloRequest= obj
+ * @returns HelloRequest
+ */
+static getSizePrefixedRootAsHelloRequest(bb:flatbuffers.ByteBuffer, obj?:HelloRequest):HelloRequest {
+  bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+  return (obj || new HelloRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.Encoding= optionalEncoding
+ * @returns string|Uint8Array|null
+ */
+name():string|null
+name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
+name(optionalEncoding?:any):string|Uint8Array|null {
+  var offset = this.bb!.__offset(this.bb_pos, 4);
+  return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startHelloRequest(builder:flatbuffers.Builder) {
+  builder.startObject(1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset nameOffset
+ */
+static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(0, nameOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endHelloRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+static createHelloRequest(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset):flatbuffers.Offset {
+  HelloRequest.startHelloRequest(builder);
+  HelloRequest.addName(builder, nameOffset);
+  return HelloRequest.endHelloRequest(builder);
+}
+
+serialize():Uint8Array {
+  return this.bb!.bytes();
+}
+
+static deserialize(buffer: Uint8Array):HelloRequest {
+  return HelloRequest.getRootAsHelloRequest(new flatbuffers.ByteBuffer(buffer))
+}
+}
diff --git a/grpc/flatbuffers-js-grpc/src/greeter_grpc.d.ts b/grpc/flatbuffers-js-grpc/src/greeter_grpc.d.ts
new file mode 100644 (file)
index 0000000..acd4c2f
--- /dev/null
@@ -0,0 +1,54 @@
+// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT ***
+import { flatbuffers } from 'flatbuffers';
+import *  as Greeter_fbs from './greeter_generated';
+
+import * as grpc from 'grpc';
+
+interface IGreeterService extends grpc.ServiceDefinition<grpc.UntypedServiceImplementation> {
+  SayHello: IGreeterService_ISayHello;
+  SayManyHellos: IGreeterService_ISayManyHellos;
+}
+interface IGreeterService_ISayHello extends grpc.MethodDefinition<Greeter_fbs.HelloRequest, Greeter_fbs.HelloReply> {
+  path: string; // /Greeter/SayHello
+  requestStream: boolean; // false
+  responseStream: boolean; // false
+  requestSerialize: grpc.serialize<Greeter_fbs.HelloRequest>;
+  requestDeserialize: grpc.deserialize<Greeter_fbs.HelloRequest>;
+  responseSerialize: grpc.serialize<Greeter_fbs.HelloReply>;
+  responseDeserialize: grpc.deserialize<Greeter_fbs.HelloReply>;
+}
+
+interface IGreeterService_ISayManyHellos extends grpc.MethodDefinition<Greeter_fbs.HelloRequest, Greeter_fbs.HelloReply> {
+  path: string; // /Greeter/SayManyHellos
+  requestStream: boolean; // false
+  responseStream: boolean; // true
+  requestSerialize: grpc.serialize<Greeter_fbs.HelloRequest>;
+  requestDeserialize: grpc.deserialize<Greeter_fbs.HelloRequest>;
+  responseSerialize: grpc.serialize<Greeter_fbs.HelloReply>;
+  responseDeserialize: grpc.deserialize<Greeter_fbs.HelloReply>;
+}
+
+
+export const GreeterService: IGreeterService;
+
+export interface IGreeterServer {
+  SayHello: grpc.handleUnaryCall<Greeter_fbs.HelloRequest, Greeter_fbs.HelloReply>;
+  SayManyHellos: grpc.handleServerStreamingCall<Greeter_fbs.HelloRequest, Greeter_fbs.HelloReply>;
+}
+
+export interface IGreeterClient {
+  SayHello(request: Greeter_fbs.HelloRequest, callback: (error: grpc.ServiceError | null, response: Greeter_fbs.HelloReply) => void): grpc.ClientUnaryCall;
+  SayHello(request: Greeter_fbs.HelloRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: Greeter_fbs.HelloReply) => void): grpc.ClientUnaryCall;
+  SayHello(request: Greeter_fbs.HelloRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: Greeter_fbs.HelloReply) => void): grpc.ClientUnaryCall;
+  SayManyHellos(request: Greeter_fbs.HelloRequest, metadata: grpc.Metadata): grpc.ClientReadableStream<Greeter_fbs.HelloReply>;
+  SayManyHellos(request: Greeter_fbs.HelloRequest, options: Partial<grpc.CallOptions>): grpc.ClientReadableStream<Greeter_fbs.HelloReply>;
+}
+
+export class GreeterClient extends grpc.Client implements IGreeterClient {
+  constructor(address: string, credentials: grpc.ChannelCredentials, options?: object);  public SayHello(request: Greeter_fbs.HelloRequest, callback: (error: grpc.ServiceError | null, response: Greeter_fbs.HelloReply) => void): grpc.ClientUnaryCall;
+  public SayHello(request: Greeter_fbs.HelloRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: Greeter_fbs.HelloReply) => void): grpc.ClientUnaryCall;
+  public SayHello(request: Greeter_fbs.HelloRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: Greeter_fbs.HelloReply) => void): grpc.ClientUnaryCall;
+  public SayManyHellos(request: Greeter_fbs.HelloRequest, metadata: grpc.Metadata): grpc.ClientReadableStream<Greeter_fbs.HelloReply>;
+  public SayManyHellos(request: Greeter_fbs.HelloRequest, options: Partial<grpc.CallOptions>): grpc.ClientReadableStream<Greeter_fbs.HelloReply>;
+}
+
diff --git a/grpc/flatbuffers-js-grpc/src/greeter_grpc.js b/grpc/flatbuffers-js-grpc/src/greeter_grpc.js
new file mode 100644 (file)
index 0000000..a184ba1
--- /dev/null
@@ -0,0 +1,55 @@
+// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT ***
+import { flatbuffers } from 'flatbuffers';
+import *  as Greeter_fbs from './greeter_generated';
+
+var grpc = require('grpc');
+
+function serialize_HelloReply(buffer_args) {
+  if (!(buffer_args instanceof Greeter_fbs.HelloReply)) {
+    throw new Error('Expected argument of type Greeter_fbs.HelloReply');
+  }
+  return buffer_args.serialize();
+}
+
+function deserialize_HelloReply(buffer) {
+  return Greeter_fbs.HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(buffer))
+}
+
+
+function serialize_HelloRequest(buffer_args) {
+  if (!(buffer_args instanceof Greeter_fbs.HelloRequest)) {
+    throw new Error('Expected argument of type Greeter_fbs.HelloRequest');
+  }
+  return buffer_args.serialize();
+}
+
+function deserialize_HelloRequest(buffer) {
+  return Greeter_fbs.HelloRequest.getRootAsHelloRequest(new flatbuffers.ByteBuffer(buffer))
+}
+
+
+var GreeterService = exports.GreeterService = {
+  SayHello: {
+    path: '/Greeter/SayHello',
+    requestStream: false,
+    responseStream: false,
+    requestType: flatbuffers.ByteBuffer,
+    responseType: Greeter_fbs.HelloReply,
+    requestSerialize: serialize_HelloRequest,
+    requestDeserialize: deserialize_HelloRequest,
+    responseSerialize: serialize_HelloReply,
+    responseDeserialize: deserialize_HelloReply,
+  },
+  SayManyHellos: {
+    path: '/Greeter/SayManyHellos',
+    requestStream: false,
+    responseStream: true,
+    requestType: flatbuffers.ByteBuffer,
+    responseType: Greeter_fbs.HelloReply,
+    requestSerialize: serialize_HelloRequest,
+    requestDeserialize: deserialize_HelloRequest,
+    responseSerialize: serialize_HelloReply,
+    responseDeserialize: deserialize_HelloReply,
+  },
+};
+exports.GreeterClient = grpc.makeGenericClientConstructor(GreeterService);
diff --git a/grpc/flatbuffers-js-grpc/src/server.ts b/grpc/flatbuffers-js-grpc/src/server.ts
new file mode 100644 (file)
index 0000000..47c2f89
--- /dev/null
@@ -0,0 +1,40 @@
+import grpc from 'grpc';
+import { HelloReply, HelloRequest } from './greeter_generated';
+import { IGreeterServer, GreeterService } from './greeter_grpc';
+import { flatbuffers } from 'flatbuffers';
+
+class GreeterServer implements IGreeterServer {
+
+    SayHello(call: grpc.ServerUnaryCall<HelloRequest>, callback: grpc.sendUnaryData<HelloReply>): void {
+        console.log(`${call.request.name()}`);
+        const builder = new flatbuffers.Builder();
+        const offset = builder.createString(`welcome ${call.request.name()}`);
+        const root = HelloReply.createHelloReply(builder, offset);
+        builder.finish(root);
+        callback(null, HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(builder.asUint8Array())));
+    }
+
+    async SayManyHellos(call: grpc.ServerWritableStream<HelloRequest>): Promise<void> {
+        const name = call.request.name();
+        console.log(`${call.request.name()} saying hi in different langagues`);
+        ['Hi', 'Hallo', 'Ciao'].forEach(element => {
+            const builder = new flatbuffers.Builder();
+            const offset = builder.createString(`${element} ${name}`);
+            const root = HelloReply.createHelloReply(builder, offset);
+            builder.finish(root);
+            call.write(HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(builder.asUint8Array())))
+        });
+        call.end();
+    }
+}
+
+function serve(): void {
+    const PORT = 3000;
+    const server = new grpc.Server();
+    server.addService<IGreeterServer>(GreeterService, new GreeterServer());
+    console.log(`Listening on ${PORT}`);
+    server.bind(`localhost:${PORT}`, grpc.ServerCredentials.createInsecure());
+    server.start();
+}
+
+serve();
\ No newline at end of file
diff --git a/grpc/flatbuffers-js-grpc/tsconfig.json b/grpc/flatbuffers-js-grpc/tsconfig.json
new file mode 100644 (file)
index 0000000..7076378
--- /dev/null
@@ -0,0 +1,17 @@
+{
+    "compilerOptions": {
+      "target": "es5",
+      "module": "commonjs",
+      "outDir": "./dist",
+      "allowJs": true,
+      "sourceMap": true,
+      "strict": true,
+      "noImplicitAny": false,
+      "strictNullChecks": false,
+      "esModuleInterop": true,
+      "baseUrl": "./",
+      "typeRoots": ["node_modules/@types"],
+      "skipLibCheck": true, 
+      "forceConsistentCasingInFileNames": true
+    }
+  }
\ No newline at end of file
index f159921090aea2ad9b465aa3f1dddac4695ff03e..23fe54059b61a60ca07a0d8bb3b64e992ea6b1c3 100644 (file)
@@ -105,3 +105,19 @@ cc_library(
         "//:flatbuffers",
     ],
 )
+
+cc_library(
+    name = "ts_generator",
+    srcs = [
+        "ts_generator.cc",
+    ],
+    hdrs = [
+        "ts_generator.h",
+        ":common_headers",
+    ],
+    include_prefix = "src/compiler",
+    strip_include_prefix = "/grpc/src/compiler",
+    deps = [
+        "//:flatbuffers",
+    ],
+)
\ No newline at end of file
index a7979fe6ae8e9df5688bd9df36daf8ea0b96a2e6..bb731d54f55d26d1f15c0ce814a5f43f3e157949 100644 (file)
@@ -229,11 +229,13 @@ void GenerateServerProtocol(const grpc_generator::Service *service,
   printer->Print("}\n\n");
 
   printer->Print(vars, "$ACCESS$ extension $ServiceQualifiedName$Provider {\n");
+  printer->Print("\n");
   printer->Print(vars,
-                 "\tvar serviceName: String { return "
+                 "\tvar serviceName: Substring { return "
                  "\"$PATH$$ServiceName$\" }\n");
+  printer->Print("\n");
   printer->Print(
-      "\tfunc handleMethod(_ methodName: String, callHandlerContext: "
+      "\tfunc handleMethod(_ methodName: Substring, callHandlerContext: "
       "CallHandlerContext) -> GRPCCallHandler? {\n");
   printer->Print("\t\tswitch methodName {\n");
   for (auto it = 0; it < service->method_count(); it++) {
diff --git a/grpc/src/compiler/ts_generator.cc b/grpc/src/compiler/ts_generator.cc
new file mode 100644 (file)
index 0000000..fe9731d
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * 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 <map>
+#include <sstream>
+
+#include "flatbuffers/util.h"
+#include "src/compiler/schema_interface.h"
+#include "src/compiler/ts_generator.h"
+
+namespace grpc_ts_generator {
+
+// MARK: - Shared code
+
+void GenerateImports(grpc_generator::Printer *printer,
+                     std::map<grpc::string, grpc::string> *dictonary,
+                     const bool grpc_var_import) {
+  auto vars = *dictonary;
+  printer->Print(
+      "// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT ***\n");
+  printer->Print("import { flatbuffers } from 'flatbuffers';\n");
+  printer->Print(vars,
+                 "import *  as $FBSFile$ from './$Filename$_generated';\n");
+  printer->Print("\n");
+  if (grpc_var_import)
+    printer->Print("var grpc = require('grpc');\n");
+  else
+    printer->Print("import * as grpc from 'grpc';\n");
+  printer->Print("\n");
+}
+
+// MARK: - Generate Main GRPC Code
+
+void GetStreamType(grpc_generator::Printer *printer,
+                   const grpc_generator::Method *method,
+                   std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  auto client_streaming = method->ClientStreaming() || method->BidiStreaming();
+  auto server_streaming = method->ServerStreaming() || method->BidiStreaming();
+  vars["ClientStreaming"] = client_streaming ? "true" : "false";
+  vars["ServerStreaming"] = server_streaming ? "true" : "false";
+  printer->Print(vars, "requestStream: $ClientStreaming$,\n");
+  printer->Print(vars, "responseStream: $ServerStreaming$,\n");
+}
+
+void GenerateSerializeMethod(grpc_generator::Printer *printer,
+                             std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  printer->Print(vars, "function serialize_$Type$(buffer_args) {\n");
+  printer->Indent();
+  printer->Print(vars, "if (!(buffer_args instanceof $FBSFile$.$Type$)) {\n");
+  printer->Indent();
+  printer->Print(
+      vars, "throw new Error('Expected argument of type $FBSFile$.$Type$');\n");
+  printer->Outdent();
+  printer->Print("}\n");
+  printer->Print(vars, "return buffer_args.serialize();\n");
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+void GenerateDeserializeMethod(
+    grpc_generator::Printer *printer,
+    std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  printer->Print(vars, "function deserialize_$Type$(buffer) {\n");
+  printer->Indent();
+  printer->Print(vars,
+                 "return $FBSFile$.$Type$.getRootAs$Type$(new "
+                 "flatbuffers.ByteBuffer(buffer))\n");
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+void GenerateMethods(const grpc_generator::Service *service,
+                     grpc_generator::Printer *printer,
+                     std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+
+  std::set<grpc::string> generated_functions;
+
+  for (auto it = 0; it < service->method_count(); it++) {
+    auto method = service->method(it);
+    auto output = method->get_output_type_name();
+    auto input = method->get_input_type_name();
+
+    if (generated_functions.find(output) == generated_functions.end()) {
+      generated_functions.insert(output);
+      vars["Type"] = output;
+      GenerateSerializeMethod(printer, &vars);
+      GenerateDeserializeMethod(printer, &vars);
+    }
+    printer->Print("\n");
+    if (generated_functions.find(input) == generated_functions.end()) {
+      generated_functions.insert(input);
+      vars["Type"] = input;
+      GenerateSerializeMethod(printer, &vars);
+      GenerateDeserializeMethod(printer, &vars);
+    }
+  }
+}
+
+void GenerateService(const grpc_generator::Service *service,
+                     grpc_generator::Printer *printer,
+                     std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  vars["NAME"] = service->name() + "Service";
+
+  printer->Print(vars, "var $NAME$ = exports.$NAME$ = {\n");
+  printer->Indent();
+  for (auto it = 0; it < service->method_count(); it++) {
+    auto method = service->method(it);
+    vars["MethodName"] = method->name();
+    vars["Output"] = method->get_output_type_name();
+    vars["Input"] = method->get_input_type_name();
+    printer->Print(vars, "$MethodName$: {\n");
+    printer->Indent();
+    printer->Print(vars, "path: '/$PATH$$ServiceName$/$MethodName$',\n");
+    GetStreamType(printer, &*method, &vars);
+    printer->Print(vars, "requestType: flatbuffers.ByteBuffer,\n");
+    printer->Print(vars, "responseType: $FBSFile$.$Output$,\n");
+    printer->Print(vars, "requestSerialize: serialize_$Input$,\n");
+    printer->Print(vars, "requestDeserialize: deserialize_$Input$,\n");
+    printer->Print(vars, "responseSerialize: serialize_$Output$,\n");
+    printer->Print(vars, "responseDeserialize: deserialize_$Output$,\n");
+    printer->Outdent();
+    printer->Print("},\n");
+  }
+  printer->Outdent();
+  printer->Print("};\n");
+  printer->Print(vars,
+                 "exports.$ServiceName$Client = "
+                 "grpc.makeGenericClientConstructor($NAME$);");
+}
+
+grpc::string Generate(grpc_generator::File *file,
+                      const grpc_generator::Service *service,
+                      const grpc::string &filename) {
+  grpc::string output;
+  std::map<grpc::string, grpc::string> vars;
+
+  vars["PATH"] = file->package();
+
+  if (!file->package().empty()) { vars["PATH"].append("."); }
+
+  vars["ServiceName"] = service->name();
+  vars["FBSFile"] = service->name() + "_fbs";
+  vars["Filename"] = filename;
+  auto printer = file->CreatePrinter(&output);
+
+  GenerateImports(&*printer, &vars, true);
+  GenerateMethods(service, &*printer, &vars);
+  GenerateService(service, &*printer, &vars);
+  return output;
+}
+
+// MARK: - Generate Interface
+
+void FillInterface(grpc_generator::Printer *printer,
+                   std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  printer->Print(
+      vars,
+      "interface I$ServiceName$Service_I$MethodName$ extends "
+      "grpc.MethodDefinition<$FBSFile$.$INPUT$, $FBSFile$.$OUTPUT$> {\n");
+  printer->Indent();
+  printer->Print(vars, "path: string; // /$PATH$$ServiceName$/$MethodName$\n");
+  printer->Print(vars, "requestStream: boolean; // $ClientStreaming$\n");
+  printer->Print(vars, "responseStream: boolean; // $ServerStreaming$\n");
+  printer->Print(vars,
+                 "requestSerialize: grpc.serialize<$FBSFile$.$INPUT$>;\n");
+  printer->Print(vars,
+                 "requestDeserialize: grpc.deserialize<$FBSFile$.$INPUT$>;\n");
+  printer->Print(vars,
+                 "responseSerialize: grpc.serialize<$FBSFile$.$OUTPUT$>;\n");
+  printer->Print(
+      vars, "responseDeserialize: grpc.deserialize<$FBSFile$.$OUTPUT$>;\n");
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void GenerateInterfaces(const grpc_generator::Service *service,
+                        grpc_generator::Printer *printer,
+                        std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  for (auto it = 0; it < service->method_count(); it++) {
+    auto method = service->method(it);
+    auto client_streaming =
+        method->ClientStreaming() || method->BidiStreaming();
+    auto server_streaming =
+        method->ServerStreaming() || method->BidiStreaming();
+    vars["ClientStreaming"] = client_streaming ? "true" : "false";
+    vars["ServerStreaming"] = server_streaming ? "true" : "false";
+    vars["MethodName"] = method->name();
+    vars["INPUT"] = method->get_input_type_name();
+    vars["OUTPUT"] = method->get_output_type_name();
+    FillInterface(printer, &vars);
+    printer->Print("\n");
+  }
+}
+
+void GenerateExportedInterface(
+    const grpc_generator::Service *service, grpc_generator::Printer *printer,
+    std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  printer->Print(vars, "export interface I$ServiceName$Server {\n");
+  printer->Indent();
+  for (auto it = 0; it < service->method_count(); it++) {
+    auto method = service->method(it);
+    vars["Name"] = method->name();
+    vars["INPUT"] = method->get_input_type_name();
+    vars["OUTPUT"] = method->get_output_type_name();
+    if (method->BidiStreaming()) {
+      printer->Print(vars,
+                     "$Name$: grpc.handleBidiStreamingCall<$FBSFile$.$INPUT$, "
+                     "$FBSFile$.$OUTPUT$>;\n");
+      continue;
+    }
+    if (method->NoStreaming()) {
+      printer->Print(vars,
+                     "$Name$: grpc.handleUnaryCall<$FBSFile$.$INPUT$, "
+                     "$FBSFile$.$OUTPUT$>;\n");
+      continue;
+    }
+    if (method->ClientStreaming()) {
+      printer->Print(
+          vars,
+          "$Name$: grpc.handleClientStreamingCall<$FBSFile$.$INPUT$, "
+          "$FBSFile$.$OUTPUT$>;\n");
+      continue;
+    }
+    if (method->ServerStreaming()) {
+      printer->Print(
+          vars,
+          "$Name$: grpc.handleServerStreamingCall<$FBSFile$.$INPUT$, "
+          "$FBSFile$.$OUTPUT$>;\n");
+      continue;
+    }
+  }
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void GenerateMainInterface(const grpc_generator::Service *service,
+                           grpc_generator::Printer *printer,
+                           std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  printer->Print(
+      vars,
+      "interface I$ServiceName$Service extends "
+      "grpc.ServiceDefinition<grpc.UntypedServiceImplementation> {\n");
+  printer->Indent();
+  for (auto it = 0; it < service->method_count(); it++) {
+    auto method = service->method(it);
+    vars["MethodName"] = method->name();
+    printer->Print(vars,
+                   "$MethodName$: I$ServiceName$Service_I$MethodName$;\n");
+  }
+  printer->Outdent();
+  printer->Print("}\n");
+  GenerateInterfaces(service, printer, &vars);
+  printer->Print("\n");
+  printer->Print(vars,
+                 "export const $ServiceName$Service: I$ServiceName$Service;\n");
+  printer->Print("\n");
+  GenerateExportedInterface(service, printer, &vars);
+}
+
+grpc::string GenerateMetaData() { return "metadata: grpc.Metadata"; }
+
+grpc::string GenerateOptions() { return "options: Partial<grpc.CallOptions>"; }
+
+void GenerateUnaryClientInterface(
+    grpc_generator::Printer *printer,
+    std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  grpc::string main = "$ISPUBLIC$$MethodName$(request: $FBSFile$.$INPUT$, ";
+  grpc::string callback =
+      "callback: (error: grpc.ServiceError | null, response: "
+      "$FBSFile$.$OUTPUT$) => void): grpc.ClientUnaryCall;\n";
+  auto meta_data = GenerateMetaData() + ", ";
+  auto options = GenerateOptions() + ", ";
+  printer->Print(vars, (main + callback).c_str());
+  printer->Print(vars, (main + meta_data + callback).c_str());
+  printer->Print(vars, (main + meta_data + options + callback).c_str());
+}
+
+void GenerateClientWriteStreamInterface(
+    grpc_generator::Printer *printer,
+    std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  grpc::string main = "$ISPUBLIC$$MethodName$(";
+  grpc::string callback =
+      "callback: (error: grpc.ServiceError | null, response: "
+      "$FBSFile$.$INPUT$) => void): "
+      "grpc.ClientWritableStream<$FBSFile$.$OUTPUT$>;\n";
+  auto meta_data = GenerateMetaData() + ", ";
+  auto options = GenerateOptions() + ", ";
+  printer->Print(vars, (main + callback).c_str());
+  printer->Print(vars, (main + meta_data + callback).c_str());
+  printer->Print(vars, (main + options + callback).c_str());
+  printer->Print(vars, (main + meta_data + options + callback).c_str());
+}
+
+void GenerateClientReadableStreamInterface(
+    grpc_generator::Printer *printer,
+    std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  grpc::string main = "$ISPUBLIC$$MethodName$(request: $FBSFile$.$INPUT$, ";
+  grpc::string end_function =
+      "): grpc.ClientReadableStream<$FBSFile$.$OUTPUT$>;\n";
+  auto meta_data = GenerateMetaData();
+  auto options = GenerateOptions();
+  printer->Print(vars, (main + meta_data + end_function).c_str());
+  printer->Print(vars, (main + options + end_function).c_str());
+}
+
+void GenerateDepluxStreamInterface(
+    grpc_generator::Printer *printer,
+    std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  grpc::string main = "$ISPUBLIC$$MethodName$(";
+  grpc::string end_function =
+      "): grpc.ClientDuplexStream<$FBSFile$.$INPUT$, $FBSFile$.$OUTPUT$>;\n";
+  auto meta_data = GenerateMetaData();
+  auto options = GenerateOptions();
+  printer->Print(vars, (main + end_function).c_str());
+  printer->Print(vars, (main + options + end_function).c_str());
+  printer->Print(vars, (main + meta_data +
+                        ", options?: Partial<grpc.CallOptions>" + end_function)
+                           .c_str());
+}
+
+void GenerateClientInterface(const grpc_generator::Service *service,
+                             grpc_generator::Printer *printer,
+                             std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  printer->Print(vars, "export interface I$ServiceName$Client {\n");
+  printer->Indent();
+  for (auto it = 0; it < service->method_count(); it++) {
+    auto method = service->method(it);
+    vars["MethodName"] = method->name();
+    vars["INPUT"] = method->get_input_type_name();
+    vars["OUTPUT"] = method->get_output_type_name();
+    vars["ISPUBLIC"] = "";
+
+    if (method->NoStreaming()) {
+      GenerateUnaryClientInterface(printer, &vars);
+      continue;
+    }
+    if (method->BidiStreaming()) {
+      GenerateDepluxStreamInterface(printer, &vars);
+      continue;
+    }
+
+    if (method->ClientStreaming()) {
+      GenerateClientWriteStreamInterface(printer, &vars);
+      continue;
+    }
+
+    if (method->ServerStreaming()) {
+      GenerateClientReadableStreamInterface(printer, &vars);
+      continue;
+    }
+  }
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void GenerateClientClassInterface(
+    const grpc_generator::Service *service, grpc_generator::Printer *printer,
+    std::map<grpc::string, grpc::string> *dictonary) {
+  auto vars = *dictonary;
+  printer->Print(vars,
+                 "export class $ServiceName$Client extends grpc.Client "
+                 "implements I$ServiceName$Client {\n");
+  printer->Indent();
+  printer->Print(
+      "constructor(address: string, credentials: grpc.ChannelCredentials, "
+      "options?: object);");
+  for (auto it = 0; it < service->method_count(); it++) {
+    auto method = service->method(it);
+    vars["MethodName"] = method->name();
+    vars["INPUT"] = method->get_input_type_name();
+    vars["OUTPUT"] = method->get_output_type_name();
+    vars["ISPUBLIC"] = "public ";
+    if (method->NoStreaming()) {
+      GenerateUnaryClientInterface(printer, &vars);
+      continue;
+    }
+    if (method->BidiStreaming()) {
+      GenerateDepluxStreamInterface(printer, &vars);
+      continue;
+    }
+
+    if (method->ClientStreaming()) {
+      GenerateClientWriteStreamInterface(printer, &vars);
+      continue;
+    }
+
+    if (method->ServerStreaming()) {
+      GenerateClientReadableStreamInterface(printer, &vars);
+      continue;
+    }
+  }
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+grpc::string GenerateInterface(grpc_generator::File *file,
+                               const grpc_generator::Service *service,
+                               const grpc::string &filename) {
+  grpc::string output;
+
+  std::set<grpc::string> generated_functions;
+  std::map<grpc::string, grpc::string> vars;
+
+  vars["PATH"] = file->package();
+
+  if (!file->package().empty()) { vars["PATH"].append("."); }
+
+  vars["ServiceName"] = service->name();
+  vars["FBSFile"] = service->name() + "_fbs";
+  vars["Filename"] = filename;
+  auto printer = file->CreatePrinter(&output);
+
+  GenerateImports(&*printer, &vars, false);
+  GenerateMainInterface(service, &*printer, &vars);
+  printer->Print("\n");
+  GenerateClientInterface(service, &*printer, &vars);
+  printer->Print("\n");
+  GenerateClientClassInterface(service, &*printer, &vars);
+  return output;
+}
+}  // namespace grpc_ts_generator
diff --git a/grpc/src/compiler/ts_generator.h b/grpc/src/compiler/ts_generator.h
new file mode 100644 (file)
index 0000000..a33bb3c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *
+ * 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 <memory>
+#include <vector>
+#include <set>
+
+#include "src/compiler/config.h"
+#include "src/compiler/schema_interface.h"
+
+#ifndef GRPC_CUSTOM_STRING
+#  include <string>
+#  define GRPC_CUSTOM_STRING std::string
+#endif
+
+namespace grpc {
+
+typedef GRPC_CUSTOM_STRING string;
+
+}  // namespace grpc
+
+namespace grpc_ts_generator {
+grpc::string Generate(grpc_generator::File *file,
+                      const grpc_generator::Service *service,
+                      const grpc::string &filename);
+
+grpc::string GenerateInterface(grpc_generator::File *file,
+                               const grpc_generator::Service *service,
+                               const grpc::string &filename);
+}  // namespace grpc_ts_generator
+
index a3c3188394bccdcf967d42ee07794ce615c23bc3..af7eb9b7da50baf69bee14ffd5e6a687886f5714 100644 (file)
@@ -1146,6 +1146,8 @@ bool GeneratePythonGRPC(const Parser &parser, const std::string &path,
 extern bool GenerateSwiftGRPC(const Parser &parser, const std::string &path,
                               const std::string &file_name);
 
+extern bool GenerateTSGRPC(const Parser &parser, const std::string &path,
+                             const std::string &file_name);
 }  // namespace flatbuffers
 
 #endif  // FLATBUFFERS_IDL_H_
index 86f0a7d600f4ef90d5feaad0d89fc21d9e5ad3f7..471d5da889e4af04cc7a40687cc879cba0d7dee4 100644 (file)
--- a/src/BUILD
+++ b/src/BUILD
@@ -71,5 +71,6 @@ cc_library(
         "//grpc/src/compiler:java_generator",
         "//grpc/src/compiler:python_generator",
         "//grpc/src/compiler:swift_generator",
+        "//grpc/src/compiler:ts_generator",
     ],
 )
index 0ad26448d3e0a2e796d897df680c8e52cc144c2a..c942bdacb2ca730fe58c0f561fdffc05662b038a 100644 (file)
@@ -78,8 +78,8 @@ int main(int argc, const char *argv[]) {
     { flatbuffers::GenerateDart, "-d", "--dart", "Dart", true, nullptr,
       flatbuffers::IDLOptions::kDart,
       "Generate Dart classes for tables/structs", flatbuffers::DartMakeRule },
-    { flatbuffers::GenerateJSTS, "-T", "--ts", "TypeScript", true, nullptr,
-      flatbuffers::IDLOptions::kTs,
+    { flatbuffers::GenerateJSTS, "-T", "--ts", "TypeScript", true,
+      flatbuffers::GenerateTSGRPC, flatbuffers::IDLOptions::kTs,
       "Generate TypeScript code for tables/structs",
       flatbuffers::JSTSMakeRule },
     { flatbuffers::GenerateCSharp, "-n", "--csharp", "C#", true, nullptr,
index 9cb01696929d001da184c5b8196a872fec4ffb95..f6535f0cc7de29367a508640d672bc691d7d9568 100644 (file)
@@ -1714,9 +1714,7 @@ class CppGenerator : public BaseGenerator {
         auto native_default = field.attributes.Lookup("native_default");
         // Scalar types get parsed defaults, raw pointers get nullptrs.
         if (IsScalar(field.value.type.base_type)) {
-          if (!initializer_list.empty()) {
-            initializer_list += ",\n        ";
-          }
+          if (!initializer_list.empty()) { initializer_list += ",\n        "; }
           initializer_list += Name(field);
           initializer_list +=
               "(" +
@@ -1992,8 +1990,7 @@ class CppGenerator : public BaseGenerator {
       code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
       code_ += "    return {{FIELD_VALUE}};";
       code_ += "  }";
-    }
-    else {
+    } else {
       auto wire_type = GenTypeBasic(type, false);
       auto face_type = GenTypeBasic(type, true);
       auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
@@ -2011,7 +2008,7 @@ class CppGenerator : public BaseGenerator {
     const auto &type = field.value.type;
     const bool is_scalar = IsScalar(type.base_type);
     if (is_scalar && IsUnion(type))
-      return; // changing of a union's type is forbidden
+      return;  // changing of a union's type is forbidden
 
     auto offset_str = GenFieldOffsetName(field);
     if (is_scalar) {
@@ -2109,9 +2106,7 @@ class CppGenerator : public BaseGenerator {
 
       code_.SetValue("FIELD_NAME", Name(field));
       GenTableFieldGetter(field);
-      if (opts_.mutable_buffer) {
-        GenTableFieldSetter(field);
-      }
+      if (opts_.mutable_buffer) { GenTableFieldSetter(field); }
 
       auto nested = field.attributes.Lookup("nested_flatbuffer");
       if (nested) {
@@ -2252,8 +2247,7 @@ class CppGenerator : public BaseGenerator {
     for (auto it = struct_def.fields.vec.begin();
          it != struct_def.fields.vec.end(); ++it) {
       const auto &field = **it;
-      if (field.deprecated)
-        continue;
+      if (field.deprecated) continue;
       const bool is_scalar = IsScalar(field.value.type.base_type);
       const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
       const bool is_string = field.value.type.base_type == BASE_TYPE_STRING;
@@ -2813,15 +2807,17 @@ class CppGenerator : public BaseGenerator {
       code_ +=
           "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
 
-      if(opts_.g_cpp_std == cpp::CPP_STD_X0) {
+      if (opts_.g_cpp_std == cpp::CPP_STD_X0) {
         auto native_name =
             NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts);
         code_.SetValue("POINTER_TYPE",
                        GenTypeNativePtr(native_name, nullptr, false));
         code_ +=
             "  {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
-      } else if(opts_.g_cpp_std == cpp::CPP_STD_11) {
-        code_ += "  auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new {{NATIVE_NAME}}());";
+      } else if (opts_.g_cpp_std == cpp::CPP_STD_11) {
+        code_ +=
+            "  auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new "
+            "{{NATIVE_NAME}}());";
       } else {
         code_ += "  auto _o = std::make_unique<{{NATIVE_NAME}}>();";
       }
@@ -2958,8 +2954,7 @@ class CppGenerator : public BaseGenerator {
     int padding_initializer_id = 0;
     int padding_body_id = 0;
     for (auto it = struct_def.fields.vec.begin();
-         it != struct_def.fields.vec.end();
-         ++it) {
+         it != struct_def.fields.vec.end(); ++it) {
       const auto field = *it;
       const auto field_name = field->name + "_";
 
index e4dde75f664cc62d61660170071f47bf97819c59..80fd5834d70ea5e00b0cdbcf28a4366269b445e8 100644 (file)
@@ -486,8 +486,7 @@ class DartGenerator : public BaseGenerator {
       auto &part = *it;
 
       for (size_t i = 0; i < part.length(); i++) {
-        if (i && !isdigit(part[i]) &&
-            part[i] == CharToUpper(part[i])) {
+        if (i && !isdigit(part[i]) && part[i] == CharToUpper(part[i])) {
           ns += "_";
           ns += CharToLower(part[i]);
         } else {
index 86a2c593e077ca2a08784b26529d33791fdf68ec..394ebe32fbdb304a7acf9b14d1709a989e4c8b12 100644 (file)
@@ -26,6 +26,7 @@
 #include "src/compiler/python_generator.h"
 #include "src/compiler/python_private_generator.h"
 #include "src/compiler/swift_generator.h"
+#include "src/compiler/ts_generator.h"
 
 #if defined(_MSC_VER)
 #  pragma warning(push)
@@ -206,7 +207,8 @@ class FlatBufFile : public grpc_generator::File {
     kLanguageCpp,
     kLanguageJava,
     kLanguagePython,
-    kLanguageSwift
+    kLanguageSwift,
+    kLanguageTS
   };
 
   FlatBufFile(const Parser &parser, const std::string &file_name,
@@ -258,6 +260,9 @@ class FlatBufFile : public grpc_generator::File {
       case kLanguageSwift: {
         return "";
       }
+      case kLanguageTS: {
+        return "";
+      }
     }
     return "";
   }
@@ -467,6 +472,54 @@ bool GenerateSwiftGRPC(const Parser &parser, const std::string &path,
   return SwiftGRPCGenerator(parser, path, file_name).generate();
 }
 
+class TSGRPCGenerator : public flatbuffers::BaseGenerator {
+ private:
+  CodeWriter code_;
+
+ public:
+  TSGRPCGenerator(const Parser &parser, const std::string &path,
+                  const std::string &filename)
+      : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "ts") {}
+
+  bool generate() {
+    code_.Clear();
+    FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageTS);
+
+    for (int i = 0; i < file.service_count(); i++) {
+      auto service = file.service(i);
+      code_ += grpc_ts_generator::Generate(&file, service.get(), file_name_);
+      const auto ts_name = GeneratedFileName(path_, file_name_);
+      if (!SaveFile(ts_name.c_str(), code_.ToString(), false)) return false;
+
+      code_.Clear();
+      code_ += grpc_ts_generator::GenerateInterface(&file, service.get(),
+                                                    file_name_);
+      const auto ts_interface_name = GeneratedFileName(path_, file_name_, true);
+      if (!SaveFile(ts_interface_name.c_str(), code_.ToString(), false))
+        return false;
+    }
+    return true;
+  }
+
+  static std::string GeneratedFileName(const std::string &path,
+                                       const std::string &file_name,
+                                       const bool is_interface = false) {
+    if (is_interface) return path + file_name + "_grpc.d.ts";
+    return path + file_name + "_grpc.js";
+  }
+};
+
+bool GenerateTSGRPC(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 TSGRPCGenerator(parser, path, file_name).generate();
+}
+
 }  // namespace flatbuffers
 
 #if defined(_MSC_VER)
index 02b85bd2f0d941f7f7dc66cb3b20dddd625316fa..71b68b853148e0c581abb40cc1c2b7eb373d585d 100644 (file)
@@ -141,7 +141,8 @@ class JsTsGenerator : public BaseGenerator {
       const auto &file = *it;
       const auto basename =
           flatbuffers::StripPath(flatbuffers::StripExtension(file.first));
-      if (basename != file_name_ && imported.find(file.second.symbol) == imported.end()) {
+      if (basename != file_name_ &&
+          imported.find(file.second.symbol) == imported.end()) {
         if (imported_files.find(file.first) == imported_files.end()) {
           code += GenPrefixedImport(file.first, basename);
           imported_files.emplace(file.first);
@@ -225,9 +226,7 @@ class JsTsGenerator : public BaseGenerator {
     for (auto it = sorted_namespaces.begin(); it != sorted_namespaces.end();
          ++it) {
       if (lang_.language == IDLOptions::kTs) {
-        if (it->find('.') == std::string::npos) {
-          break;
-        }
+        if (it->find('.') == std::string::npos) { break; }
       } else {
         code += "/**\n * @const\n * @namespace\n */\n";
         if (it->find('.') == std::string::npos) {
@@ -992,8 +991,8 @@ class JsTsGenerator : public BaseGenerator {
     std::string constructor_func = "constructor(";
     constructor_func += (struct_def.fields.vec.empty() ? "" : "\n");
 
-
-    const auto has_create = struct_def.fixed || CanCreateFactoryMethod(struct_def);
+    const auto has_create =
+        struct_def.fixed || CanCreateFactoryMethod(struct_def);
 
     std::string pack_func_prototype =
         "/**\n * " +
@@ -1004,14 +1003,13 @@ class JsTsGenerator : public BaseGenerator {
     std::string pack_func_offset_decl;
     std::string pack_func_create_call;
 
-    const auto struct_name = GenPrefixedTypeName(WrapInNameSpace(struct_def), struct_def.file);
+    const auto struct_name =
+        GenPrefixedTypeName(WrapInNameSpace(struct_def), struct_def.file);
 
     if (has_create) {
-      pack_func_create_call =
-        "  return " +
-        struct_name +
-        ".create" + Verbose(struct_def) + "(builder" +
-        (struct_def.fields.vec.empty() ? "" : ",\n    ");
+      pack_func_create_call = "  return " + struct_name + ".create" +
+                              Verbose(struct_def) + "(builder" +
+                              (struct_def.fields.vec.empty() ? "" : ",\n    ");
     } else {
       pack_func_create_call = "  " + struct_name + ".start(builder);\n";
     }
@@ -1231,7 +1229,9 @@ class JsTsGenerator : public BaseGenerator {
         if (has_create) {
           pack_func_create_call += field_offset_val;
         } else {
-          pack_func_create_call += "  " + struct_name + ".add" + MakeCamel(field.name) + "(builder, " + field_offset_val + ");\n";
+          pack_func_create_call += "  " + struct_name + ".add" +
+                                   MakeCamel(field.name) + "(builder, " +
+                                   field_offset_val + ");\n";
         }
       }
 
@@ -1239,7 +1239,9 @@ class JsTsGenerator : public BaseGenerator {
         constructor_annotation += "\n";
         constructor_func += ",\n";
 
-        if (!struct_def.fixed && has_create) { pack_func_create_call += ",\n    "; }
+        if (!struct_def.fixed && has_create) {
+          pack_func_create_call += ",\n    ";
+        }
 
         unpack_func += ",\n";
         unpack_to_func += "\n";
@@ -1698,11 +1700,12 @@ class JsTsGenerator : public BaseGenerator {
 
         if (struct_def.fixed) {
           code += "  " + GenBBAccess() + ".write" +
-                  MakeCamel(GenType(field.value.type)) +
-                  "(this.bb_pos + " + NumToString(field.value.offset) + ", ";
+                  MakeCamel(GenType(field.value.type)) + "(this.bb_pos + " +
+                  NumToString(field.value.offset) + ", ";
         } else {
-          code += "  var offset = " + GenBBAccess() + ".__offset(this.bb_pos, " +
-                  NumToString(field.value.offset) + ");\n\n";
+          code += "  var offset = " + GenBBAccess() +
+                  ".__offset(this.bb_pos, " + NumToString(field.value.offset) +
+                  ");\n\n";
           code += "  if (offset === 0) {\n";
           code += "    return false;\n";
           code += "  }\n\n";
@@ -2063,6 +2066,21 @@ class JsTsGenerator : public BaseGenerator {
       }
     }
 
+    if (!struct_def.fixed && parser_.services_.vec.size() != 0 &&
+        lang_.language == IDLOptions::kTs) {
+      auto name = Verbose(struct_def, "");
+      code += "\n";
+      code += "serialize():Uint8Array {\n";
+      code += "  return this.bb!.bytes();\n";
+      code += "}\n";
+
+      code += "\n";
+      code += "static deserialize(buffer: Uint8Array):"+ name +" {\n";
+      code += "  return " + name + ".getRootAs" + name +
+              "(new flatbuffers.ByteBuffer(buffer))\n";
+      code += "}\n";
+    }
+
     if (lang_.language == IDLOptions::kTs) {
       if (parser_.opts.generate_object_based_api) {
         std::string obj_api_class;
index 79913f5473742925004fe3be8f0c3f5d8681d62f..80416d5e7569f7361dd4396fcc3a821c69f2fe29 100644 (file)
@@ -303,12 +303,15 @@ class KotlinGenerator : public BaseGenerator {
           }
           writer += ")";
         });
-        GenerateFunOneLine(writer, "name", "e: Int", "String", [&]() {
-          writer += "names[e\\";
-          if (enum_def.MinValue()->IsNonZero())
-            writer += " - " + enum_def.MinValue()->name + ".toInt()\\";
-          writer += "]";
-        }, parser_.opts.gen_jvmstatic);
+        GenerateFunOneLine(
+            writer, "name", "e: Int", "String",
+            [&]() {
+              writer += "names[e\\";
+              if (enum_def.MinValue()->IsNonZero())
+                writer += " - " + enum_def.MinValue()->name + ".toInt()\\";
+              writer += "]";
+            },
+            parser_.opts.gen_jvmstatic);
       }
     });
     writer.DecrementIdentLevel();
@@ -449,7 +452,8 @@ class KotlinGenerator : public BaseGenerator {
     return key_offset;
   }
 
-  void GenStruct(StructDef &struct_def, CodeWriter &writer, IDLOptions options) const {
+  void GenStruct(StructDef &struct_def, CodeWriter &writer,
+                 IDLOptions options) const {
     if (struct_def.generated) return;
 
     GenerateComment(struct_def.doc_comment, writer, &comment_config);
@@ -488,9 +492,10 @@ class KotlinGenerator : public BaseGenerator {
           // Generate verson check method.
           // Force compile time error if not using the same version
           // runtime.
-          GenerateFunOneLine(writer, "validateVersion", "", "", [&]() {
-            writer += "Constants.FLATBUFFERS_1_12_0()";
-          }, options.gen_jvmstatic);
+          GenerateFunOneLine(
+              writer, "validateVersion", "", "",
+              [&]() { writer += "Constants.FLATBUFFERS_1_12_0()"; },
+              options.gen_jvmstatic);
 
           GenerateGetRootAsAccessors(Esc(struct_def.name), writer, options);
           GenerateBufferHasIdentifier(struct_def, writer, options);
@@ -520,8 +525,10 @@ class KotlinGenerator : public BaseGenerator {
           GenerateEndStructMethod(struct_def, writer, options);
           auto file_identifier = parser_.file_identifier_;
           if (parser_.root_struct_def_ == &struct_def) {
-            GenerateFinishStructBuffer(struct_def, file_identifier, writer, options);
-            GenerateFinishSizePrefixed(struct_def, file_identifier, writer, options);
+            GenerateFinishStructBuffer(struct_def, file_identifier, writer,
+                                       options);
+            GenerateFinishSizePrefixed(struct_def, file_identifier, writer,
+                                       options);
           }
 
           if (struct_def.has_key) {
@@ -606,9 +613,10 @@ class KotlinGenerator : public BaseGenerator {
     auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
     auto params = "builder: FlatBufferBuilder, offset: Int";
     auto method_name = "finishSizePrefixed" + Esc(struct_def.name) + "Buffer";
-    GenerateFunOneLine(writer, method_name, params, "", [&]() {
-      writer += "builder.finishSizePrefixed(offset" + id + ")";
-    }, options.gen_jvmstatic);
+    GenerateFunOneLine(
+        writer, method_name, params, "",
+        [&]() { writer += "builder.finishSizePrefixed(offset" + id + ")"; },
+        options.gen_jvmstatic);
   }
   void GenerateFinishStructBuffer(StructDef &struct_def,
                                   const std::string &identifier,
@@ -617,9 +625,10 @@ class KotlinGenerator : public BaseGenerator {
     auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
     auto params = "builder: FlatBufferBuilder, offset: Int";
     auto method_name = "finish" + Esc(struct_def.name) + "Buffer";
-    GenerateFunOneLine(writer, method_name, params, "",
-                       [&]() { writer += "builder.finish(offset" + id + ")"; },
-                       options.gen_jvmstatic);
+    GenerateFunOneLine(
+        writer, method_name, params, "",
+        [&]() { writer += "builder.finish(offset" + id + ")"; },
+        options.gen_jvmstatic);
   }
 
   void GenerateEndStructMethod(StructDef &struct_def, CodeWriter &writer,
@@ -630,18 +639,21 @@ class KotlinGenerator : public BaseGenerator {
     auto returns = "Int";
     auto field_vec = struct_def.fields.vec;
 
-    GenerateFun(writer, name, params, returns, [&]() {
-      writer += "val o = builder.endTable()";
-      writer.IncrementIdentLevel();
-      for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
-        auto &field = **it;
-        if (field.deprecated || !field.required) { continue; }
-        writer.SetValue("offset", NumToString(field.value.offset));
-        writer += "builder.required(o, {{offset}})";
-      }
-      writer.DecrementIdentLevel();
-      writer += "return o";
-    }, options.gen_jvmstatic);
+    GenerateFun(
+        writer, name, params, returns,
+        [&]() {
+          writer += "val o = builder.endTable()";
+          writer.IncrementIdentLevel();
+          for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
+            auto &field = **it;
+            if (field.deprecated || !field.required) { continue; }
+            writer.SetValue("offset", NumToString(field.value.offset));
+            writer += "builder.required(o, {{offset}})";
+          }
+          writer.DecrementIdentLevel();
+          writer += "return o";
+        },
+        options.gen_jvmstatic);
   }
 
   // Generate a method to create a vector from a Kotlin array.
@@ -656,15 +668,18 @@ class KotlinGenerator : public BaseGenerator {
     writer.SetValue("root", GenMethod(vector_type));
     writer.SetValue("cast", CastToSigned(vector_type));
 
-    GenerateFun(writer, method_name, params, "Int", [&]() {
-      writer += "builder.startVector({{size}}, data.size, {{align}})";
-      writer += "for (i in data.size - 1 downTo 0) {";
-      writer.IncrementIdentLevel();
-      writer += "builder.add{{root}}(data[i]{{cast}})";
-      writer.DecrementIdentLevel();
-      writer += "}";
-      writer += "return builder.endVector()";
-    }, options.gen_jvmstatic);
+    GenerateFun(
+        writer, method_name, params, "Int",
+        [&]() {
+          writer += "builder.startVector({{size}}, data.size, {{align}})";
+          writer += "for (i in data.size - 1 downTo 0) {";
+          writer.IncrementIdentLevel();
+          writer += "builder.add{{root}}(data[i]{{cast}})";
+          writer.DecrementIdentLevel();
+          writer += "}";
+          writer += "return builder.endVector()";
+        },
+        options.gen_jvmstatic);
   }
 
   void GenerateStartVectorField(FieldDef &field, CodeWriter &writer,
@@ -678,9 +693,11 @@ class KotlinGenerator : public BaseGenerator {
 
     GenerateFunOneLine(
         writer, "start" + MakeCamel(Esc(field.name) + "Vector", true), params,
-        "", [&]() {
+        "",
+        [&]() {
           writer += "builder.startVector({{size}}, numElems, {{align}})";
-        }, options.gen_jvmstatic);
+        },
+        options.gen_jvmstatic);
   }
 
   void GenerateAddField(std::string field_pos, FieldDef &field,
@@ -745,12 +762,13 @@ class KotlinGenerator : public BaseGenerator {
   // fun startMonster(builder: FlatBufferBuilder) = builder.startTable(11)
   void GenerateStartStructMethod(StructDef &struct_def, CodeWriter &code,
                                  const IDLOptions options) const {
-    GenerateFunOneLine(code, "start" + Esc(struct_def.name),
-                       "builder: FlatBufferBuilder", "", [&]() {
-                         code += "builder.startTable(" +
-                                 NumToString(struct_def.fields.vec.size()) +
-                                 ")";
-                       }, options.gen_jvmstatic);
+    GenerateFunOneLine(
+        code, "start" + Esc(struct_def.name), "builder: FlatBufferBuilder", "",
+        [&]() {
+          code += "builder.startTable(" +
+                  NumToString(struct_def.fields.vec.size()) + ")";
+        },
+        options.gen_jvmstatic);
   }
 
   void GenerateTableCreator(StructDef &struct_def, CodeWriter &writer,
@@ -793,51 +811,59 @@ class KotlinGenerator : public BaseGenerator {
         params << GenTypeBasic(field.value.type.base_type) << optional;
       }
 
-      GenerateFun(writer, name, params.str(), "Int", [&]() {
-        writer.SetValue("vec_size", NumToString(fields_vec.size()));
-
-        writer += "builder.startTable({{vec_size}})";
-
-        auto sortbysize = struct_def.sortbysize;
-        auto largest = sortbysize ? sizeof(largest_scalar_t) : 1;
-        for (size_t size = largest; size; size /= 2) {
-          for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); ++it) {
-            auto &field = **it;
-            auto base_type_size = SizeOf(field.value.type.base_type);
-            if (!field.deprecated && (!sortbysize || size == base_type_size)) {
-              writer.SetValue("camel_field_name",
-                              MakeCamel(Esc(field.name), true));
-              writer.SetValue("field_name", MakeCamel(Esc(field.name), false));
-
-              // we wrap on null check for scalar optionals
-              writer +=
-                  field.IsScalarOptional() ? "{{field_name}}?.run { \\" : "\\";
-
-              writer += "add{{camel_field_name}}(builder, {{field_name}}\\";
-              if (!IsScalar(field.value.type.base_type)) {
-                writer += "Offset\\";
+      GenerateFun(
+          writer, name, params.str(), "Int",
+          [&]() {
+            writer.SetValue("vec_size", NumToString(fields_vec.size()));
+
+            writer += "builder.startTable({{vec_size}})";
+
+            auto sortbysize = struct_def.sortbysize;
+            auto largest = sortbysize ? sizeof(largest_scalar_t) : 1;
+            for (size_t size = largest; size; size /= 2) {
+              for (auto it = fields_vec.rbegin(); it != fields_vec.rend();
+                   ++it) {
+                auto &field = **it;
+                auto base_type_size = SizeOf(field.value.type.base_type);
+                if (!field.deprecated &&
+                    (!sortbysize || size == base_type_size)) {
+                  writer.SetValue("camel_field_name",
+                                  MakeCamel(Esc(field.name), true));
+                  writer.SetValue("field_name",
+                                  MakeCamel(Esc(field.name), false));
+
+                  // we wrap on null check for scalar optionals
+                  writer += field.IsScalarOptional()
+                                ? "{{field_name}}?.run { \\"
+                                : "\\";
+
+                  writer += "add{{camel_field_name}}(builder, {{field_name}}\\";
+                  if (!IsScalar(field.value.type.base_type)) {
+                    writer += "Offset\\";
+                  }
+                  // we wrap on null check for scalar optionals
+                  writer += field.IsScalarOptional() ? ") }" : ")";
+                }
               }
-              // we wrap on null check for scalar optionals
-              writer += field.IsScalarOptional() ? ") }" : ")";
             }
-          }
-        }
-        writer += "return end{{struct_name}}(builder)";
-      }, options.gen_jvmstatic);
+            writer += "return end{{struct_name}}(builder)";
+          },
+          options.gen_jvmstatic);
     }
   }
-  void GenerateBufferHasIdentifier(StructDef &struct_def,
-                                   CodeWriter &writer, IDLOptions options) const {
+  void GenerateBufferHasIdentifier(StructDef &struct_def, CodeWriter &writer,
+                                   IDLOptions options) const {
     auto file_identifier = parser_.file_identifier_;
     // Check if a buffer has the identifier.
     if (parser_.root_struct_def_ != &struct_def || !file_identifier.length())
       return;
     auto name = MakeCamel(Esc(struct_def.name), false);
-    GenerateFunOneLine(writer, name + "BufferHasIdentifier", "_bb: ByteBuffer",
-                       "Boolean", [&]() {
-                         writer += "__has_identifier(_bb, \"" +
-                                   file_identifier + "\")";
-                       }, options.gen_jvmstatic);
+    GenerateFunOneLine(
+        writer, name + "BufferHasIdentifier", "_bb: ByteBuffer", "Boolean",
+        [&]() {
+          writer += "__has_identifier(_bb, \"" + file_identifier + "\")";
+        },
+        options.gen_jvmstatic);
   }
 
   void GenerateStructGetters(StructDef &struct_def, CodeWriter &writer) const {
@@ -996,12 +1022,11 @@ class KotlinGenerator : public BaseGenerator {
             break;
           }
           case BASE_TYPE_UNION:
-            GenerateFun(writer, field_name, "obj: " + field_type, return_type,
-                        [&]() {
-                          writer += OffsetWrapperOneLine(
-                              offset_val, bbgetter + "(obj, o + bb_pos)",
-                              "null");
-                        });
+            GenerateFun(
+                writer, field_name, "obj: " + field_type, return_type, [&]() {
+                  writer += OffsetWrapperOneLine(
+                      offset_val, bbgetter + "(obj, o + bb_pos)", "null");
+                });
             break;
           default: FLATBUFFERS_ASSERT(0);
         }
@@ -1293,10 +1318,13 @@ class KotlinGenerator : public BaseGenerator {
                                         const IDLOptions options) {
     // create a struct constructor function
     auto params = StructConstructorParams(struct_def);
-    GenerateFun(code, "create" + Esc(struct_def.name), params, "Int", [&]() {
-      GenStructBody(struct_def, code, "");
-      code += "return builder.offset()";
-    }, options.gen_jvmstatic);
+    GenerateFun(
+        code, "create" + Esc(struct_def.name), params, "Int",
+        [&]() {
+          GenStructBody(struct_def, code, "");
+          code += "return builder.offset()";
+        },
+        options.gen_jvmstatic);
   }
 
   static std::string StructConstructorParams(const StructDef &struct_def,
@@ -1482,9 +1510,7 @@ class KotlinGenerator : public BaseGenerator {
   // Prepend @JvmStatic to methods in companion object.
   static void GenerateJvmStaticAnnotation(CodeWriter &code,
                                           bool gen_jvmstatic) {
-    if (gen_jvmstatic) {
-      code += "@JvmStatic";
-    }
+    if (gen_jvmstatic) { code += "@JvmStatic"; }
   }
 
   // This tracks the current namespace used to determine if a type need to be
index 1e7502ae03aff57e106c1f667b135e2e22b3240f..16c8dfa1e48fcbdf3ec0d87e554d6e76e31a05ab 100644 (file)
@@ -47,9 +47,7 @@ std::string MakeSnakeCase(const std::string &in) {
 // Convert a string to all uppercase.
 std::string MakeUpper(const std::string &in) {
   std::string s;
-  for (size_t i = 0; i < in.length(); i++) {
-    s += CharToUpper(in[i]);
-  }
+  for (size_t i = 0; i < in.length(); i++) { s += CharToUpper(in[i]); }
   return s;
 }
 
@@ -668,8 +666,8 @@ class RustGenerator : public BaseGenerator {
         return field.optional ? "None" : field.value.constant;
       }
       case ftBool: {
-        return field.optional ? "None" :
-          field.value.constant == "0" ? "false" : "true";
+        return field.optional ? "None"
+                              : field.value.constant == "0" ? "false" : "true";
       }
       case ftUnionKey:
       case ftEnumKey: {
@@ -868,9 +866,9 @@ class RustGenerator : public BaseGenerator {
       case ftBool:
       case ftFloat: {
         const auto typname = GetTypeBasic(field.value.type);
-        return (field.optional ?
-                   "self.fbb_.push_slot_always::<" :
-                   "self.fbb_.push_slot::<") + typname + ">";
+        return (field.optional ? "self.fbb_.push_slot_always::<"
+                               : "self.fbb_.push_slot::<") +
+               typname + ">";
       }
       case ftEnumKey:
       case ftUnionKey: {
@@ -1005,7 +1003,7 @@ class RustGenerator : public BaseGenerator {
           const auto default_value = GetDefaultScalarValue(field);
           return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" +
                  default_value + ")).unwrap()";
-       }
+        }
       }
       case ftStruct: {
         const auto typname = WrapInNameSpace(*type.struct_def);
index 566482d2107d2edba6b1050eac34ad20161f1e10..d2c729a740d6afc26e090d5e7adbda083c12ad3b 100644 (file)
@@ -757,7 +757,8 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
             type.enum_def->name + "'.");
       }
       if (field->attributes.Lookup("key")) {
-        return Error("only a non-optional scalar field can be used as a 'key' field");
+        return Error(
+            "only a non-optional scalar field can be used as a 'key' field");
       }
       if (!SupportsOptionalScalars()) {
         return Error(
@@ -862,7 +863,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
   if (field->required && (struct_def.fixed || IsScalar(type.base_type)))
     return Error("only non-scalar fields in tables may be 'required'");
 
-  if(!IsScalar(type.base_type)) {
+  if (!IsScalar(type.base_type)) {
     // For nonscalars, only required fields are non-optional.
     // At least until https://github.com/google/flatbuffers/issues/6053
     field->optional = !field->required;
@@ -1230,7 +1231,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
       if (!struct_def.sortbysize ||
           size == SizeOf(field_value.type.base_type)) {
         switch (field_value.type.base_type) {
-          // clang-format off
+// clang-format off
           #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
             case BASE_TYPE_ ## ENUM: \
               builder_.Pad(field->padding); \
@@ -1369,7 +1370,7 @@ CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue,
     // start at the back, since we're building the data backwards.
     auto &val = field_stack_.back().first;
     switch (val.type.base_type) {
-      // clang-format off
+// clang-format off
       #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE,...) \
         case BASE_TYPE_ ## ENUM: \
           if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
@@ -2279,7 +2280,7 @@ CheckedError Parser::CheckClash(std::vector<FieldDef *> &fields,
   return NoError();
 }
 
-bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions &opts){
+bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions &opts) {
   static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
       IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster |
       IDLOptions::kKotlin | IDLOptions::kCpp;
index cb941a029fbfe5ee5408b4070300016dce75bb2b..2dedcb4f18d3aa8fb40b349a928780a0dc505960 100644 (file)
@@ -23,7 +23,7 @@
 namespace flatbuffers {
 
 int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
-  // clang-format off
+// clang-format off
   #define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data))
   switch (type) {
     case reflection::UType:
@@ -121,7 +121,7 @@ std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
 }
 
 void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) {
-  // clang-format off
+// clang-format off
   #define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val))
   switch (type) {
     case reflection::UType:
index 43b81574add4b1c056003b278551ccfb188f44e0..f3c4b6755a983dabb673996a976086bc9414ea8c 100644 (file)
@@ -49,8 +49,10 @@ public protocol GreeterProvider: CallHandlerProvider {
 }
 
 public extension GreeterProvider {
-       var serviceName: String { return "Greeter" }
-       func handleMethod(_ methodName: String, callHandlerContext: CallHandlerContext) -> GRPCCallHandler? {
+
+       var serviceName: Substring { return "Greeter" }
+
+       func handleMethod(_ methodName: Substring, callHandlerContext: CallHandlerContext) -> GRPCCallHandler? {
                switch methodName {
                case "SayHello":
                return CallHandlerFactory.makeUnary(callHandlerContext: callHandlerContext) { context in
index 45915dd911a1e50b0d3fd13a154afb3e5d46d2ab..74729e7e3f0e8df405f11dfd8944d92d056ea9ee 100644 (file)
@@ -36,6 +36,7 @@ func greet(name: String, client greeter: GreeterServiceClient) {
     
     // Make the RPC call to the server.
     let sayHello = greeter.SayHello(Message<HelloRequest>(builder: &builder))
+
     // wait() on the response to stop the program from exiting before the response is received.
     do {
         let response = try sayHello.response.wait()
@@ -43,15 +44,15 @@ func greet(name: String, client greeter: GreeterServiceClient) {
     } 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)")
@@ -83,10 +84,15 @@ func main(args: [String]) {
         // Configure the channel, we're not using TLS so the connection is `insecure`.
         let channel = ClientConnection.insecure(group: group)
           .connect(host: "localhost", port: port)
-        
+
+        // Close the connection when we're done with it.
+        defer {
+          try! channel.close().wait()
+        }
+
         // Provide the connection to the generated client.
         let greeter = GreeterServiceClient(channel: channel)
-        
+
         // Do the greeting.
         greet(name: name ?? "Hello FlatBuffers!", client: greeter)
     }
index b361b256b811cce2849bc6183dae96e6037ba658..396c151e9b7cc806354fef0ef75faf23ab6b3f7c 100644 (file)
@@ -40,7 +40,7 @@ class Greeter: GreeterProvider {
         context: StatusOnlyCallContext
     ) -> EventLoopFuture<Message<HelloReply>> {
         let recipient = request.object.name ?? "Stranger"
-        
+
         var builder = FlatBufferBuilder()
         let off = builder.create(string: recipient)
         let root = HelloReply.createHelloReply(&builder, offsetOfMessage: off)
index 66bac373f69b6dbaccf048f2f680b2ee5177e6d3..b2f3ff27c23065959708a4de9a6d313e24b4674b 100644 (file)
@@ -61,8 +61,10 @@ public protocol MyGame_Example_MonsterStorageProvider: CallHandlerProvider {
 }
 
 public extension MyGame_Example_MonsterStorageProvider {
-       var serviceName: String { return "MyGame.Example.MonsterStorage" }
-       func handleMethod(_ methodName: String, callHandlerContext: CallHandlerContext) -> GRPCCallHandler? {
+
+       var serviceName: Substring { return "MyGame.Example.MonsterStorage" }
+
+       func handleMethod(_ methodName: Substring, callHandlerContext: CallHandlerContext) -> GRPCCallHandler? {
                switch methodName {
                case "Store":
                return CallHandlerFactory.makeUnary(callHandlerContext: callHandlerContext) { context in
index 9ba7254150d6019401c287b54859545e6a66d2e4..bc4b084b8560e45ee74204c6f0449da8fac9f20a 100644 (file)
@@ -210,6 +210,14 @@ static createInParentNamespace(builder:flatbuffers.Builder):flatbuffers.Offset {
   return InParentNamespace.endInParentNamespace(builder);
 }
 
+serialize():Uint8Array {
+  return this.bb!.bytes();
+}
+
+static deserialize(buffer: Uint8Array):InParentNamespace {
+  return InParentNamespace.getRootAsInParentNamespace(new flatbuffers.ByteBuffer(buffer))
+}
+
 /**
  * @returns InParentNamespaceT
  */
@@ -297,6 +305,14 @@ static createMonster(builder:flatbuffers.Builder):flatbuffers.Offset {
   return Monster.endMonster(builder);
 }
 
+serialize():Uint8Array {
+  return this.bb!.bytes();
+}
+
+static deserialize(buffer: Uint8Array):Monster {
+  return Monster.getRootAsMonster(new flatbuffers.ByteBuffer(buffer))
+}
+
 /**
  * @returns MonsterT
  */
@@ -531,6 +547,14 @@ static createTestSimpleTableWithEnum(builder:flatbuffers.Builder, color:MyGame.E
   return TestSimpleTableWithEnum.endTestSimpleTableWithEnum(builder);
 }
 
+serialize():Uint8Array {
+  return this.bb!.bytes();
+}
+
+static deserialize(buffer: Uint8Array):TestSimpleTableWithEnum {
+  return TestSimpleTableWithEnum.getRootAsTestSimpleTableWithEnum(new flatbuffers.ByteBuffer(buffer))
+}
+
 /**
  * @returns TestSimpleTableWithEnumT
  */
@@ -1031,6 +1055,14 @@ static createStat(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset, val:
   return Stat.endStat(builder);
 }
 
+serialize():Uint8Array {
+  return this.bb!.bytes();
+}
+
+static deserialize(buffer: Uint8Array):Stat {
+  return Stat.getRootAsStat(new flatbuffers.ByteBuffer(buffer))
+}
+
 /**
  * @returns StatT
  */
@@ -1171,6 +1203,14 @@ static createReferrable(builder:flatbuffers.Builder, id:flatbuffers.Long):flatbu
   return Referrable.endReferrable(builder);
 }
 
+serialize():Uint8Array {
+  return this.bb!.bytes();
+}
+
+static deserialize(buffer: Uint8Array):Referrable {
+  return Referrable.getRootAsReferrable(new flatbuffers.ByteBuffer(buffer))
+}
+
 /**
  * @returns ReferrableT
  */
@@ -2922,6 +2962,14 @@ static finishSizePrefixedMonsterBuffer(builder:flatbuffers.Builder, offset:flatb
 };
 
 
+serialize():Uint8Array {
+  return this.bb!.bytes();
+}
+
+static deserialize(buffer: Uint8Array):Monster {
+  return Monster.getRootAsMonster(new flatbuffers.ByteBuffer(buffer))
+}
+
 /**
  * @returns MonsterT
  */
@@ -3741,6 +3789,14 @@ static createTypeAliases(builder:flatbuffers.Builder, i8:number, u8:number, i16:
   return TypeAliases.endTypeAliases(builder);
 }
 
+serialize():Uint8Array {
+  return this.bb!.bytes();
+}
+
+static deserialize(buffer: Uint8Array):TypeAliases {
+  return TypeAliases.getRootAsTypeAliases(new flatbuffers.ByteBuffer(buffer))
+}
+
 /**
  * @returns TypeAliasesT
  */
diff --git a/tests/monster_test_grpc.d.ts b/tests/monster_test_grpc.d.ts
new file mode 100644 (file)
index 0000000..128c602
--- /dev/null
@@ -0,0 +1,92 @@
+// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT ***
+import { flatbuffers } from 'flatbuffers';
+import *  as MonsterStorage_fbs from './monster_test_generated';
+
+import * as grpc from 'grpc';
+
+interface IMonsterStorageService extends grpc.ServiceDefinition<grpc.UntypedServiceImplementation> {
+  Store: IMonsterStorageService_IStore;
+  Retrieve: IMonsterStorageService_IRetrieve;
+  GetMaxHitPoint: IMonsterStorageService_IGetMaxHitPoint;
+  GetMinMaxHitPoints: IMonsterStorageService_IGetMinMaxHitPoints;
+}
+interface IMonsterStorageService_IStore extends grpc.MethodDefinition<MonsterStorage_fbs.Monster, MonsterStorage_fbs.Stat> {
+  path: string; // /MyGame.Example.MonsterStorage/Store
+  requestStream: boolean; // false
+  responseStream: boolean; // false
+  requestSerialize: grpc.serialize<MonsterStorage_fbs.Monster>;
+  requestDeserialize: grpc.deserialize<MonsterStorage_fbs.Monster>;
+  responseSerialize: grpc.serialize<MonsterStorage_fbs.Stat>;
+  responseDeserialize: grpc.deserialize<MonsterStorage_fbs.Stat>;
+}
+
+interface IMonsterStorageService_IRetrieve extends grpc.MethodDefinition<MonsterStorage_fbs.Stat, MonsterStorage_fbs.Monster> {
+  path: string; // /MyGame.Example.MonsterStorage/Retrieve
+  requestStream: boolean; // false
+  responseStream: boolean; // true
+  requestSerialize: grpc.serialize<MonsterStorage_fbs.Stat>;
+  requestDeserialize: grpc.deserialize<MonsterStorage_fbs.Stat>;
+  responseSerialize: grpc.serialize<MonsterStorage_fbs.Monster>;
+  responseDeserialize: grpc.deserialize<MonsterStorage_fbs.Monster>;
+}
+
+interface IMonsterStorageService_IGetMaxHitPoint extends grpc.MethodDefinition<MonsterStorage_fbs.Monster, MonsterStorage_fbs.Stat> {
+  path: string; // /MyGame.Example.MonsterStorage/GetMaxHitPoint
+  requestStream: boolean; // true
+  responseStream: boolean; // false
+  requestSerialize: grpc.serialize<MonsterStorage_fbs.Monster>;
+  requestDeserialize: grpc.deserialize<MonsterStorage_fbs.Monster>;
+  responseSerialize: grpc.serialize<MonsterStorage_fbs.Stat>;
+  responseDeserialize: grpc.deserialize<MonsterStorage_fbs.Stat>;
+}
+
+interface IMonsterStorageService_IGetMinMaxHitPoints extends grpc.MethodDefinition<MonsterStorage_fbs.Monster, MonsterStorage_fbs.Stat> {
+  path: string; // /MyGame.Example.MonsterStorage/GetMinMaxHitPoints
+  requestStream: boolean; // true
+  responseStream: boolean; // true
+  requestSerialize: grpc.serialize<MonsterStorage_fbs.Monster>;
+  requestDeserialize: grpc.deserialize<MonsterStorage_fbs.Monster>;
+  responseSerialize: grpc.serialize<MonsterStorage_fbs.Stat>;
+  responseDeserialize: grpc.deserialize<MonsterStorage_fbs.Stat>;
+}
+
+
+export const MonsterStorageService: IMonsterStorageService;
+
+export interface IMonsterStorageServer {
+  Store: grpc.handleUnaryCall<MonsterStorage_fbs.Monster, MonsterStorage_fbs.Stat>;
+  Retrieve: grpc.handleServerStreamingCall<MonsterStorage_fbs.Stat, MonsterStorage_fbs.Monster>;
+  GetMaxHitPoint: grpc.handleClientStreamingCall<MonsterStorage_fbs.Monster, MonsterStorage_fbs.Stat>;
+  GetMinMaxHitPoints: grpc.handleBidiStreamingCall<MonsterStorage_fbs.Monster, MonsterStorage_fbs.Stat>;
+}
+
+export interface IMonsterStorageClient {
+  Store(request: MonsterStorage_fbs.Monster, callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Stat) => void): grpc.ClientUnaryCall;
+  Store(request: MonsterStorage_fbs.Monster, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Stat) => void): grpc.ClientUnaryCall;
+  Store(request: MonsterStorage_fbs.Monster, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Stat) => void): grpc.ClientUnaryCall;
+  Retrieve(request: MonsterStorage_fbs.Stat, metadata: grpc.Metadata): grpc.ClientReadableStream<MonsterStorage_fbs.Monster>;
+  Retrieve(request: MonsterStorage_fbs.Stat, options: Partial<grpc.CallOptions>): grpc.ClientReadableStream<MonsterStorage_fbs.Monster>;
+  GetMaxHitPoint(callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Monster) => void): grpc.ClientWritableStream<MonsterStorage_fbs.Stat>;
+  GetMaxHitPoint(metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Monster) => void): grpc.ClientWritableStream<MonsterStorage_fbs.Stat>;
+  GetMaxHitPoint(options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Monster) => void): grpc.ClientWritableStream<MonsterStorage_fbs.Stat>;
+  GetMaxHitPoint(metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Monster) => void): grpc.ClientWritableStream<MonsterStorage_fbs.Stat>;
+  GetMinMaxHitPoints(): grpc.ClientDuplexStream<MonsterStorage_fbs.Monster, MonsterStorage_fbs.Stat>;
+  GetMinMaxHitPoints(options: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<MonsterStorage_fbs.Monster, MonsterStorage_fbs.Stat>;
+  GetMinMaxHitPoints(metadata: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<MonsterStorage_fbs.Monster, MonsterStorage_fbs.Stat>;
+}
+
+export class MonsterStorageClient extends grpc.Client implements IMonsterStorageClient {
+  constructor(address: string, credentials: grpc.ChannelCredentials, options?: object);  public Store(request: MonsterStorage_fbs.Monster, callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Stat) => void): grpc.ClientUnaryCall;
+  public Store(request: MonsterStorage_fbs.Monster, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Stat) => void): grpc.ClientUnaryCall;
+  public Store(request: MonsterStorage_fbs.Monster, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Stat) => void): grpc.ClientUnaryCall;
+  public Retrieve(request: MonsterStorage_fbs.Stat, metadata: grpc.Metadata): grpc.ClientReadableStream<MonsterStorage_fbs.Monster>;
+  public Retrieve(request: MonsterStorage_fbs.Stat, options: Partial<grpc.CallOptions>): grpc.ClientReadableStream<MonsterStorage_fbs.Monster>;
+  public GetMaxHitPoint(callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Monster) => void): grpc.ClientWritableStream<MonsterStorage_fbs.Stat>;
+  public GetMaxHitPoint(metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Monster) => void): grpc.ClientWritableStream<MonsterStorage_fbs.Stat>;
+  public GetMaxHitPoint(options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Monster) => void): grpc.ClientWritableStream<MonsterStorage_fbs.Stat>;
+  public GetMaxHitPoint(metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: MonsterStorage_fbs.Monster) => void): grpc.ClientWritableStream<MonsterStorage_fbs.Stat>;
+  public GetMinMaxHitPoints(): grpc.ClientDuplexStream<MonsterStorage_fbs.Monster, MonsterStorage_fbs.Stat>;
+  public GetMinMaxHitPoints(options: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<MonsterStorage_fbs.Monster, MonsterStorage_fbs.Stat>;
+  public GetMinMaxHitPoints(metadata: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<MonsterStorage_fbs.Monster, MonsterStorage_fbs.Stat>;
+}
+
diff --git a/tests/monster_test_grpc.js b/tests/monster_test_grpc.js
new file mode 100644 (file)
index 0000000..c12d789
--- /dev/null
@@ -0,0 +1,79 @@
+// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT ***
+import { flatbuffers } from 'flatbuffers';
+import *  as MonsterStorage_fbs from './monster_test_generated';
+
+var grpc = require('grpc');
+
+function serialize_Stat(buffer_args) {
+  if (!(buffer_args instanceof MonsterStorage_fbs.Stat)) {
+    throw new Error('Expected argument of type MonsterStorage_fbs.Stat');
+  }
+  return buffer_args.serialize();
+}
+
+function deserialize_Stat(buffer) {
+  return MonsterStorage_fbs.Stat.getRootAsStat(new flatbuffers.ByteBuffer(buffer))
+}
+
+
+function serialize_Monster(buffer_args) {
+  if (!(buffer_args instanceof MonsterStorage_fbs.Monster)) {
+    throw new Error('Expected argument of type MonsterStorage_fbs.Monster');
+  }
+  return buffer_args.serialize();
+}
+
+function deserialize_Monster(buffer) {
+  return MonsterStorage_fbs.Monster.getRootAsMonster(new flatbuffers.ByteBuffer(buffer))
+}
+
+
+
+
+var MonsterStorageService = exports.MonsterStorageService = {
+  Store: {
+    path: '/MyGame.Example.MonsterStorage/Store',
+    requestStream: false,
+    responseStream: false,
+    requestType: flatbuffers.ByteBuffer,
+    responseType: MonsterStorage_fbs.Stat,
+    requestSerialize: serialize_Monster,
+    requestDeserialize: deserialize_Monster,
+    responseSerialize: serialize_Stat,
+    responseDeserialize: deserialize_Stat,
+  },
+  Retrieve: {
+    path: '/MyGame.Example.MonsterStorage/Retrieve',
+    requestStream: false,
+    responseStream: true,
+    requestType: flatbuffers.ByteBuffer,
+    responseType: MonsterStorage_fbs.Monster,
+    requestSerialize: serialize_Stat,
+    requestDeserialize: deserialize_Stat,
+    responseSerialize: serialize_Monster,
+    responseDeserialize: deserialize_Monster,
+  },
+  GetMaxHitPoint: {
+    path: '/MyGame.Example.MonsterStorage/GetMaxHitPoint',
+    requestStream: true,
+    responseStream: false,
+    requestType: flatbuffers.ByteBuffer,
+    responseType: MonsterStorage_fbs.Stat,
+    requestSerialize: serialize_Monster,
+    requestDeserialize: deserialize_Monster,
+    responseSerialize: serialize_Stat,
+    responseDeserialize: deserialize_Stat,
+  },
+  GetMinMaxHitPoints: {
+    path: '/MyGame.Example.MonsterStorage/GetMinMaxHitPoints',
+    requestStream: true,
+    responseStream: true,
+    requestType: flatbuffers.ByteBuffer,
+    responseType: MonsterStorage_fbs.Stat,
+    requestSerialize: serialize_Monster,
+    requestDeserialize: deserialize_Monster,
+    responseSerialize: serialize_Stat,
+    responseDeserialize: deserialize_Stat,
+  },
+};
+exports.MonsterStorageClient = grpc.makeGenericClientConstructor(MonsterStorageService);