algoroutine 0.1.7

Light-weight algebraic effect(algebraic goroutine) in Rust
Documentation
#![feature(coroutines)]
#![feature(coroutine_trait)]
#![feature(stmt_expr_attributes)]

use std::{
    marker::PhantomData,
    ops::{Coroutine, CoroutineState},
    pin::Pin,
};

use algoroutine::{
    go,
    handler::{Consumer, OneStep, SyncConsumer},
};

fn main() {
    let prepare = #[coroutine]
    |_: Option<i32>| {
        go!(Log("preparing".into()) => Effect);
        return ResultCode(0);
    };

    let logic = #[coroutine]
    |_: Option<i32>| {
        go!(Log("start".into()) => Effect);

        go!(State::Set(Some(9)));
        let s = go!(State::Get);
        go!(Log(format!("Got {:?}", s)));

        let res = go!(prepare, None);
        if !res.is_ok() {
            go!(Log(format!("error code: {}", res.0)));
        }
        return res;
    };

    let handler: Handler<Option<i32>> = Handler::new();
    let mut consumer = SyncConsumer::from(handler);
    let ans = consumer.consume(logic, None);
    dbg!(ans);
}

struct Log(String);
enum State<S> {
    Get,
    Set(Option<S>),
}

enum Effect<S> {
    Log(Log),
    State(State<S>),
}

impl<S> From<Log> for Effect<S> {
    fn from(value: Log) -> Self {
        Effect::Log(value)
    }
}

impl<S> From<State<S>> for Effect<S> {
    fn from(value: State<S>) -> Self {
        Effect::State(value)
    }
}

#[derive(Debug)]
struct ResultCode(i32);

impl ResultCode {
    pub fn is_ok(&self) -> bool {
        self.0 == 0
    }
}

impl From<Option<i32>> for ResultCode {
    fn from(value: Option<i32>) -> Self {
        ResultCode(value.unwrap_or(0))
    }
}

struct Handler<I> {
    state: Option<i32>,
    _marker: PhantomData<I>,
}

impl<I> Handler<I> {
    fn new() -> Self {
        Self {
            state: None,
            _marker: PhantomData,
        }
    }
}

pub trait Project<E> {
    fn project(self) -> Option<E>;
}

impl<S> Project<S> for Option<S> {
    fn project(self) -> Option<S> {
        self
    }
}

impl<I> algoroutine::handler::Step<Effect<i32>, I, ResultCode> for Handler<I>
where
    I: From<Option<i32>> + Project<i32>,
{
    fn step<F>(&mut self, continuation: Pin<&mut F>, pre: I) -> OneStep<I, ResultCode>
    where
        F: Coroutine<I, Yield = Effect<i32>, Return = ResultCode>,
    {
        let mut pinned = Box::pin(continuation);
        let state = pinned.as_mut().resume(pre);
        match state {
            CoroutineState::Complete(n) => OneStep::Return(n),
            CoroutineState::Yielded(Effect::Log(Log(msg))) => {
                println!("{msg}?");
                OneStep::Yield(I::from(Some(0)))
            }
            CoroutineState::Yielded(Effect::State(s)) => match s {
                State::Get => OneStep::Yield(I::from(self.state.clone())),
                State::Set(s) => {
                    self.state = s;
                    OneStep::Yield(I::from(None))
                }
            },
        }
    }
}