# capnp-rpc-rust
[](https://crates.io/crates/capnp-rpc)
[documentation](https://docs.rs/capnp-rpc/)
This is a [level one](https://capnproto.org/rpc.html#protocol-features)
implementation of the Cap'n Proto remote procedure call protocol.
It is a fairly direct translation of the original
[C++ implementation](https://github.com/sandstorm-io/capnproto).
## Defining an interface
First, make sure that the
[`capnp` executable](https://capnproto.org/capnp-tool.html)
is installed on your system,
and that you have the [`capnpc`](https://crates.io/crates/capnpc) crate
in the `build-dependencies` section of your `Cargo.toml`.
Then, in a file named `foo.capnp`, define your interface:
```capnp
@0xa7ed6c5c8a98ca40;
interface Bar {
baz @0 (x :Int32) -> (y :Int32);
}
interface Qux {
quux @0 (bar :Bar) -> (y :Int32);
}
```
Now you can invoke the schema compiler in a
[`build.rs`](http://doc.crates.io/build-script.html) file, like this:
```rust
fn main() {
::capnpc::CompilerCommand::new().file("foo.capnp").run().unwrap();
}
```
Such a command generates a `foo_capnp.rs` file in the `OUT_DIR`
directory provided by `cargo`.
To import the generated code, add a line like this at the root of your crate:
```rust
capnp::generated_code!(pub mod foo_capnp);
```
(If you want to import the code at a non-toplevel module location, then you will
need to use the `$Rust.parentModule` annotation, defined in `rust.capnp`.)
## Calling methods on an RPC object
For each defined interface, the generated code includes a `Client` struct
that can be used to call the interface's methods. For example, the following
code calls the `Bar.baz()` method:
```rust
fn call_bar(client: ::foo_capnp::bar::Client)
-> Box<Future<Item=i32, Error=::capnp::Error>>
{
let mut req = client.baz_request();
req.get().set_x(11);
Box::new(req.send().promise.and_then(|response| {
Ok(response.get()?.get_y())
}))
}
```
A `bar::Client` is a reference to a possibly-remote `Bar` object.
The Cap'n Proto RPC runtime tracks the number of such references
that are live at any given time and automatically drops the
object when none are left.
## Implementing an interface
The generated code also includes a `Server` trait for each of your interfaces.
To create an RPC-enabled object, you must implement that trait.
```rust
struct MyBar {}
impl ::foo_capnp::bar::Server for MyBar {
async fn baz(
self: Rc<Self>,
params: ::foo_capnp::bar::BazParams,
mut results: ::foo_capnp::bar::BazResults)
-> Result<(), ::capnp::Error>
{
results.get().set_y(params.get()?.get_x() + 1);
Ok(())
}
}
```
Then you can convert your object into a capability client like this:
```rust
let client: foo_capnp::bar::Client = capnp_rpc::new_client(MyBar {});
```
This new `client` can now be sent across the network.
You can use it as the bootstrap capability when you construct an `RpcSystem`,
and you can pass it in RPC method arguments and results.
## Async methods
The methods of the generated `Server` traits return
a value of type `impl Future<Output = Result<(), ::capnp::Error>>`.
As you have seen above,
these can be implented as `async fn` methods returning `Result<(), ::capnp::Error>`.
The RPC response will be sent back to the method's caller once two things have happened:
1. The `Results` struct has been dropped.
2. The method's returned `Future` has resolved.
Usually (1) happens before (2).
Here's an example of a method implementation that does not return immediately
because it awaits another request:
```rust
struct MyQux {}
impl ::foo_capnp::qux::Server for MyQux {
async fn quux(
self: Rc<Self>,
params: ::foo_capnp::qux::QuuxParams,
mut results: ::foo_capnp::wux::QuuxResults)
-> Result<(), ::capnp::Error>
{
// Call `baz()` on the passed-in client.
let bar_client = params.get()?.get_bar()?;
let mut req = bar_client.baz_request();
req.get().set_x(42);
let response = req.send().promise.await?; // <-- await
results.get().set_y(response.get()?.get_y());
Ok(())
}
}
```
It's possible for multiple calls of `quux()` to be active at the same time
on the same object, and they do not need to return in the same order
as they were called.
## Further reading
* The [hello world example](/capnp-rpc/examples/hello-world) demonstrates a basic request/reply pattern.
* The [calculator example](/capnp-rpc/examples/calculator)
demonstrates how to use [promise pipelining](https://capnproto.org/rpc.html#time-travel-promise-pipelining).
* The [pubsub example](/capnp-rpc/examples/pubsub) shows how even an interface with no methods can be useful.
* The [Sandstorm raw API example app](https://github.com/dwrensha/sandstorm-rawapi-example-rust)
shows how Sandstorm lets you write web apps using Cap'n Proto instead of HTTP.