This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git


The following commit(s) were added to refs/heads/main by this push:
     new ff66e29d3 docs(compiler): documented grpc service stubs (#3818)
ff66e29d3 is described below

commit ff66e29d356bbb174f73abb99fb887ba507b0cdc
Author: Ayush Kumar <[email protected]>
AuthorDate: Sun Jul 5 08:41:47 2026 +0530

    docs(compiler): documented grpc service stubs (#3818)
    
    ## Why?
    
    
    
    ## What does this PR do?
    
    
    
    ## Related issues
    
    
    
    ## AI Contribution Checklist
    
    
    
    - [ ] Substantial AI assistance was used in this PR: `yes` / `no`
    - [ ] If `yes`, I included a completed [AI Contribution
    
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
    in this PR description and the required `AI Usage Disclosure`.
    - [ ] If `yes`, my PR description includes the required `ai_review`
    summary and screenshot evidence or equivalent persisted links of the
    final clean AI review results from both fresh reviewers described in
    `AI_POLICY.md`, the Fory-guided reviewer and the independent general
    reviewer, on the current PR diff or current HEAD after the latest code
    changes.
    
    
    
    ## Does this PR introduce any user-facing change?
    
    
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
---
 compiler/README.md | 313 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 303 insertions(+), 10 deletions(-)

diff --git a/compiler/README.md b/compiler/README.md
index 99c690b0c..2896165c0 100644
--- a/compiler/README.md
+++ b/compiler/README.md
@@ -10,6 +10,7 @@ The FDL compiler generates cross-language serialization code 
from schema definit
 - **Type ID and namespace support**: Both numeric IDs and name-based type 
registration
 - **Field modifiers**: Optional fields, reference tracking, list fields, 
scalar encoding modifiers
 - **File imports**: Modular schemas with import support
+- **gRPC service generation**: Native gRPC stubs and service bases for Java, 
Python, Go, Rust, C#, JavaScript, Dart, Kotlin, and Scala
 
 ## Documentation
 
@@ -71,6 +72,9 @@ foryc schema.fdl --java_out=./src/main/java 
--python_out=./python/src --csharp_o
 
 # Combine with other options
 foryc schema.fdl --java_out=./gen --go_out=./gen/go --csharp_out=./gen/csharp 
--javascript_out=./gen/js --scala_out=./gen/scala -I ./proto
+
+# Also generate gRPC service stubs
+foryc schema.fdl --lang java,python,go --grpc --output ./generated
 ```
 
 ### 3. Use Generated Code
@@ -226,6 +230,38 @@ message Example {
 }
 ```
 
+### Service Definition
+
+Define gRPC services alongside message types in the same FDL file:
+
+```fdl
+package demo.greeter;
+
+message HelloRequest {
+    string name = 1;
+}
+
+message HelloReply {
+    string reply = 1;
+}
+
+service Greeter {
+    rpc SayHello (HelloRequest) returns (HelloReply);
+    rpc StreamReplies (HelloRequest) returns (stream HelloReply);
+    rpc CollectRequests (stream HelloRequest) returns (HelloReply);
+    rpc Chat (stream HelloRequest) returns (stream HelloReply);
+}
+```
+
+Each `rpc` declaration supports four streaming modes:
+
+| Mode             | Syntax                                         |
+| ---------------- | ---------------------------------------------- |
+| Unary            | `rpc Method (Req) returns (Res)`               |
+| Server streaming | `rpc Method (Req) returns (stream Res)`        |
+| Client streaming | `rpc Method (stream Req) returns (Res)`        |
+| Bidirectional    | `rpc Method (stream Req) returns (stream Res)` |
+
 ### Fory Options
 
 FDL uses plain option keys without a `(fory)` prefix:
@@ -281,18 +317,29 @@ fory_compiler/
 │       └── parser.py     # Recursive descent parser
 ├── ir/
 │   ├── __init__.py
-│   ├── ast.py            # Canonical Fory IDL AST
+│   ├── ast.py            # Canonical Fory IDL AST (Schema, Message, Enum, 
Service, RpcMethod)
 │   ├── validator.py      # Schema validation
 │   └── emitter.py        # Optional FDL emitter
 └── generators/
-    ├── base.py           # Base generator class
+    ├── base.py           # Base generator class and GeneratorOptions
     ├── java.py           # Java POJO generator
     ├── python.py         # Python dataclass generator
     ├── go.py             # Go struct generator
     ├── rust.py           # Rust struct generator
     ├── cpp.py            # C++ struct generator
     ├── csharp.py         # C# class generator
-    └── javascript.py     # JavaScript interface generator
+    ├── javascript.py     # JavaScript interface generator
+    └── services/
+        ├── base.py       # StreamingMode enum and shared helpers
+        ├── java.py       # Java gRPC stub generator (grpc-java style)
+        ├── python.py     # Python gRPC companion module (grpcio style)
+        ├── go.py         # Go gRPC stub generator (google.golang.org/grpc)
+        ├── rust.py       # Rust gRPC service module (tonic style)
+        ├── csharp.py     # C# gRPC service companion (Grpc.Core style)
+        ├── javascript.py # JavaScript Node.js and gRPC-Web client generators
+        ├── dart.py       # Dart gRPC service companion
+        ├── kotlin.py     # Kotlin coroutine gRPC service companion
+        └── scala.py      # Scala gRPC service companion
 ```
 
 ### FDL Frontend
@@ -307,10 +354,14 @@ The FDL frontend is a hand-written lexer/parser that 
produces the Fory IDL AST:
 
 Each generator extends `BaseGenerator` and implements:
 
-- `generate()`: Returns list of `GeneratedFile` objects
+- `generate()`: Returns list of `GeneratedFile` objects for type definitions
 - `generate_type()`: Converts FDL types to target language types
+- `generate_services()`: Returns gRPC service companion files when `--grpc` is 
set
 - Language-specific registration helpers or modules
 
+Service generators live in `generators/services/` as mixins and are combined 
with the
+corresponding type generator via multiple inheritance in each language 
generator class.
+
 ## Generated Output
 
 ### Java
@@ -448,20 +499,262 @@ export interface Cat {
 }
 ```
 
+## gRPC Service Generation
+
+Pass `--grpc` to generate gRPC service stubs alongside type definitions for 
all selected
+languages that support service generation (Java, Python, Go, Rust, C#, 
JavaScript, Dart,
+Kotlin, and Scala). Stubs use Fory serialization as the on-wire codec.
+
+```bash
+# Generate type definitions and gRPC stubs
+foryc examples/service.fdl --lang java,python,go --grpc --output ./generated
+
+# JavaScript gRPC-Web client (requires --grpc-web, implies JavaScript output)
+foryc examples/service.fdl --javascript_out=./gen/js --grpc-web
+
+# Python async mode (default) or sync mode
+foryc examples/service.fdl --python_out=./gen/python --grpc --grpc-python-mode 
sync
+```
+
+### Generated gRPC Output
+
+For each language the compiler emits one gRPC companion file per schema file.
+The following examples use the schema from `examples/service.fdl`:
+
+```fdl
+package demo.greeter;
+
+message HelloRequest { string name = 1; }
+message HelloReply   { string reply = 1; }
+
+service Greeter {
+    rpc SayHello (HelloRequest) returns (HelloReply);
+}
+```
+
+#### Java
+
+Generates `<ServiceName>Grpc.java` with a grpc-java-style companion class:
+
+- Method descriptors with double-checked-locking initialization
+- `<ServiceName>ImplBase` abstract server base
+- `<ServiceName>Stub` (async), `<ServiceName>BlockingStub`, and 
`<ServiceName>FutureStub` client stubs
+- Factory methods `newStub`, `newBlockingStub`, and `newFutureStub`
+- Fory-backed marshaller shared by all methods in the class
+
+```java
+// GreeterGrpc.java (demo/greeter/GreeterGrpc.java)
+public final class GreeterGrpc {
+    public static final String SERVICE_NAME = "demo.greeter.Greeter";
+
+    public abstract static class GreeterImplBase implements 
io.grpc.BindableService {
+        public void sayHello(HelloRequest request,
+                io.grpc.stub.StreamObserver<HelloReply> responseObserver) {
+            io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(
+                getSayHelloMethod(), responseObserver);
+        }
+        @Override
+        public final io.grpc.ServerServiceDefinition bindService() {
+            return GreeterGrpc.bindService(this);
+        }
+    }
+
+    public static final class GreeterStub
+            extends io.grpc.stub.AbstractAsyncStub<GreeterStub> { ... }
+    public static final class GreeterBlockingStub
+            extends io.grpc.stub.AbstractBlockingStub<GreeterBlockingStub> { 
... }
+    public static final class GreeterFutureStub
+            extends io.grpc.stub.AbstractFutureStub<GreeterFutureStub> { ... }
+}
+```
+
+#### Python
+
+Generates `<module>_grpc.py` with a grpcio-style companion module. The default 
API
+mode is async (`grpc.aio`); pass `--grpc-python-mode sync` for the classic 
sync API:
+
+- `<ServiceName>Stub` client class wired to the Fory serializer/deserializer 
pair
+- `<ServiceName>Servicer` server base with `UNIMPLEMENTED` stubs
+- Per-service registration helper and a top-level `add_servicer(servicer, 
server)` dispatcher
+
+```python
+# demo_greeter_grpc.py
+class GreeterStub(object):
+    """Client stub for Greeter."""
+    def __init__(self, channel):
+        self.say_hello = channel.unary_unary(
+            "/demo.greeter.Greeter/SayHello",
+            request_serializer=_serialize,
+            response_deserializer=_deserialize,
+        )
+
+class GreeterServicer(object):
+    """AsyncIO base servicer for Greeter."""
+    async def say_hello(self, request, context):
+        await context.abort(grpc.StatusCode.UNIMPLEMENTED, "Method not 
implemented!")
+
+def add_servicer(servicer, server): ...
+```
+
+#### Go
+
+Generates `<file>_grpc.go` with a google.golang.org/grpc-compatible stub file:
+
+- `CodecV2` implementing `grpc/encoding.CodecV2` using the Fory thread-safe 
runtime
+- `<ServiceName>Client` interface and `New<ServiceName>Client` constructor
+- `<ServiceName>Server` interface and `Unimplemented<ServiceName>Server` struct
+- Per-streaming-mode send/receive stream types
+- `Register<ServiceName>Server` and a `ServiceDesc` variable
+
+```go
+// greeter_grpc.go
+type GreeterClient interface {
+    SayHello(ctx context.Context, in *HelloRequest,
+        opts ...grpc.CallOption) (*HelloReply, error)
+}
+
+func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient { ... }
+
+type GreeterServer interface {
+    SayHello(context.Context, *HelloRequest) (*HelloReply, error)
+    mustEmbedUnimplementedGreeterServer()
+}
+
+func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) { ... }
+```
+
+#### Rust
+
+Generates two files: `<module>_api.rs` (service trait definitions) and
+`<module>_grpc.rs` (tonic-compatible client/server modules):
+
+- A service trait per service name
+- `<service_name>_client` and `<service_name>_server` submodules compatible 
with tonic
+- Fory codec registered via the `<SERVICE>_SERVICE_NAME` constant
+
+```rust
+// greeter_grpc.rs
+pub mod greeter_client {
+    pub struct GreeterClient<T> { inner: tonic::client::Grpc<T> }
+    impl<T> GreeterClient<T> {
+        pub async fn say_hello(&mut self, request: impl 
tonic::IntoRequest<HelloRequest>)
+            -> std::result::Result<tonic::Response<HelloReply>, tonic::Status> 
{ ... }
+    }
+}
+
+pub mod greeter_server {
+    pub trait Greeter: std::marker::Send + std::marker::Sync + 'static {
+        async fn say_hello(&self, request: tonic::Request<HelloRequest>)
+            -> std::result::Result<tonic::Response<HelloReply>, tonic::Status>;
+    }
+}
+```
+
+#### C\#
+
+Generates `<ServiceName>Grpc.cs` with a Grpc.Core-style partial class:
+
+- Static Fory marshallers for each distinct request/response type pair
+- `Method<TReq, TRes>` descriptors for each RPC
+- `<ServiceName>Base` abstract server base class
+- `<ServiceName>Client` client class
+- `BindService` helper for server-side registration
+
+```csharp
+// GreeterGrpc.cs
+public static partial class Greeter
+{
+    static readonly string __ServiceName = "demo.greeter.Greeter";
+
+    public abstract class GreeterBase
+    {
+        public virtual Task<HelloReply> SayHello(
+            HelloRequest request, grpc::ServerCallContext context)
+            => throw new grpc::RpcException(new grpc::Status(
+                grpc::StatusCode.Unimplemented, ""));
+    }
+
+    public class GreeterClient : grpc::ClientBase<GreeterClient>
+    {
+        public virtual HelloReply SayHello(
+            HelloRequest request, grpc::CallOptions options = default) { ... }
+    }
+}
+```
+
+#### JavaScript
+
+Generates `<module>_grpc.js` (Node.js, `--grpc`) and/or `<module>_grpc_web.js`
+(browser, `--grpc-web`) TypeScript/JavaScript companion modules:
+
+- `<ServiceName>Client` class extending `grpc.Client` (Node) or a gRPC-Web 
base (browser)
+- Per-method call wrappers using the Fory serializer/deserializer pair
+- A `<ServiceName>Service` descriptor object for server-side registration 
(Node)
+
+```typescript
+// greeter_grpc.js (Node)
+export class GreeterClient extends grpc.Client {
+  sayHello(argument, metadata, options, callback) { ... }
+}
+export const GreeterService = {
+  sayHello: { path: "/demo.greeter.Greeter/SayHello", ... },
+};
+```
+
+#### Dart
+
+Generates `<file>_grpc.dart` with a dart-grpc-compatible companion:
+
+- `<ServiceName>Client` class extending `grpc.Client`
+- `<ServiceName>ServiceBase` abstract server base class
+- Fory codec passed as the `serialize`/`deserialize` pair on each 
`ClientMethod`
+
+#### Kotlin
+
+Generates `<ServiceName>GrpcKt.kt` with grpc-kotlin coroutine companions:
+
+- `<ServiceName>CoroutineImplBase` abstract server base using suspend functions
+- `<ServiceName>CoroutineStub` coroutine client stub
+- Fory serialization used as the gRPC marshaller
+
+#### Scala
+
+Generates `<ServiceName>GrpcScala.scala` with ZIO/Monix-friendly stubs:
+
+- `<ServiceName>Grpc` object with a `bindService` method for server 
registration
+- `<ServiceName>Stub` client class
+- Fory codec registered as the channel marshaller
+
 ## CLI Reference
 
 ```
 foryc [OPTIONS] FILES...
 
 Arguments:
-  FILES                 FDL files to compile
+  FILES                     FDL files to compile
 
 Options:
-  --lang TEXT          Target languages 
(java,python,cpp,rust,go,csharp,javascript,swift,dart,scala or "all")
-                       Default: all
-  --output, -o PATH    Output directory
-                       Default: ./generated
-  --help               Show help message
+  --lang TEXT               Target languages (java,python,cpp,rust,go,csharp,
+                            javascript,swift,dart,scala,kotlin or "all")
+                            Default: all
+  --output, -o PATH         Output directory
+                            Default: ./generated
+  --java_out DST_DIR        Generate Java code in DST_DIR
+  --python_out DST_DIR      Generate Python code in DST_DIR
+  --go_out DST_DIR          Generate Go code in DST_DIR
+  --rust_out DST_DIR        Generate Rust code in DST_DIR
+  --cpp_out DST_DIR         Generate C++ code in DST_DIR
+  --csharp_out DST_DIR      Generate C# code in DST_DIR
+  --javascript_out DST_DIR  Generate JavaScript code in DST_DIR
+  --swift_out DST_DIR       Generate Swift code in DST_DIR
+  --dart_out DST_DIR        Generate Dart code in DST_DIR
+  --scala_out DST_DIR       Generate Scala 3 code in DST_DIR
+  --kotlin_out DST_DIR      Generate Kotlin code in DST_DIR
+  -I PATH                   Add a directory to the import search path
+  --grpc                    Generate gRPC service stubs alongside type 
definitions
+  --grpc-web                Generate JavaScript gRPC-Web client code
+  --grpc-python-mode MODE   Python gRPC API style: async (default) or sync
+  --help                    Show help message
 ```
 
 ## Examples


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to