5 releases (3 breaking)

0.5.1 Jun 22, 2023
0.5.0 Feb 26, 2023
0.3.0 Jan 5, 2023
0.2.0 Dec 25, 2022
0.1.0 Dec 25, 2022

#679 in Concurrency

Download history 7/week @ 2024-02-12 16/week @ 2024-02-19 29/week @ 2024-02-26 13/week @ 2024-03-04 27/week @ 2024-03-11 14/week @ 2024-03-18 16/week @ 2024-03-25 39/week @ 2024-04-01

70 downloads per month
Used in 5 crates (3 directly)

MIT license


An actor-like RPC framework built for true zero-copy message handling.

A actor-like RPC framework built for true zero-copy message handling.

This framework is inspired by tonic but is not a GRPC framework. Instead, it makes use of the incredible rkyv (de)serialization framework which provides us with lightning fast (de)serialization and also lets us perform true zero-copy deserialization which can lead to massive performance improvements when processing lots of big messages at once.


  • Fast (de)serialization of owned types.
  • True zero-copy deserialization avoiding heavy allocations.
  • Dynamic adding and removing of message handlers/services.

Basic example

use std::net::SocketAddr;                                                                      
use datacake_rpc::{                                                                             
use rkyv::{Archive, Deserialize, Serialize};                                                    
// The framework accepts any messages which implement `Archive` and `Serialize` along           
// with the archived values implementing `CheckBytes` from the `bytecheck` crate.               
// This is to ensure safe, validated deserialization of the values.                             
// Checkout rkyv for more information!                                                          
#[derive(Serialize, Deserialize, Archive, PartialEq, Debug)]                                    
#[archive(compare(PartialEq), check_bytes)]                                                                  
#[archive_attr(derive(PartialEq, Debug))]                                           
pub struct MyMessage {                                                                          
    name: String,                                                                               
    age: u32,                                                                                   
pub struct MyService;                                                                           
impl RpcService for MyService {                                                                 
    // The `register_handlers` is used to mark messages as something                            
    // the given service can handle and process.                                                
    // Messages which are not registered will not be dispatched to the handler.                 
    fn register_handlers(registry: &mut ServiceRegistry<Self>) {                                
impl Handler<MyMessage> for MyService {                                                         
    type Reply = String;                                                                        
    // Our `Request` gives us a zero-copy view to our message, this doesn't actually            
    // allocate the message type.                                                               
    async fn on_message(&self, msg: Request<MyMessage>) -> Result<Self::Reply, Status> {        
async fn main() -> anyhow::Result<()> {                                                         
    let address = "".parse::<SocketAddr>()?;                                      
    let server = Server::listen(address).await?;                                                
    // Services can be added and removed at runtime once the server is started.                 
    println!("Listening to address {}!", address);                                              
    // Channels are cheap to clone similar to tonic.                                            
    let client = Channel::connect(address);                                              
    println!("Connected to address {}!", address);                                              
    let rpc_client = RpcClient::<MyService>::new(client);                                   
    let msg1 = MyMessage {                                                                      
        name: "Bobby".to_string(),                                                              
        age: 12,                                                                                
    // Clients only need references to the message which helps                                  
    // reduce allocations.                                                                      
    let resp = rpc_client.send(&msg1).await?;                                                   
    assert_eq!(resp, msg1.name);                                                                     


~162K SLoC