Expand description
gentian is a proc macro that transforms generators to state machines.
Currently it supports loop statements, while statements, if statements, and the extended syntax for using co_yield
and co_return
and return
in these statements.
gentian_attr
attribute of a function
It has two kinds of parameters,
state
represents the state currently used to maintain the automaton.ret_val
represents the default return value of the function, which is usually used for the result returned by calling again after the state machine ends.
co_yield
or co_return
statement
This divides into three logical steps:
co_yield
orco_return
save the current state of the coroutine.- The resume point is defined immediately following the statement.
- Same as rust
return
semantics, it returns from the function immediately.
return
statement
This type of statement divides into two logical steps:
return
sets the coroutine state to indicate termination.- Same as rust
return
semantics, it returns from the function immediately. - When the function is called again, it returns the default return value (
ret_val
), or does nothing which means the function has no return value.
Example
The following code demonstrates the use of generators with and without a return value.
use gentian::gentian;
#[cfg(test)]
struct MyGenerator {
my_state_1: usize,
pub my_state_2: usize,
pub num: u32,
pub num1: u32,
}
#[cfg(test)]
impl MyGenerator {
pub fn new() -> MyGenerator {
MyGenerator {
my_state_1: 0,
my_state_2: 0,
num: 0,
num1: 0,
}
}
#[gentian]
#[gentian_attr(state=self.my_state_1)]
pub fn test_simple(&mut self) {
loop {
println!("Hello, ");
//co_yield;
while self.num1 < 99 {
println!("Generator{}", self.num1);
self.num1 += 1;
co_yield;
}
return;
}
}
// state_name , return_default_value
#[gentian]
#[gentian_attr(state=self.my_state_2,ret_val=0u32)]
pub fn get_odd(&mut self) -> u32 {
loop {
if self.num % 2 == 1 {
co_yield(self.num);
}
self.num += 1;
}
}
}
#[test]
fn test_generator_proc_macro() {
let mut gen = MyGenerator::new();
gen.test_simple(); // print Hello,
for _ in 0..200 {
gen.test_simple(); // only print 99 times `Generator`
}
gen.test_simple(); // print nothing
assert_eq!(gen.num1, 99);
for i in (1u32..1000).step_by(2) {
assert_eq!(gen.get_odd(), i);
}
}