Expand description
§Not Postcard-RPC
It needs a better name. nprpc is a tool for communication that is:
- Strongly typed (and Rust focused)
- Uses
postcard-schemafor deriving payload schemas. - Messages are tagged with an eight-byte hash of the method name, request schema, and response schema. Hash collisions are caught at compile time, and Cool Schemas Never Change.
- Uses
serdeandpostcardare used for serialization and deserialization. postcard-dyncan be used for dynamic ser/de, and transcoding frames to/from JSON (Coming Soon™️).
- Uses
- Strongly ordered
- Client initiates request to Server, then Server replies to Client.
- No concurrent in-flight requests.
- No multi-part requests or responses.
- Currently only blocking client/servers supported.
- At least an async (Tokio) client Coming Soon™️.
- Flexible transport and storage
- Can be used with or without a heap, both for frame buffering as well as request/response data payloads.
- Can work over any transport, clients and servers both have
Iotraits for custom plumbing. - For bounded types, maximum message sizes can be calculated, and
necessary buffer sizes are generated as
consts.
- Support for flexible data payloads:
- Variable length messages supported.
&[u8]or&strs can be borrowed from the incoming frame (for requests), or borrowed from the server for the outgoing frame (for responses).- Support for “type punning” on either side of the connection, e.g. the
server can send a
&strand the client can receive an ownedString.
- Doesn’t concern itself with reliable delivery (and doesn’t attempt to add reliability, That’s On You).
§Lightning Tour
We call “a set of remotely callable methods” an “interface”. You define
an interface using the interface! macro. You usually do this in a shared
example-api crate.
use nprpc::interface;
interface! {
/// This module named "example" contains everything you need for both
/// the client and server.
mod example {
/// We support doc comments and `#[cfg]`s on methods. Methods are
/// written using a mostly-rust-like syntax.
fn echo(u32) -> u32;
}
}In order to implement the server for this interface, you need to implement
the example::Server trait’s methods. You can use rust-analyzer’s
“Implement missing methods” action to do this quickly.
use nprpc::Request;
// From the `example-api` crate above
use example::Server;
// Not shown: impl Backend for WireBackend { .. }
struct WireBackend {
// ...
}
// Server-specific type that contains necessary trait
struct ServerImpl {
// ...
}
// Implementation of `example` defined by `interface!` above
impl example::Server for ServerImpl {
fn echo(&mut self, req: Request<u32>) -> u32 {
// `req` contains both the header of the request as well as the
// body, what we defined in the interface! macro. We just copy the
// data back out.
*req.body
}
}
fn main() {
let mut wire = WireBackend::new();
let mut server = ServerImpl::new();
// Server one request, typically done in a loop
let res = server.serve_one(&mut wire);
if let Err(e) = res {
println!("Err: {e:?}");
}
}
As a client, you’ll get an extension trait called Client that lets you
call the methods you defined.
// Not shown: impl Backend for WireBackend { .. }
struct WireBackend;
use nprpc::io::client::ClientIoError;
use nprpc::Response;
// Pull in the extension trait to get access to the methods for any type
// that impls `Backend`
use example::Client;
fn main() {
let mut backend = WireBackend;
let res: Result<Response<u32>, ClientIoError<_>> = backend.echo(&123);
}
§Naming Guide
For the sake of consistency, we use the following naming scheme for types and lifetimes. Prefer the 4-letter abbreviations to keep pieces aligned in multi-line code.
- “Request”
- A message sent by a client, and received by a server
request,rqst, or'rqst
- “Response”
- A message sent by a server, and received by a client
response,resp, or'resp
- “Header”
- Included in every request and response, same type in all items
headerorhedr
- “Body”
- The type-specific payload. Used for both the serialized form as well as the rust-type form.
- Always
body. May have the lifetime'rqstor'resp.
Re-exports§
pub use io::client::ClientError;pub use io::client::ClientIoError;pub use io::server::ServerError;pub use io::server::ServerIoError;
Modules§
- interface
- Interface and Interface Methods
- io
- Client and Server I/O items
- macros
- Declarative macros
- wire
- Wire types
Macros§
- autobuffer
- Defines a buffer type for a given interface
- compose_
interfaces - Macro to combine multiple interfaces into a single composite interface.
- interface
- Interface Definition macro
Structs§
- Request
- Borrowed view of a request
- Request
Raw - Borrowed view of a request
- Response
- Owned view of a response