effect-rs 0.1.0

A high-performance, strictly-typed, functional effect system for Rust.
Documentation
use effect_rs::{Effect, Exit, Ref, Runtime};
use std::time::Duration;

#[test]
fn test_ref_update() {
    let rt = Runtime::new();

    let counter = Ref::new(0);

    let program = counter.update(|x| x + 1).flat_map(move |val| {
        assert_eq!(val, 1);
        counter.get()
    });

    let result = rt.block_on(program, ());
    match result {
        Exit::Success(val) => assert_eq!(val, 1),
        Exit::Failure(_) => panic!("Expected success"),
    }
}

#[test]
fn test_ref_concurrent_updates() {
    let rt = Runtime::new();
    let counter = Ref::new(0);

    // Better: Collect handles and join all.
    let counter_p = counter.clone();
    let program = Effect::succeed(Vec::<effect_rs::Fiber<(), i32>>::new())
        .flat_map(move |_| {
            let mut effects = Vec::new();
            for _ in 0..10 {
                let counter = counter_p.clone();
                let eff = Effect::async_effect(move || async {
                    tokio::time::sleep(Duration::from_millis(10)).await;
                    ()
                })
                .flat_map(move |_| counter.update(|x| x + 1))
                .fork();
                effects.push(eff);
            }

            // Fold effects to accumulating fibers
            effects
                .into_iter()
                .fold(Effect::succeed(Vec::new()), |acc, eff| {
                    acc.flat_map(move |mut fibers| {
                        eff.map(move |fiber| {
                            fibers.push(fiber);
                            fibers
                        })
                    })
                })
        })
        .flat_map(|fibers| {
            // Join all fibers
            fibers.into_iter().fold(Effect::succeed(()), |acc, fiber| {
                acc.flat_map(move |_| {
                    Effect::async_effect(move || async move { fiber.join().await })
                        .flat_map(Effect::done)
                        .map(|_| ())
                })
            })
        });

    let result = rt.block_on(program, ());
    match result {
        Exit::Success(_) => {}
        Exit::Failure(_) => panic!("Expected success"),
    }

    // Check final value
    let check = rt.block_on(counter.get(), ());
    match check {
        Exit::Success(val) => assert_eq!(val, 10), // 10 updates
        Exit::Failure(_) => panic!("Expected success"),
    }
}