Crate mpsc_requests

source ·
Expand description

mpsc_requests is a small library built on top of std::sync::mpsc but with the addition of the consumer responding with a message to the producer. Since the producer no longer only produces and the consumer no longer only consumes, the producer is renamed to requester and the consumer is renamed to responder.

mpsc_requests is small and lean by only building on top of the rust standard library

A perfect use-case for this library is single-threaded databases which need to be accessed from multiple threads (such as SQLite)

Echo example

use std::thread;
use mpsc_requests::channel;

type RequestType = String;
type ResponseType = String;
let (responder, requester) = channel::<RequestType, ResponseType>();
thread::spawn(move || {
    responder.poll_loop(|req| req);
});
let msg = String::from("Hello");
let res = requester.send_req(msg.clone());
assert_eq!(res, msg);

Database example

use std::thread;
use std::collections::HashMap;
use mpsc_requests::channel;
#[derive(Debug)]
enum Errors {
    NoSuchPerson,
}
enum Commands {
    CreateUser(String, u64),
    GetUser(String)
}
#[derive(Debug)]
enum Responses {
    Success(),
    GotUser(u64)
}
let (responder, requester) = channel::<Commands, Result<Responses, Errors>>();
thread::spawn(move || {
    let mut age_table : HashMap<String, u64> = HashMap::new();
    loop {
        responder.poll(|request| {
            match request {
                Commands::CreateUser(user, age) => {
                    age_table.insert(user, age);
                    Ok(Responses::Success())
                },
                Commands::GetUser(user) => {
                    match age_table.get(&user) {
                        Some(age) => Ok(Responses::GotUser(age.clone())),
                        None => Err(Errors::NoSuchPerson)
                    }
                }
            }
        });
    }
});

// Create user
let username = String::from("George");
requester.send_req(Commands::CreateUser(username.clone(), 64)).unwrap();
// Fetch user and verify data
let command = Commands::GetUser(username.clone());
match requester.send_req(command).unwrap() {
    Responses::GotUser(age) => assert_eq!(age, 64),
    _ => panic!("Wrong age")
}
// Try to fetch non-existing user
let username = String::from("David");
let command = Commands::GetUser(username);
let result = requester.send_req(command);
assert!(result.is_err());

Structs

Requester has a connection to a Responder which it can send requests to
A responder listens to requests of a specific type and responds back to the requester

Enums

Errors which can occur when a responder handles a request

Functions

Create a channel between one requester and one responder. The requester can be cloned to be able to do requests to the same responder from multiple threads.