corophage 0.4.0

Algebraic effects for stable Rust
Documentation
use std::marker::PhantomData;

use corophage::prelude::*;

#[effect(Never)]
struct Cancel;

#[effect(())]
pub struct Log<'a>(pub &'a str);

#[effect(String)]
pub struct FileRead(pub String);

#[derive(Default)]
#[effect(S)]
pub struct GetState<S> {
    _marker: PhantomData<S>,
}

#[effect(())]
pub struct SetState<S>(pub S);

async fn cancel(_: &mut State, _c: Cancel) -> Control<Never> {
    Control::cancel()
}

async fn log(_: &mut State, Log(msg): Log<'_>) -> Control<()> {
    println!("LOG: {msg}");
    Control::resume(())
}

async fn file_read(_: &mut State, FileRead(file): FileRead) -> Control<String> {
    println!("Reading file: {file}");
    Control::resume("file content".to_string())
}

#[derive(Debug, PartialEq, Eq)]
struct State {
    x: u64,
}

#[effectful(Cancel, Log<'static>, FileRead, GetState<u64>, SetState<u64>)]
fn my_program() -> () {
    println!("Logging...");
    let () = yield_!(Log("Hello, world!"));

    println!("Reading file...");
    let text = yield_!(FileRead("example.txt".to_string()));
    println!("Read file: {text}");

    let state = yield_!(GetState::default());
    println!("State: {state}");
    yield_!(SetState(state * 2));
    let state = yield_!(GetState::default());
    println!("State: {state}");

    println!("Cancelling...");
    yield_!(Cancel);
    println!("Cancelled!");
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
    let mut state = State { x: 42 };

    let result = my_program()
        .handle(cancel)
        .handle(log)
        .handle(file_read)
        .handle(async |s: &mut State, _g: GetState<u64>| Control::resume(s.x))
        .handle(async |s: &mut State, SetState(x)| {
            s.x = x;
            Control::resume(())
        })
        .run_stateful(&mut state)
        .await;

    assert_eq!(result, Err(Cancelled));
    assert_eq!(state, State { x: 84 });
}