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
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)
}
}