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
//! # rpc_api
//!
//! Stable API boundary for the Thruput ONC-RPC stack.
//!
//! This crate owns the shared public types that connect three parties:
//!
//! - **`rpc_driver`** — the transport, pool, and dispatch implementation.
//! It depends on this crate, re-exports everything here at its historical
//! paths, and implements [`RpcSender`] for its connections and pools.
//! - **Generated protocol bindings** (protocol-rs clients and dispatchers),
//! which are generated against this crate only and acquire no transport
//! dependency.
//! - **Consumers**, which wire generated clients and dispatchers to driver
//! connections.
//!
//! Because all three share these types through a single, rarely-changing
//! crate, `rpc_driver` can make breaking implementation-only releases
//! (pools, configuration, transports) without forcing generated protocol
//! crates to republish.
//!
//! ## Stability
//!
//! This crate is intentionally tiny, and its dependencies are limited to
//! `async-trait` and `thiserror`. XDR serialization is the generated
//! bindings' business: they encode through [`CallBuf::append_with`] with
//! the `xdrs` they were generated against, so an `xdrs` release never
//! forces a release here. Changes must be additive wherever
//! possible: new [`RpcError`] variants are non-breaking thanks to
//! `#[non_exhaustive]`, and a new trait method ships with a default
//! implementation when a correct one exists for every sender. A breaking
//! change here forces a coordinated republish of every generated protocol
//! crate — treat it as a last resort.
//!
//! ## Sending a call
//!
//! Callers take a [`CallBuf`] from the sender with [`RpcSender::call_buf`],
//! encode the arguments into it, and pass it to [`RpcSender::send_call`].
//! The buffer keeps the wire prefix reserved ahead of the payload so the
//! driver frames the call in place, and driver senders recycle spent record
//! buffers through `call_buf`, so a steady stream of calls allocates
//! nothing. [`CallBuf::append_with`] hands the record buffer to a closure
//! that serializes into it in place; generated protocol clients encode
//! their argument tuple that way.
//!
//! ```
//! use rpc_api::CallBuf;
//!
//! let mut call = CallBuf::new();
//! call.extend_from_slice(&42u32.to_be_bytes());
//! assert_eq!(call.payload(), &[0, 0, 0, 42]);
//! ```
//!
//! ## Chunked messages
//!
//! A message too large for one record goes out as a run of records that
//! may arrive in any order. [`ChunkPosition`] says where a record sits in
//! its run, and a protocol crate implements [`ChunkRecord`] for each of its
//! chunked records; `rpc_driver::ChunkRunAssembler` reassembles the runs on
//! the server, so handlers push the records they receive as they are.
pub use CallBuf;
pub use ;
pub use RpcError;
pub use RpcHandler;
pub use ProgramError;
pub use RpcResponse;
pub use RpcSender;
/// RPC program and version identifier.