Function bicoro::send

source ·
pub fn send<'a, I, O>(o: O) -> Coroutine<'a, I, O, ()>
Expand description

Yields a value to the executor

This pauses until the executor uses it

use bicoro::*;
let co :Coroutine<(),&str,()> = send("hello");
Examples found in repository?
examples/fsm-input-driven.rs (line 29)
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
pub fn needs_input() -> Coroutine<'static, Input, Output, turnstile::Input> {
    // this is a recursive function. Any easy way to express a loop
    fn loop_(input: Input) -> Coroutine<'static, Input, Output, turnstile::Input> {
        match input.0.trim() {
            "push" => result(turnstile::Input::Push),
            "coin" => result(turnstile::Input::Coin),
            other => {
                let error = format!("Turnstile: 'I don't understand {}' \r\n", other);
                let prompt = "What do you try instead?".to_string();

                send(Output::StdErr(error))
                    .and_then(|()| send(Output::StdOut(prompt)))
                    .and_then(|()| send(Output::Flush))
                    .and_then(|()| receive())
                    .and_then(loop_) // we loop if it's invalid, we need to get that input for the turnstile!
            }
        }
    }
    // kicks off the loop
    let initial_prompt = format!("What do you do?: ");
    send(Output::StdOut(initial_prompt))
        .and_then(|()| send(Output::Flush))
        .and_then(|()| receive())
        .and_then(loop_)
}

/// Simply display the transition
pub fn on_output(o: turnstile::Output) -> Coroutine<'static, Input, Output, ()> {
    send(Output::StdOut(format!(
        "Turnstile responds with: '{}'\r\n",
        o.to_string()
    )))
}

pub fn main() {
    let turnstile = create();

    // we can run a child routine inside this routine, with the provided functiosn to convert
    // the inputs and outputs. Result remains the same.
    let mut composed = send(Output::StdOut(
        "You are stopped by a turnstile!\r\n".to_string(),
    ))
    .and_then(|()| send(Output::Flush))
    .and_then(|()| subroutine(needs_input, on_output, turnstile));

    // This is the main loop. Notice it's really only concerned
    // with handling inputs and outputs of the termninal.
    loop {
        match run_step(composed) {
            StepResult::Done(_) => unreachable!(), // just for this case, as its a non-exiting coroutine
            StepResult::Yield { output, next } => {
                match output {
                    Output::StdOut(o) => print!("{}", o),
                    Output::StdErr(e) => print!("{}", e),
                    Output::Flush => std::io::stdout().flush().unwrap(),
                }
                composed = *next;
            }
            StepResult::Next(fun) => {
                // Prompts only appear when needed here
                let mut buf = String::new();
                std::io::stdin().read_line(&mut buf).unwrap();
                let input = Input(buf);
                composed = fun(input);
            }
        }
    }
}
More examples
Hide additional examples
examples/turnstile/mod.rs (line 38)
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
    fn on_input<'a>(state: State, input: Input) -> Coroutine<'a, Input, Output, Never> {
        // coroutine section that sends the output, and sets the next state
        let next = match (state, input) {
            (State::Locked, Input::Coin) => m! {
                send(Output::Unlocked);
                result(State::Unlocked)
            },
            (State::Locked, Input::Push) => m! {
                send(Output::NoChange);
                result(State::Locked)
            },
            (State::Unlocked, Input::Coin) => m! {
                send(Output::NoChange);
                result(State::Unlocked)
            },
            (State::Unlocked, Input::Push) => m! {
                send(Output::Locked);
                result(State::Locked)
            },
        };

        // read an input, and call on_input again
        m! {
            state <- next;
            input <- receive();
            on_input(state, input)
        }
    }