essrpc 0.4.1

RPC using natural trait definitions and calls.
Documentation
use essrpc::essrpc;
use essrpc::transports::{BincodeAsyncClientTransport, BincodeTransport, ReadWrite};
use essrpc::{AsyncRPCClient, RPCErrorKind, RPCServer};
use serde::{Deserialize, Serialize};
use std::env;
use std::fmt;
use std::process::Stdio;
use std::result::Result;
use tokio;
use tokio::process::Command;

#[tokio::main]
pub async fn main() {
    use readwrite::ReadWriteTokio;

    let args: Vec<String> = env::args().collect();

    if args.len() > 1 {
        server().await;
        return;
    }

    // launch server
    let cmd = &args[0];
    let mut server = Command::new(cmd)
        .arg("s")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::inherit())
        .spawn()
        .expect("Failed to spawn remote server");

    let server_in = server.stdin.as_mut().expect("Failed to open stdin");
    let server_out = server.stdout.as_mut().expect("Failed to read stdout");

    let server_io = ReadWriteTokio::new(server_out, server_in);

    let remote = FooAsyncRPCClient::new(BincodeAsyncClientTransport::new(server_io));

    println!(
        "{}",
        remote
            .bar("the answer".to_string(), 42)
            .await
            .expect("failed to run bar")
    );
    println!("{:?}", remote.foo().await.expect("failed to run foo"));
}

async fn server() {
    use std::io::{self};

    let stdin = io::stdin();
    let stdout = io::stdout();

    let stdio = ReadWrite::new(stdin, stdout);

    let mut serve = FooRPCServer::new(FooImpl::new(), BincodeTransport::new(stdio));
    match serve.serve() {
        Ok(_) => panic!("Expected EOF error"),
        Err(e) => assert_eq!(e.kind, RPCErrorKind::TransportEOF),
    };
}

#[derive(Debug, Deserialize, Serialize)]
pub struct TestError {
    msg: String,
}

impl fmt::Display for TestError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "error: {}", self.msg)
    }
}

impl std::error::Error for TestError {}
impl From<essrpc::RPCError> for TestError {
    fn from(error: essrpc::RPCError) -> Self {
        TestError {
            msg: format!("{}", error),
        }
    }
}

#[essrpc(async, sync)]
pub trait Foo {
    fn foo(&self) -> Result<Vec<u8>, TestError>;
    fn bar(&self, a: String, b: i32) -> Result<String, TestError>;
    fn expect_error(&self) -> Result<String, TestError>;
}

struct FooImpl;

impl FooImpl {
    fn new() -> Self {
        FooImpl {}
    }
}

impl Foo for FooImpl {
    fn foo(&self) -> Result<Vec<u8>, TestError> {
        let mut a: Vec<u8> = Vec::new();
        a.resize(1024, 0);
        Ok(a)
    }
    fn bar(&self, a: String, b: i32) -> Result<String, TestError> {
        Ok(format!("{} is {}", a, b))
    }
    fn expect_error(&self) -> Result<String, TestError> {
        Err(TestError {
            msg: "iamerror".to_string(),
        })
    }
}