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.
co_await
statement
It’s a syntax sugar for co_yield
or co_return
with std::task::Poll
.
ⓘ
co_await(some_poll_func());
is equivalent to
ⓘ
loop{
let tmp=some_poll_func();
if tmp.is_ready(){
break;
}
co_yield(Poll::Pending);
}
This divides into two logical steps:
co_await
save the current state of the coroutine.- The resume point is defined immediately following the statement and if and only if the waited poll function is ready.
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);
}
}