tarpc-cat 0.1.0

RPC framework built on comp-cat-rs: typed effects, no async, categorical foundations
Documentation
  • Coverage
  • 100%
    54 out of 54 items documented0 out of 29 items with examples
  • Size
  • Source code size: 45.76 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 4.23 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 48s Average build duration of successful builds.
  • all releases: 48s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • MavenRain/tarpc-cat
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • MavenRain

tarpc-cat

RPC framework built on comp-cat-rs: typed effects, no async, categorical foundations.

Reimagines the core abstractions of tarpc using Io<E, A> as the effect type, blocking I/O via Io::suspend, and thread-based concurrency. Nothing executes until .run().

Features

  • Lazy effects -- all operations return Io<Error, A>, composable via map, flat_map, zip
  • Linear state-threading transport -- the Transport trait consumes and returns itself on each operation, avoiding shared state
  • Connection-per-request client -- simple, stateless TCP calls
  • Thread-per-connection server -- accepts connections via iterator combinators, spawns a thread for each
  • Pluggable transport -- TcpTransport for production, ChannelTransport for testing
  • Length-delimited JSON wire format -- 4-byte big-endian length prefix + JSON payload
  • No async, no tokio -- pure std::net + comp-cat-rs effects

Usage

Define a service

use tarpc_cat::serve::Serve;
use tarpc_cat::error::Error;
use comp_cat_rs::effect::io::Io;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct Ping(String);

#[derive(Serialize, Deserialize)]
struct Pong(String);

#[derive(Clone)]
struct PingService;

impl Serve for PingService {
    type Request = Ping;
    type Response = Pong;

    fn handle(&self, request: Ping) -> Io<Error, Pong> {
        Io::pure(Pong(request.0))
    }
}

Run the server

use tarpc_cat::server::{serve, ListenAddr};

let addr = ListenAddr::new("127.0.0.1:9000".parse().unwrap());
serve(addr, PingService).run()?;

Call from a client

use tarpc_cat::client::{call, ServerAddr};

let addr = ServerAddr::new("127.0.0.1:9000".parse().unwrap());
let pong: Pong = call(addr, Ping("hello".into())).run()?;

Compose multiple calls

use tarpc_cat::client::{call, ServerAddr};

let addr = ServerAddr::new("127.0.0.1:9000".parse().unwrap());

let both = call::<Ping, Pong>(addr, Ping("first".into()))
    .flat_map(move |pong1| {
        call::<Ping, Pong>(addr, Ping("second".into()))
            .map(move |pong2| (pong1, pong2))
    });

let (a, b) = both.run()?;

Use the transport directly

use tarpc_cat::client::call_on;
use tarpc_cat::transport::TcpTransport;

let transport = TcpTransport::connect("127.0.0.1:9000".parse().unwrap()).run()?;
let (response, transport) = call_on::<_, Ping, Pong>(transport, Ping("hello".into())).run()?;
// transport is available for another call
let (response2, _) = call_on::<_, Ping, Pong>(transport, Ping("again".into())).run()?;

Architecture

client.rs      call() and call_on() -- connection-per-request RPC
server.rs      serve() -- bind + accept loop + thread-per-connection
serve.rs       Serve trait -- Clone + Send + 'static, handle returns Io
transport.rs   Transport trait -- linear state-threading, TcpTransport, ChannelTransport
codec.rs       Length-delimited JSON framing over Read/Write
protocol.rs    Wire types: RequestId newtype, Envelope sum type
error.rs       Error enum with hand-rolled Display/Error/From

Building

cargo build

Testing

cargo test

Linting

RUSTFLAGS="-D warnings" cargo clippy

Documentation

cargo doc --no-deps --open

Docs are auto-published to GitHub Pages on push to main via the workflow in .github/workflows/docs.yml. Enable in repo Settings > Pages > Source > GitHub Actions.

License

Licensed under either of

at your option.