doc: gentian - Rust
repo: GitHub - darsvador/generator: This crate provides a proof-of-concept proc macro attribute that allows transforming generators to state machines.
This crate provides a proof-of-concept proc macro attribute that allows transforming generators to state machines.
Motivation
Rust's async and await are cool. But when you manually implement Future
/Stream
, the problem comes. Either give up a certain performance to extend the lifetime of Future
and poll it or manually maintain the state machine. When the logic of the poll is gradually complicated, the correctness of the state machine becomes more difficult to guarantee. Unstable Rust's standard library provides generator
but it is not suitable for solving the above problems. In summary, this crate is to support using yield/yield return in a subset of rust's control flow. And, same as async and await, it will be compiled into state machines.
Example
#[gentian]
#[gentian_attr(ret_val=Err(ErrorKind::UnexpectedEof.into()).into())]
pub fn poll_write_encrypted<W>(
&mut self,
ctx: &mut Context<'_>,
w: &mut W,
data: &[u8],
) -> Poll<io::Result<usize>>
where
W: AsyncWrite + Unpin,
{
loop {
if data.len() == 0 {
return Poll::Ready(Ok(0));
}
let mut minimal_data_to_write =
cmp::min(CHUNK_SIZE - self.security.overhead_len(), data.len());
let data = &data[..minimal_data_to_write];
self.encrypted_buffer(data);
loop {
self.write_res = self.write_data(w, ctx);
if self.write_res.is_ready() {
break;
}
co_yield(Poll::Pending);
}
self.buffer.clear();
co_yield(std::mem::replace(&mut self.write_res, Poll::Pending));
}
}
The above code would be expanded as:
// Recursive expansion of gentian! macro
// ======================================
pub fn poll_write_encrypted<W>(&mut self,ctx: &mut Context< '_> ,w: &mut W,data: &[u8],) -> Poll<io::Result<usize> >where W:AsyncWrite+Unpin,{
'genloop:loop {
match self.state {
23 => {
break 'genloop;
}
0 => {
self.state = 4;
if data.len()==0 {
self.state = 2;
continue 'genloop;
}
}
2 => {
self.state = 3;
return Poll::Ready(Ok(0));
}
3 => {
break 'genloop;
}
4 => {
let mut minimal_data_to_write = cmp::min(CHUNK_SIZE-self.security.overhead_len(),data.len());
let data = &data[..minimal_data_to_write];
self.encrypted_buffer(data);
self.state = 5;
}
5 => {
self.write_res = self.write_data(w,ctx);
self.state = 8;
if self.write_res.is_ready(){
self.state = 6;
continue 'genloop;
}
}
6 => {
self.buffer.clear();
self.state = 0;
return std::mem::replace(&mut self.write_res,Poll::Pending);
}
8 => {
self.state = 5;
return Poll::Pending;
}
_ => {
break 'genloop;
}
}
}return Err(ErrorKind::UnexpectedEof.into()).into();
}