# dubbo-rs-codegen
[](https://crates.io/crates/dubbo-rs-codegen)
[](https://docs.rs/dubbo-rs-codegen)
[](LICENSE)
protoc code generation plugin for dubbo-rs.
## Installation
Add this to your `Cargo.toml`:
```toml
[dependencies]
dubbo-rs-codegen = "0.1"
```
Or use `cargo add`:
```bash
cargo add dubbo-rs-codegen
```
Integrates with `tonic-prost-build` to compile `.proto` files, generating standard proto types + tonic service stubs to `OUT_DIR`. Then produces Dubbo-specific integration wrappers (service registration helpers, channel-based and invoker-based clients) as `GeneratedCode`.
## Key Types
| `CodeGenerator` | Main entry point — takes `GeneratorConfig`, runs code generation |
| `GeneratorConfig` | Configuration: `proto_paths`, `output_dir`, `enable_client`, `enable_server`, `client_mode` |
| `GeneratorConfigBuilder` | Builder for `GeneratorConfig` — validates `proto_paths` is non-empty |
| `GeneratedCode` | Output container — `files: HashMap<String, String>`, with `write_to_dir` |
| `ClientMode` | Client generation mode: `Channel`, `Invoker`, or `Both` (default) |
## Client Modes
| `Channel` | Generates a channel-based client wrapping tonic's typed `GreeterClient<Channel>` |
| `Invoker` | Generates an invoker-based client using `Box<dyn Invoker>` with prost encoding |
| `Both` (default) | Generates both client types |
### Channel Client
Wraps the tonic-generated typed client. Provides `connect()`, `from_channel()`, and `from_dubbo_client()` constructors. Supports all 4 RPC types (unary, server-streaming, client-streaming, bidi-streaming).
```rust
pub struct GreeterChannelClient {
inner: proto::greeter_client::GreeterClient<tonic::transport::Channel>,
}
impl GreeterChannelClient {
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error> { ... }
pub fn from_channel(channel: tonic::transport::Channel) -> Self { ... }
pub fn from_dubbo_client(client: &dubbo_rs_client::Client) -> Option<Self> { ... }
}
```
### Invoker Client
Uses `Box<dyn dubbo_rs_protocol::Invoker>` with `prost::Message` encoding/decoding. Unary methods are fully supported. Streaming methods generate a comment indicating they are not supported via Invoker and the user should use the Channel client instead.
```rust
pub struct GreeterInvokerClient {
invoker: Box<dyn dubbo_rs_protocol::Invoker>,
}
impl GreeterInvokerClient {
pub fn new(invoker: Box<dyn dubbo_rs_protocol::Invoker>) -> Self { ... }
pub async fn say_hello(&self, request: proto::HelloRequest) -> anyhow::Result<proto::HelloReply> {
// Uses prost::Message::encode_to_vec / decode with path "/greeter.Greeter/SayHello"
}
}
```
## Usage
```rust
use dubbo_rs_codegen::{CodeGenerator, GeneratorConfigBuilder, ClientMode};
let config = GeneratorConfigBuilder::new()
.proto_path("proto/hello.proto")
.proto_path("proto/common.proto")
.output_dir("src/gen")
.enable_client(true)
.enable_server(true)
.client_mode(ClientMode::Both)
.build()?;
let generator = CodeGenerator::new(config);
let generated = generator.generate()?;
// Write generated files to disk
generated.write_to_dir(std::path::Path::new("src/gen"))?;
```
## Generated Output
For a proto with `package greeter` and `service Greeter`, generates `greeter_dubbo.rs`:
```rust
//! Dubbo integration for `greeter` package.
//! Generated by dubbo-codegen. DO NOT EDIT.
/// Proto types and tonic stubs.
pub mod proto {
tonic::include_proto!("greeter");
}
// === Service Registration ===
/// Register a `Greeter` service with a Dubbo server.
pub fn register_greeter_service(
server: dubbo_rs_server::Server,
svc: impl proto::greeter_server::Greeter + 'static,
) -> dubbo_rs_server::Server {
server.register_service(|builder| {
builder.add_service(proto::greeter_server::GreeterServer::new(svc))
})
}
// === Channel Client ===
pub struct GreeterChannelClient {
inner: proto::greeter_client::GreeterClient<tonic::transport::Channel>,
}
impl GreeterChannelClient {
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error> { ... }
pub fn from_channel(channel: tonic::transport::Channel) -> Self { ... }
pub fn from_dubbo_client(client: &dubbo_rs_client::Client) -> Option<Self> { ... }
}
impl GreeterChannelClient {
pub async fn say_hello(&mut self, request: impl Into<proto::HelloRequest>)
-> Result<tonic::Response<proto::HelloReply>, tonic::Status> { ... }
}
// === Invoker Client ===
pub struct GreeterInvokerClient {
invoker: Box<dyn dubbo_rs_protocol::Invoker>,
}
impl GreeterInvokerClient {
pub fn new(invoker: Box<dyn dubbo_rs_protocol::Invoker>) -> Self { ... }
}
impl GreeterInvokerClient {
pub async fn say_hello(&self, request: proto::HelloRequest)
-> anyhow::Result<proto::HelloReply> { ... }
}
```
## Streaming Support
All 4 RPC types are supported in generated code:
| Unary | ✅ Forwarded to tonic | ✅ prost encode/decode |
| Server Streaming | ✅ `tonic::codec::Streaming<T>` | ❌ Use Channel client |
| Client Streaming | ✅ `IntoStreamingRequest` | ❌ Use Channel client |
| Bidi Streaming | ✅ Both streaming | ❌ Use Channel client |
## Streaming Proto Example
For a streaming proto like:
```protobuf
service TelephoneExchange {
rpc Dial(DialRequest) returns (stream DialProgress);
}
```
The generated channel client method returns:
```rust
pub async fn dial(&mut self, request: impl Into<proto::DialRequest>)
-> Result<tonic::Response<tonic::codec::Streaming<proto::DialProgress>>, tonic::Status>
```
## License
Apache-2.0