1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//! A gRPC server and client for [trillium](https://trillium.rs), built as a
//! thin layer on `trillium-http`'s HTTP/2, h2c (HTTP/2 over cleartext), and
//! HTTP/3 support. If you have a `.proto` service definition and want to serve
//! it — or call it — from a trillium application, this generates the glue and
//! handles the wire format. It is a from-scratch, spec-conformant
//! implementation of the [gRPC over HTTP/2 protocol].
//!
//! All four call shapes are supported — unary, server-streaming,
//! client-streaming, and bidirectional-streaming — along with protobuf
//! messages via [`prost`](https://docs.rs/prost) (and optional JSON behind the
//! `json` feature) and per-message compression (`gzip` by default, `deflate`
//! and `zstd` behind features).
//!
//! # Generating service code
//!
//! You write a `.proto`; codegen produces a Rust module containing the prost
//! message types, a service trait you implement, a `<Service>Server` handler
//! that mounts into a trillium handler chain, and a `<Service>Client` for
//! calling the service. There are three ways to run that codegen, and they all
//! produce the same output:
//!
//! **The `trillium grpc` CLI** writes the generated module to a path you choose
//! and check in:
//!
//! ```text
//! cargo install trillium-cli --features grpc --no-default-features
//! trillium grpc path/to/service.proto src/generated/service.rs -I path/to/include
//! ```
//!
//! Checking the output in is a feature, not a workaround — the generated code
//! is meant to be read, reviewed, and diffed like any other source file, the
//! way you'd treat a committed `Cargo.lock`. You bring it into your crate with
//! a plain module:
//!
//! ```rust,ignore
//! mod service {
//! include!("generated/service.rs");
//! }
//! ```
//!
//! **The [`generate!`] macro** (requires the `macros` feature) runs the same
//! codegen at compile time and inlines the result, so there's no file to
//! manage:
//!
//! ```rust,ignore
//! trillium_grpc::generate!("proto/service.proto");
//! ```
//!
//! **A build script** (requires the `codegen` feature) writes the module into
//! `OUT_DIR` and re-runs when the `.proto` changes. This is the most
//! conventional option for prost users but the least transparent — the output
//! isn't visible in your tree — so reach for it only if the CLI and macro don't
//! fit:
//!
//! ```rust,ignore
//! // build.rs
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! trillium_grpc::codegen::compile_protos(&["proto/service.proto"], &["proto"])?;
//! Ok(())
//! }
//! ```
//!
//! ```rust,ignore
//! // src/lib.rs
//! mod service {
//! include!(concat!(env!("OUT_DIR"), "/service.v1.rs"));
//! }
//! ```
//!
//! # A worked example
//!
//! Given this service:
//!
//! ```proto
//! syntax = "proto3";
//! package greeter.v1;
//!
//! service Greeter {
//! rpc SayHello(HelloRequest) returns (HelloReply);
//! rpc SayHelloStream(HelloRequest) returns (stream HelloReply);
//! }
//!
//! message HelloRequest { string name = 1; }
//! message HelloReply { string message = 1; }
//! ```
//!
//! codegen emits a `Greeter` trait. Unary methods take the request and return
//! the response; server-streaming methods receive a [`ResponseSink`] to push
//! responses into. You implement it on your own type:
//!
//! ```rust,ignore
//! use trillium_grpc::{ResponseSink, Status};
//! use greeter::v1::{Greeter, HelloReply, HelloRequest};
//!
//! struct MyGreeter;
//!
//! impl Greeter for MyGreeter {
//! async fn say_hello(&self, req: HelloRequest) -> Result<HelloReply, Status> {
//! Ok(HelloReply { message: format!("Hello, {}", req.name) })
//! }
//!
//! async fn say_hello_stream(
//! &self,
//! req: HelloRequest,
//! mut responses: ResponseSink<'_, HelloReply>,
//! ) -> Result<(), Status> {
//! for i in 1..=3 {
//! responses.send(HelloReply { message: format!("Hello {i}, {}", req.name) }).await?;
//! }
//! Ok(())
//! }
//! }
//! ```
//!
//! `GreeterServer::new(MyGreeter)` is an ordinary trillium
//! [`Handler`](trillium::Handler) — mount it like any other:
//!
//! ```rust,ignore
//! trillium_tokio::run(greeter::v1::GreeterServer::new(MyGreeter));
//! ```
//!
//! The generated `GreeterClient` wraps a [`trillium_client::Client`]. Its
//! constructor takes the client by `From`, appending the service path to the
//! base URL; each method then issues one RPC:
//!
//! ```rust,ignore
//! use greeter::v1::{GreeterClient, HelloRequest};
//!
//! let client = GreeterClient::from(
//! trillium_client::Client::new(trillium_tokio::ClientConfig::default())
//! .with_base("http://127.0.0.1:8080"),
//! );
//! let reply = client.say_hello(HelloRequest { name: "world".into() }).await?;
//! ```
//!
//! Per-client options — outbound compression, a default deadline — live on the
//! [`ServiceClientExt`] trait, which every generated client implements.
//!
//! # The streaming shapes
//!
//! The server trait method signature follows the RPC's directionality. The
//! streaming directions are expressed as borrowed primitives whose lifetime is
//! tied to the method call: you read requests and push responses through them,
//! and the framework writes the terminating status from your returned
//! `Result`:
//!
//! | RPC shape | server receives | server returns |
//! |--------------------|------------------------------------------------|------------------------|
//! | unary | `Req` | `Result<Resp, Status>` |
//! | server-streaming | `Req`, [`ResponseSink`]`<'_, Resp>` | `Result<(), Status>` |
//! | client-streaming | [`RequestStream`]`<'_, Req>` | `Result<Resp, Status>` |
//! | bidirectional | [`Channel`]`<'_, Req, Resp>` | `Result<(), Status>` |
//!
//! On the client side, request streams are taken as `impl Stream<Item = Req>`
//! and response streams are returned as `impl Stream<Item = Result<Resp,
//! Status>>` backed by [`ResponseStream`].
//!
//! [gRPC over HTTP/2 protocol]: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
pub use trillium_grpc_codegen as codegen;
pub use generate;
pub use ;
pub use ;
pub use Encoding;
pub use Stream;
pub use ;
pub use ;
pub use ;