Hello everyone. I would like to share something I've been working on with you today. I think I have made a generalized version of a stackful coroutine (example crates would be corosensei, may or its generator library) by modifying the aforementioned corosensei library (thanks to @Amanieu). I've called it a fiber for people that are familiar with such term, and I thought it more closely suited the new concept.
It is a single type Fiber
which would represent a lightweight thread of execution. There are two functions: a constructor and the switch
method, which basically swaps current execution context with the execution context of a fiber. This implies that you can simply have a fiber, even if it executes the main function. You can check out its entire documentation published via github pages.
So here is an example:
use corosensei::Fiber;
struct Arg {
exec: Fiber<Option<Yield>>,
i: i32,
}
struct Yield {
exec: Fiber<Arg>,
i: i32,
}
impl Arg {
fn new(exec: Fiber<Option<Yield>>, input: i32) -> Self {
Self { exec, i: input }
}
}
fn main() {
println!("[main] creating execution");
let mut exec = Fiber::new(|Arg { mut exec, i }| {
println!("[execution] execution started with input {}", i);
for mut i in 0..5 {
println!("[execution] yielding {}", i);
Arg { exec, i } = exec.switch(move |exec| Some(Yield { exec, i }));
println!("[execution] got {} from parent", i)
}
println!("[execution] exiting execution");
(exec, |_| None)
});
let mut counter = 100;
loop {
println!("[main] resuming execution with argument {}", counter);
match exec.switch(move |exec| Arg::new(exec, counter)) {
Some(Yield { exec: new, i }) => {
exec = new;
println!("[main] got {:?} from execution", i)
}
None => break,
}
counter += 1;
}
println!("[main] exiting");
}
And it prints:
[main] creating execution
[main] resuming execution with argument 100
[execution] execution started with input 100
[execution] yielding 0
[main] got 0 from execution
[main] resuming execution with argument 101
[execution] got 101 from parent
[execution] yielding 1
[main] got 1 from execution
[main] resuming execution with argument 102
[execution] got 102 from parent
[execution] yielding 2
[main] got 2 from execution
[main] resuming execution with argument 103
[execution] got 103 from parent
[execution] yielding 3
[main] got 3 from execution
[main] resuming execution with argument 104
[execution] got 104 from parent
[execution] yielding 4
[main] got 4 from execution
[main] resuming execution with argument 105
[execution] got 105 from parent
[execution] exiting execution
[main] exiting