Skip to main content

generator_light/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3mod core {
4    #[cfg(not(feature = "std"))]
5    pub use core::*;
6    #[cfg(feature = "std")]
7    pub use std::*;
8}
9
10mod fut_generator;
11
12pub(crate) mod fn_trait;
13pub(crate) mod gen_context;
14
15pub mod ext;
16pub mod generator_state;
17
18use core::{ops::DerefMut, pin::Pin};
19
20use crate::fn_trait::FnOnceOutput;
21pub use crate::gen_context::Yielder;
22pub use crate::generator_state::GeneratorState;
23
24pub trait Generator<R = ()> {
25    type Yield;
26    type Return;
27    fn resume(self: Pin<&mut Self>, value: R) -> GeneratorState<Self::Yield, Self::Return>;
28}
29
30impl<R, G> Generator<R> for &mut G
31where
32    G: Generator<R> + ?Sized + Unpin,
33{
34    type Return = G::Return;
35    type Yield = G::Yield;
36    fn resume(mut self: Pin<&mut Self>, value: R) -> GeneratorState<Self::Yield, Self::Return> {
37        G::resume(Pin::new(&mut **self), value)
38    }
39}
40
41#[cfg(feature = "std")]
42impl<R, G> Generator<R> for core::boxed::Box<G>
43where
44    G: Generator<R> + ?Sized + Unpin,
45{
46    type Return = G::Return;
47    type Yield = G::Yield;
48    fn resume(mut self: Pin<&mut Self>, value: R) -> GeneratorState<Self::Yield, Self::Return> {
49        G::resume(Pin::new(&mut **self), value)
50    }
51}
52
53impl<R, P> Generator<R> for Pin<P>
54where
55    P: DerefMut<Target: Generator<R>>,
56{
57    type Return = <P::Target as Generator<R>>::Return;
58    type Yield = <P::Target as Generator<R>>::Yield;
59
60    fn resume(self: Pin<&mut Self>, value: R) -> GeneratorState<Self::Yield, Self::Return> {
61        <P::Target as Generator<R>>::resume(self.as_deref_mut(), value)
62    }
63}
64
65/// To build generator, pass an async function with two parameters:
66/// First parameter is Yielder -- context handle to yield generated item
67/// The second parameter -- it's a Resume value passed
68///     to the Generator::resume() method at the first time
69pub const fn generator<F, Resume, Yield, Return>(
70    f: F,
71) -> impl Generator<Resume, Yield = Yield, Return = Return>
72where
73    // F: AsyncFnOnce(Yielder<Yield, Resume>, Resume) -> Return,
74    // but this has to be expressed in such ugly form
75    for<'a> F: FnOnceOutput<Yielder<'a, Yield, Resume>, Resume, Out: Future<Output = Return>>,
76{
77    fut_generator::Generator::new(f)
78}
79
80#[cfg(test)]
81mod tests {
82
83    use crate::core::pin::pin;
84
85    use crate::{ext::GeneratorIterator, *};
86
87    fn squares(n: usize) -> impl Generator<Yield = usize, Return = ()> {
88        generator(async move |mut this: Yielder<_, _>, _| {
89            for x in 1..=n {
90                yield_!(this, x * x);
91            }
92        })
93    }
94
95    fn tok_generator<'a>(s: &'a str) -> impl Generator<Yield = &'a str, Return = ()> {
96        generator(async move |mut this: Yielder<_, _>, _| {
97            for tok in s.split_whitespace() {
98                yield_!(this, tok);
99            }
100        })
101    }
102
103    #[test]
104    fn test_squares() {
105        let g = pin!(squares(5));
106        let mut g = g.into_iter();
107        assert_eq!(g.next(), Some(1));
108        assert_eq!(g.next(), Some(4));
109        assert_eq!(g.next(), Some(9));
110        assert_eq!(g.next(), Some(16));
111        assert_eq!(g.next(), Some(25));
112        assert_eq!(g.next(), None);
113    }
114
115    #[test]
116    fn test_tokens() {
117        let g = pin!(tok_generator("hello world"));
118        let mut g = g.into_iter();
119        assert_eq!(g.next(), Some("hello"));
120        assert_eq!(g.next(), Some("world"));
121        assert_eq!(g.next(), None);
122    }
123}