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
37    // #[inline]
38    fn resume(mut self: Pin<&mut Self>, value: R) -> GeneratorState<Self::Yield, Self::Return> {
39        G::resume(Pin::new(&mut **self), value)
40    }
41}
42
43#[cfg(feature = "std")]
44impl<R, G> Generator<R> for core::boxed::Box<G>
45where
46    G: Generator<R> + ?Sized + Unpin,
47{
48    type Return = G::Return;
49    type Yield = G::Yield;
50
51    // #[inline]
52    fn resume(mut self: Pin<&mut Self>, value: R) -> GeneratorState<Self::Yield, Self::Return> {
53        G::resume(Pin::new(&mut **self), value)
54    }
55}
56
57impl<R, P> Generator<R> for Pin<P>
58where
59    P: DerefMut<Target: Generator<R>>,
60{
61    type Return = <P::Target as Generator<R>>::Return;
62    type Yield = <P::Target as Generator<R>>::Yield;
63
64    fn resume(self: Pin<&mut Self>, value: R) -> GeneratorState<Self::Yield, Self::Return> {
65        <P::Target as Generator<R>>::resume(self.as_deref_mut(), value)
66    }
67}
68
69/// To build generator, pass an async function with a parameter:
70/// First parameter is Yielder -- context handle to yield generated item
71pub fn generator<F, Resume, Yield, Return>(
72    f: F,
73) -> impl Generator<Resume, Yield = Yield, Return = Return>
74where
75    // F: AsyncFnOnce(Yielder<Yield, Resume>, Resume) -> Return,
76    // but this has to be expressed in such ugly form
77    for<'a> F: FnOnceOutput<Yielder<'a, Yield, Resume>, Out: Future<Output = Return>>,
78{
79    fut_generator::fut_generator(f)
80}
81
82#[cfg(test)]
83mod tests {
84
85    use crate::core::pin::pin;
86
87    use crate::{ext::GeneratorIterator, *};
88
89    fn squares(n: usize) -> impl Generator<Yield = usize, Return = ()> {
90        generator(async move |mut this: Yielder<_, _>| {
91            for x in 1..=n {
92                yield_!(this, x * x);
93            }
94        })
95    }
96
97    fn tok_generator<'a>(s: &'a str) -> impl Generator<Yield = &'a str, Return = ()> {
98        generator(async move |mut this: Yielder<_, _>| {
99            for tok in s.split_whitespace() {
100                yield_!(this, tok);
101            }
102        })
103    }
104
105    #[test]
106    fn test_squares() {
107        let g = pin!(squares(5));
108        let mut g = g.into_iter();
109        assert_eq!(g.next(), Some(1));
110        assert_eq!(g.next(), Some(4));
111        assert_eq!(g.next(), Some(9));
112        assert_eq!(g.next(), Some(16));
113        assert_eq!(g.next(), Some(25));
114        assert_eq!(g.next(), None);
115    }
116
117    #[test]
118    fn test_tokens() {
119        let g = pin!(tok_generator("hello world"));
120        let mut g = g.into_iter();
121        assert_eq!(g.next(), Some("hello"));
122        assert_eq!(g.next(), Some("world"));
123        assert_eq!(g.next(), None);
124    }
125}