#rust #generator #pin #coroutine
generator nightly flags #
#![feature(generators, generator_trait)]
generator
trait
#
源码 https://github.com/rust-lang/rust/blob/master/library/core/src/ops/generator.rs
pub enum GeneratorState<Y, R> {
Yielded(Y),
Complete(R),
}
pub trait Generator<R = ()> {
type Yield;
type Return;
fn resume(self: Pin<&mut Self>, resume: R) -> GeneratorState<Self::Yield, Self::Return>;
}
使用 #
fn test_g1() {
let mut g = || {
yield "hi";
()
};
while let GeneratorState::Yielded(value) = Pin::new(&mut g).resume(()) {
println!("value: {value}");
}
}
上面的例子并没提现 resume 时候的参数。参考下面的例子:
fn test_g2() {
// return type 用到了 never_type, #![feature(never_type)]
fn map<T, U>(mut f: impl FnMut(T) -> U) -> impl Generator<T, Yield=U, Return=!> + Unpin {
move |mut t| loop {
t = yield f(t);
}
}
let mut gen = Box::pin(map(|x| x * 2));
dbg!(gen.as_mut().resume(1));
dbg!(gen.as_mut().resume(2));
dbg!(gen.as_mut().resume(3));
}
在自己的类型上实现 generator
trait
#
fn test_gen_impl() {
enum GeneratorA {
Enter,
Counter { state: u8 },
Exit,
}
impl GeneratorA {
fn new() -> Self { GeneratorA::Enter } // created in `Enter` state
}
impl ! Unpin for GeneratorA {}
// 类型参数 R 实例到 u32 上
impl Generator<u32> for GeneratorA {
type Yield = u8;
type Return = ();
fn resume(mut self: Pin<&mut Self>, limit: u32) -> GeneratorState<Self::Yield, Self::Return> {
let this = unsafe { self.get_unchecked_mut() };
match *this {
GeneratorA::Enter => {
*this = GeneratorA::Counter { state: 0 };
GeneratorState::Yielded(0)
}
GeneratorA::Counter { state } => {
if state == limit as u8 {
GeneratorState::Complete(())
} else {
*this = GeneratorA::Counter { state: state + 1 };
GeneratorState::Yielded(state + 1)
}
}
GeneratorA::Exit => {
panic!("already exited")
}
}
}
}
let mut g1 = Box::pin(GeneratorA::new());
println!("yield {:?}", g1.as_mut().resume(3));
println!("yield {:?}", g1.as_mut().resume(3));
println!("yield {:?}", g1.as_mut().resume(3));
println!("yield {:?}", g1.as_mut().resume(3));
println!("yield {:?}", g1.as_mut().resume(3));
println!("yield {:?}", g1.as_mut().resume(3));
let mut g2 = Box::pin(GeneratorA::new());
while let GeneratorState::Yielded(num) = g2.as_mut().resume(7) {
println!("num: {num}");
}
}
实现 #
查看 HIR 代码, cargo rustc -- -Z unpretty=hir
或者在 playground 中查看
HIR 可以将其理解为 AST 的另一中表示方式,主要是将语法糖做了转换 MIR HIR 被转换成了更低级的结构,生命周期在这里会被抹除
fn main() {}
#[inline(never)]
async fn foo() -> usize { 5 }
async fn bar() -> usize { foo().await }
ResumeTy
来自 https://github.com/rust-lang/rust/blob/master/library/core/src/future/mod.rs (TODO)