Protobuf and Code Generation
TrevRPC follows the same basic workflow as ConnectRPC: protobuf defines the API, and code generation creates type-safe client and server glue. Application code implements the generated service trait or interface.
Example Service
syntax = "proto3";
package example.greeter;
service Greeter {
rpc SayHello(HelloRequest) returns (HelloReply);
rpc LotsOfReplies(HelloRequest) returns (stream HelloReply);
rpc LotsOfGreetings(stream HelloRequest) returns (HelloReply);
rpc BidiHello(stream HelloRequest) returns (stream HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
This schema covers all supported RPC shapes:
| Protobuf shape | TrevRPC kind |
|---|---|
Req -> Res |
Unary |
Req -> stream Res |
Server streaming |
stream Req -> Res |
Client streaming |
stream Req -> stream Res |
Bidirectional streaming |
Install Generators Locally
Install the Rust generator from the repository root:
cargo install --path trevrpc-rust/crates/protoc-gen-trevrpc-rust
Install the Go generator from the Go module directory:
cd trevrpc-go
go install ./cmd/protoc-gen-trevrpc-go
Install the C generator from the repository root:
cmake -S trevrpc-c -B build/trevrpc-c-codegen \
-DTREVRPC_BUILD_MSQUIC=OFF \
-DTREVRPC_BUILD_WEBTRANSPORT=OFF \
-DTREVRPC_BUILD_RUNTIME=OFF \
-DTREVRPC_BUILD_TESTS=OFF
cmake --build build/trevrpc-c-codegen --target protoc-gen-trevrpc-c
cmake --install build/trevrpc-c-codegen --prefix ~/.local
Build and install the C++ runtime and protoc-gen-trevrpc-cpp from the repository root:
cmake -S trevrpc-cpp -B build/trevrpc-cpp
cmake --build build/trevrpc-cpp
cmake --install build/trevrpc-cpp --prefix ~/.local
For C++, run both protobuf's built-in C++ generator and the TrevRPC plugin against the same schema:
protoc -I proto \
--cpp_out=gen/cpp \
--trevrpc-cpp_out=gen/cpp \
proto/example/greeter.proto
The plugin emits .trevrpc.hpp and .trevrpc.cpp. Compile them with protobuf's .pb.h and .pb.cc. Use normal protobuf C++ generation for the full runtime, or set option optimize_for = LITE_RUNTIME; and link protobuf lite. Do not generate protobuf-c files for the C++ runtime.
Install the JavaScript generator from the JavaScript package directory:
cd trevrpc-js
npm install
npm link
For local development without linking, call the checked-in bin/protoc-gen-trevrpc-js.js executable directly from your Buf or protoc configuration.
Build the Kotlin generator from the Kotlin project:
cd trevrpc-kotlin
./gradlew :protoc-gen-trevrpc-kotlin:installDist
The executable is under protoc-gen-trevrpc-kotlin/build/install/protoc-gen-trevrpc-kotlin/bin/. Add that directory to PATH or reference the executable directly.
Buf Configuration
Example buf.gen.yaml:
version: v2
plugins:
- local: protoc-gen-trevrpc-rust
out: trevrpc-rust/src/generated
opt:
- runtime_path=::trevrpc
- package_root=crate
- local: protoc-gen-trevrpc-go
out: trevrpc-go/generated
opt:
- runtime_import=trev.zip/llc/trevrpc/trevrpc-go
- local: protoc-gen-trevrpc-c
out: trevrpc-c/generated
opt:
- runtime_include=trevrpc.h
- local: protoc-gen-trevrpc-cpp
out: trevrpc-cpp/generated
- local: protoc-gen-trevrpc-kotlin
out: trevrpc-kotlin/generated
opt:
- runtime_package=zip.trev.trevrpc
- local: protoc-gen-trevrpc-js
out: trevrpc-js/generated
opt:
- runtime_import=trevrpc-js
The exact output directories depend on your project layout. Generated TrevRPC files should be compiled alongside the protobuf message types generated by your protobuf generator.
Rust Generator
The Rust plugin is protoc-gen-trevrpc-rust.
It generates:
- An async service trait per protobuf service.
- A
{Service}Client<T>generic over a TrevRPC transport. - A
register_{service}function that installs routes ontrevrpc::server::Server.
Supported options:
| Option | Default | Purpose |
|---|---|---|
runtime_path |
::trevrpc |
Path used to refer to the TrevRPC runtime in generated code |
file_suffix |
.trevrpc.rs |
Suffix for generated files |
package_root |
crate |
Root path used when generated code references messages from other protobuf packages |
The Rust generator emits one file per protobuf package. A package named hello.v1 produces hello.v1.trevrpc.rs by default.
Include generated TrevRPC bindings in the same Rust module as the corresponding prost message types:
pub mod hello {
pub mod v1 {
include!(concat!(env!("OUT_DIR"), "/hello.v1.rs"));
include!(concat!(env!("OUT_DIR"), "/hello.v1.trevrpc.rs"));
}
}
Generated Rust service signatures use concrete protobuf message types and trevrpc::BoxMessageStream<T> for streamed inputs and outputs.
Go Generator
The Go plugin is protoc-gen-trevrpc-go.
It generates:
- A
{Service}Serverinterface. - A
{Service}Clientwith typed methods. - A
New{Service}Clientconstructor. - A
Register{Service}Serverfunction that installs routes on*trevrpc.Server.
Supported options:
| Option | Default | Purpose |
|---|---|---|
runtime_import |
trev.zip/llc/trevrpc/trevrpc-go |
Import path for the TrevRPC Go runtime |
file_suffix |
.trevrpc.go |
Suffix for generated files |
The Go generator emits output only for requested proto files that contain services. A file named greeter.proto produces greeter.trevrpc.go by default.
Generated Go service signatures use protobuf message pointers and trevrpc.MessageStream[T] for streamed inputs and outputs.
C Generator
The C plugin is protoc-gen-trevrpc-c.
It generates:
- A service implementation struct with one function pointer per RPC.
- Typed unary, server-streaming, client-streaming, and bidirectional-streaming client helpers.
- Typed stream send and receive helpers around
trevrpc_stream. - A registration function that installs protobuf-c decoding/encoding adapters on
trevrpc_server.
Supported options:
| Option | Default | Purpose |
|---|---|---|
runtime_include |
trevrpc.h |
Header path for the TrevRPC C runtime |
header_suffix |
.trevrpc.h |
Suffix for generated C headers |
source_suffix |
.trevrpc.c |
Suffix for generated C source files |
Generated C files should be compiled with the corresponding protobuf-c output for the same .proto file. Generated handlers use protobuf-c message pointers and trevrpc_stream* for streamed inputs and outputs.
C++ Generator
The C++ plugin is protoc-gen-trevrpc-cpp. It generates:
- A synchronous
{Service}Serviceinterface for server implementations. - A synchronous
{Service}Clientwith typed operations for all four RPC shapes. - A
Register{Service}function that installs the implementation onServer. - Explicit
Resultreturn values for calls, stream operations, registration, and lifecycle operations that can fail. - Serialization adapters for protobuf C++ full and lite generated message classes.
The C++ generator consumes protobuf descriptors but does not generate message classes itself. Generate messages with protobuf's C++ generator and compile those files beside the TrevRPC service bindings. A schema's protobuf full-versus-lite selection determines the message runtime; the TrevRPC binding shape remains the same.
Supported options:
| Option | Default | Purpose |
|---|---|---|
runtime_include |
trevrpc/trevrpc.hpp |
C++ runtime header used by generated code |
header_suffix |
.trevrpc.hpp |
Generated binding header suffix |
source_suffix |
.trevrpc.cpp |
Generated binding source suffix |
The C++ layer does not use protobuf-c. Generated adapters serialize protobuf C++ messages to bytes, pass those bytes through the existing trevrpc-c transport and server primitives, and parse response bytes back into protobuf C++ messages. This keeps the C transport responsible for QUIC, framing, limits, cancellation, and channel reconnection while C++ owns typed protobuf integration.
Generated declarations use the protobuf package's C++ namespace and concrete protobuf message types. Clients own a shared Channel; registration retains a shared service implementation through the server route adapters.
Kotlin Generator
The Kotlin plugin is protoc-gen-trevrpc-kotlin.
It generates:
- A
{Service}Serviceinterface with suspend handlers andFlowstreams. - A
{Service}Clientwith typed convenience and interactive streaming methods. - A
register{Service}function that installs routes onzip.trev.trevrpc.Server. - Protobuf Java message codecs plus service, method, and RPC-kind constants.
Supported options:
| Option | Default | Purpose |
|---|---|---|
runtime_package |
zip.trev.trevrpc |
Package used to refer to the Kotlin core runtime |
file_suffix |
.trevrpc.kt |
Suffix for generated Kotlin binding files |
The generator emits output only for requested proto files that contain services. A file named greeter.proto produces greeter.trevrpc.kt by default. Generated bindings use protobuf Java message classes, so compile them alongside Java or Kotlin protobuf output for the same schema.
Streaming convenience methods use kotlinx.coroutines.flow.Flow. Client-streaming and bidirectional methods also expose call objects with bounded send, closeSend, receive, and close operations.
JavaScript Generator
The JavaScript plugin is protoc-gen-trevrpc-js.
It generates:
- A
{Service}Clientclass with typed TrevRPC method names. - A
create{Service}Clienthelper. - A
{Service}Servicedescriptor used by the runtime client factory. - A protobuf.js reflection root embedded in the generated file.
- A companion TypeScript declaration file for the generated JavaScript module.
Supported options:
| Option | Default | Purpose |
|---|---|---|
runtime_import |
trevrpc-js |
Import path for the TrevRPC JavaScript runtime |
file_suffix |
.trevrpc.js |
Suffix for generated files |
The JavaScript generator emits output only for requested proto files that contain services. A file named greeter.proto produces greeter.trevrpc.js and greeter.trevrpc.d.ts by default.
Generated JavaScript clients use protobuf.js reflection types and accept plain JavaScript objects for protobuf messages. Unary calls resolve to one response object. Server-streaming calls resolve to an async iterable of response objects. Client-streaming and bidirectional-streaming calls resolve to sendable call objects.
Generated declaration files include TypeScript interfaces for the protobuf message types embedded in the generated reflection root. TypeScript projects import the same .trevrpc.js module path and receive the companion .d.ts types:
import { GreeterClient } from "./hello/v1/greeter.trevrpc.js";
import type { HelloRequest } from "./hello/v1/greeter.trevrpc.js";
const request: HelloRequest = { name: "TrevRPC" };
What Generated Code Does
Generated client methods call the runtime helpers for the matching RPC kind:
- Rust:
trevrpc::client::unary,server_streaming,client_streaming,bidirectional_streaming. - Go:
trevrpc.Unary,ServerStreaming,ClientStreaming,BidirectionalStreaming. - C:
trevrpc_client_call_unary,trevrpc_client_start_stream, and generated typed stream helpers. - C++: synchronous generated client and stream operations that serialize protobuf C++ messages and delegate byte transport to
trevrpc-c. - Kotlin:
Client.unaryEnvelope,serverStreaming,clientStreaming, andbidirectionalStreamingfromzip.trev.trevrpc. - JavaScript:
unary,serverStreaming,clientStreaming,bidirectionalStreamingfromtrevrpc-js.
Generated Rust, Go, C, C++, and Kotlin registration functions decode request protobuf messages, call your implementation, encode response protobuf messages, and register the method with the runtime server. C++ performs that work with protobuf C++ full or lite APIs rather than protobuf-c.
Error Handling in Generated Code
Handlers return regular language errors that the runtime maps into TrevRPC statuses:
- Rust service methods return
Result<_, trevrpc::Status>. - Go service methods return
(_, error), where*trevrpc.Statuspreserves an explicit status code. - C service methods return
0on success or a TrevRPC/POSIX-style negative error code that the runtime maps into a status. - C++ service methods and client operations return explicit
Resultvalues. Streaming send, receive, finish, and terminal status failures are surfaced at the operation that observes them. - Kotlin service methods return message values or
Flowand throwTrevRpcExceptionto preserve an explicit status code.
JavaScript generated clients throw TrevRpcError for non-OK TrevRPC statuses and mapped transport failures.
Decode failures are reported as InvalidArgument. Unknown methods are reported as Unimplemented. Oversized frames and streams are reported as ResourceExhausted.