8 个版本

0.1.8 2022 年 4 月 1 日
0.1.7 2022 年 3 月 24 日
0.1.6 2022 年 2 月 24 日

#850 in 异步

自定义许可

53KB
1K SLoC

gentian

此 crate 提供了一个证明概念的 proc macro 属性,允许将生成器转换为状态机。此 crate 将作为辅助工具用于 v2ray-rust

动机

Rust 的 asyncawait 非常酷。但当手动实现 Future/Stream/Poll 时,问题出现了。要么放弃一定的性能来扩展 future 的生命周期或手动维护状态机。当 poll 的逻辑逐渐复杂时,状态机的正确性变得更加难以保证。不稳定的 Rust 标准库提供了 generator,但它不适用于解决上述问题。总之,这个 crate 旨在支持在 Rust 控制流子集中使用 yield/yield return。就像 asyncawait 一样,它将被编译成状态机。

示例

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

说明

以下代码不是有效的 Rust 函数,但它展示了生成代码的逻辑。

pub fn poll_read_decrypted<R>(
    &mut self,
    ctx: &mut Context<'_>,
    r: &mut R,
    dst: &mut [u8],
    ) -> Poll<io::Result<(usize)>>
    where
    R: AsyncRead + Unpin,
    {
        co_yield;
        co_return(Poll::Pending);
        if cond1{
            f();
            co_return(Poll::Pending);
            g();
        }else{
            let c=p();
            co_return(Poll::Ready(Ok(c)));
            q();
        }
        'outer: loop {
            println!("Entered the outer loop");

            'inner: loop {
                println!("Entered the inner loop");

                // This would break only the inner loop
                //break;

                // This breaks the outer loop
                break 'outer;
            }

            println!("This point will never be reached");
        }
        loop{
            if cond2{
                return Poll::Ready();
            } else{
                break;
            }
        }
        loop{
            if cond3{
                println!("cond3 is true");
                continue;
            } else{
                break;
            }
        }
        while not_done{
            let c=do1();
            co_return(Poll::Ready(Ok(c)));
            do2();
            if cond4{
                break;
            }
        }
    }

上述代码将被展开为

pub fn poll_read_decrypted<R>(
    &mut self,
    ctx: &mut Context<'_>,
    r: &mut R,
    dst: &mut [u8],
) -> Poll<io::Result<(usize)>>
where
    R: AsyncRead + Unpin,
{
    'genloop: loop {
        match state {
            50 => {
                break 'genloop;
            }
            0 => {
                state = 1;
                return;
            }
            1 => {
                state = 2;
                return Poll::Pending;
            }
            2 => {
                state = 18;
                if cond1 {
                    state = 3;
                    continue 'genloop;
                }
            }
            3 => {
                f();
                state = 4;
                return Poll::Pending;
            }
            4 => {
                g();
                state = 5;
            }
            5 => {
                println!("Entered the outer loop");
                println!("Entered the inner loop");
                state = 9;
                if cond2 {
                    state = 6;
                    continue 'genloop;
                }
            }
            6 => {
                state = 7;
                return Poll::Ready();
            }
            7 => {
                state = 50;
            }
            9 => {
                state = 12;
                if cond3 {
                    state = 10;
                    continue 'genloop;
                }
            }
            10 => {
                println!("cond3 is true");
                state = 9;
            }
            12 => {
                state = 7;
                if not_done {
                    state = 13;
                    continue 'genloop;
                }
            }
            13 => {
                let c = do1();
                state = 14;
                return Poll::Ready(Ok(c));
            }
            14 => {
                do2();
                state = 12;
                if cond4 {
                    state = 7;
                    continue 'genloop;
                }
            }
            18 => {
                let c = p();
                state = 19;
                return Poll::Ready(Ok(c));
            }
            19 => {
                q();
                state = 5;
            }
            _ => {
                break 'genloop;
            }
        }
    }
    return Poll::Pending;
}

上述代码的控制流图(CFG)为 cfg_state

依赖项

~2MB
~44K SLoC