#async-trait #middleware #async #traits #monads #future

async-middleware

Simple async monad(ish) middleware in Rust using tuples and async trait transforms

2 releases (1 stable)

1.0.0 Jul 21, 2022
0.1.0 Jul 21, 2022

#1891 in Asynchronous

MIT license

18KB
360 lines

async-middleware

latest version documentation license

Provides a way to pipe a number of async middleware functions together that is type safe between each of the input -> output. This allows you to combine A -> B -> C similar to a monad but not quite as formal. Although, you could in theory use this as a monad library but it isn't really setup to handle identity, maps, unwraps, fors (a more formal and idiomatic approach https://medium.com/swlh/monad-interface-rust-edition-bd6486b93607) would be better but there are some things missing like async closures that would make this easier. Things like wrapping an existing async function is very difficult due to the lack of async closures in rust. In any case, this provides a simple middleware chaining.

Examples

// import * as this provides all the trait implementations by default
use async_middleware::*;

async fn producer() -> i32 {
    3
}

async fn multipler(i: i32) -> i32 {
    i * 32
}

async fn stringer(i: i32) -> String {
    i.to_string()
}

async fn logger(s: String) {
    println!("{}", s);
}

async fn log_nums(i: i32) {
    println!("{}", i);
}

#[test]
fn test_piper_tuple() {
    pipe((producer, log_nums));
    pipe((producer, stringer, logger));
    pipe((producer, multipler, stringer, logger));
    pipe((multipler, multipler, multipler));
    pipe((multipler, multipler, stringer));

    // alternative syntax
    (producer, log_nums).pipe();
    (producer, stringer, logger).pipe();
    (producer, multipler, stringer, logger).pipe();
    (multipler, multipler, multipler).pipe();
    (multipler, multipler, stringer).pipe();

    // pipe different pipes
    let m = (producer, multipler).pipe();
    let m = (m, multipler).pipe();
    let m = pipe((m, stringer));

    assert_eq!(String::from("3072"), m.call(()).await);
}

#[async_std::test]
async fn test_piper_tuple_inputs() {
    let m = (multipler, multipler, stringer).pipe();
    assert_eq!(String::from("1024"), m.call(1).await);
    assert_eq!(String::from("2048"), m.call(2).await);
    assert_eq!(String::from("3072"), m.call(3).await);
}

#[test]
fn test_convert_transform() {
    convert(multipler, stringer);
    convert(multipler, multipler);
}

#[test]
fn test_source_transform() {
    convert(producer, multipler);
}

#[test]
fn test_source_sink() {
    convert(producer, log_nums);
}

#[test]
fn test_transform() {
    convert(convert(producer, multipler), stringer);
}

#[test]
fn test_transform_source_transform_sink() {
    convert(convert(convert(producer, multipler), stringer), logger);
}

Dependencies

~310–760KB
~18K SLoC