⚠️ Rumpsteak is currently a work in progress and the API is likely to dramatically change. Feel free to try out examples but please do not yet use Rumpsteak for any production applications!
Rumpsteak is a Rust framework for safely and efficiently implementing message-passing asynchronous programs. It uses multiparty session types to statically guarantee the absence of communication errors such as deadlocks and asynchronous subtyping to allow optimizing communications.
Multiparty session types (MPST) verify the safety of message-passing protocols, as described in A Very Gentle Introduction to Multiparty Session Types. Asynchronous subtyping, introduced for MPST in Precise Subtyping for Asynchronous Multiparty Sessions, verifies the reordering of messages to create more optimized implementations than are usually possible with MPST.
- Provides deadlock-free communication.
- Integrates with
async
/await
code. - Supports any number of participants.
- Includes benchmarks to track performance.
Add the following to your Cargo.toml
file.
[dependencies]
rumpsteak = "0.1"
use futures::{
channel::mpsc::{UnboundedReceiver, UnboundedSender},
executor, try_join,
};
use rumpsteak::{
channel::Bidirectional, session, try_session, End, Message, Receive, Role, Roles, Send,
};
use std::{error::Error, result};
type Result<T> = result::Result<T, Box<dyn Error>>;
type Channel = Bidirectional<UnboundedSender<Label>, UnboundedReceiver<Label>>;
#[derive(Roles)]
struct Roles(C, S);
#[derive(Role)]
#[message(Label)]
struct C(#[route(S)] Channel);
#[derive(Role)]
#[message(Label)]
struct S(#[route(C)] Channel);
#[derive(Message)]
enum Label {
Add(Add),
Sum(Sum),
}
struct Add(i32);
struct Sum(i32);
#[session]
type Client = Send<S, Add, Send<S, Add, Receive<S, Sum, End>>>;
#[session]
type Server = Receive<C, Add, Receive<C, Add, Send<C, Sum, End>>>;
async fn client(role: &mut C, x: i32, y: i32) -> Result<i32> {
try_session(role, |s: Client<'_, _>| async {
let s = s.send(Add(x)).await?;
let s = s.send(Add(y)).await?;
let (Sum(z), s) = s.receive().await?;
Ok((z, s))
})
.await
}
async fn server(role: &mut S) -> Result<()> {
try_session(role, |s: Server<'_, _>| async {
let (Add(x), s) = s.receive().await?;
let (Add(y), s) = s.receive().await?;
let s = s.send(Sum(x + y)).await?;
Ok(((), s))
})
.await
}
fn main() {
let Roles(mut c, mut s) = Roles::default();
executor::block_on(async {
let (output, _) = try_join!(client(&mut c, 1, 2), server(&mut s)).unwrap();
assert_eq!(output, 3);
});
}
Benchmark suite to track Rumpsteak's performance over time.
HTTP cache case study backed by Redis.
Comparison with some other Rust implementations of session types.
Many examples of using Rumpsteak from popular protocols.
Automatic code generation from finite state machines to Rumpsteak's API.
Crate for procedural macros used within Rumpsteak's API.
Outdated experimental implementation of using one-shot channels for communication.
Licensed under the MIT license. See the LICENSE file for details.