midi_toolkit/
gen_iter.rs

1use core::iter::{FusedIterator, Iterator};
2use core::marker::Unpin;
3use core::ops::{Coroutine, CoroutineState};
4use core::pin::Pin;
5
6/// an iterator that holds an internal coroutine representing
7/// the iteration state
8#[derive(Copy, Clone, Debug)]
9pub struct GenIter<T>(pub T)
10where
11    T: Coroutine<Return = ()> + Unpin;
12
13impl<T> Iterator for GenIter<T>
14where
15    T: Coroutine<Return = ()> + Unpin,
16{
17    type Item = T::Yield;
18
19    #[inline]
20    fn next(&mut self) -> Option<Self::Item> {
21        match Pin::new(&mut self.0).resume(()) {
22            CoroutineState::Yielded(n) => Some(n),
23            CoroutineState::Complete(()) => None,
24        }
25    }
26}
27
28impl<G> From<G> for GenIter<G>
29where
30    G: Coroutine<Return = ()> + Unpin,
31{
32    #[inline]
33    fn from(gen: G) -> Self {
34        GenIter(gen)
35    }
36}
37
38/// macro to simplify iterator - via - coroutine construction
39///
40/// ```
41/// #![feature(coroutines)]
42///
43/// use gen_iter::gen_iter;
44///
45/// let mut g = gen_iter!({
46///     yield 1;
47///     yield 2;
48/// });
49///
50/// assert_eq!(g.next(), Some(1));
51/// assert_eq!(g.next(), Some(2));
52/// assert_eq!(g.next(), None);
53///
54/// ```
55#[macro_export]
56macro_rules! gen_iter {
57    ($block: block) => {
58        $crate::gen_iter::GenIter(
59            #[coroutine]
60            || $block,
61        )
62    };
63    (move $block: block) => {
64        $crate::gen_iter::GenIter(
65            #[coroutine]
66            move || $block,
67        )
68    };
69}
70
71/// `GenIterReturn<G>` holds a coroutine `G` or the return value of `G`,
72/// `&mut GenIterReturn<G>` acts as an iterator.
73///
74/// Differences with `GenIter<G>`:
75/// 1. able to get return value of a coroutine
76/// 2. safe to call `next()` after coroutine is done without panic
77/// 3. maybe less efficient than `GenIter<G>`
78#[derive(Copy, Clone, Debug)]
79pub struct GenIterReturn<G: Coroutine + Unpin>(Result<G::Return, G>);
80
81impl<G: Coroutine + Unpin> GenIterReturn<G> {
82    #[inline]
83    pub fn new(g: G) -> Self {
84        GenIterReturn(Err(g))
85    }
86
87    #[inline]
88    pub fn is_done(&self) -> bool {
89        self.0.is_ok()
90    }
91
92    #[inline]
93    pub fn return_or_self(self) -> Result<G::Return, Self> {
94        match self.0 {
95            Ok(r) => Ok(r),
96            Err(_) => Err(self),
97        }
98    }
99}
100
101/// Force use `&mut g` as iterator to prevent the code below,
102/// in which return value cannot be got.
103/// ```compile_fail
104/// // !!INVALID CODE!!
105/// # #![feature(coroutines)]
106/// # use gen_iter::gen_iter_return;
107/// let mut g = gen_iter_return!({ yield 1; return "done"; });
108/// for v in g {} // invalid, because `GenIterReturn<G>` is not `Iterator`
109/// let ret = g.return_or_self(); // g is dropped after for loop
110/// ```
111impl<G: Coroutine + Unpin> Iterator for &mut GenIterReturn<G> {
112    type Item = G::Yield;
113
114    #[inline]
115    fn next(&mut self) -> Option<Self::Item> {
116        match self.0 {
117            Ok(_) => None,
118            Err(ref mut g) => match Pin::new(g).resume(()) {
119                CoroutineState::Yielded(y) => Some(y),
120                CoroutineState::Complete(r) => {
121                    self.0 = Ok(r);
122                    None
123                }
124            },
125        }
126    }
127}
128
129/// `GenIterReturn<G>` satisfies the trait `FusedIterator`
130impl<G: Coroutine + Unpin> FusedIterator for &mut GenIterReturn<G> {}
131
132impl<G: Coroutine + Unpin> From<G> for GenIterReturn<G> {
133    #[inline]
134    fn from(g: G) -> Self {
135        GenIterReturn::new(g)
136    }
137}
138
139/// macro to simplify iterator - via - coroutine with return value construction
140/// ```
141/// #![feature(coroutines)]
142///
143/// use gen_iter::gen_iter_return;
144///
145/// let mut g = gen_iter_return!({
146///     yield 1;
147///     yield 2;
148///     return "done";
149/// });
150///
151/// assert_eq!((&mut g).collect::<Vec<_>>(), [1, 2]); // use `&mut g` as an iterator
152/// assert_eq!(g.is_done(), true); // check whether coroutine is done
153/// assert_eq!((&mut g).next(), None); // safe to call `next()` after done
154/// assert_eq!(g.return_or_self().ok(), Some("done")); // get return value of coroutine
155/// ```
156#[macro_export]
157macro_rules! gen_iter_return {
158    ($block: block) => {
159        $crate::gen_iter::GenIterReturn::new(
160            #[coroutine]
161            || $block,
162        )
163    };
164    (move $block: block) => {
165        $crate::gen_iter::GenIterReturn::new(
166            #[coroutine]
167            move || $block,
168        )
169    };
170}
171
172#[cfg(test)]
173mod tests {
174    use super::GenIterReturn;
175
176    #[test]
177    fn gen_iter_works() {
178        let mut g = gen_iter!({
179            yield 1;
180            yield 2;
181        });
182
183        assert_eq!(g.next(), Some(1));
184        assert_eq!(g.next(), Some(2));
185        assert_eq!(g.next(), None);
186    }
187
188    #[test]
189    fn gen_iter_macro() {
190        let mut g = gen_iter!(move {
191            yield 1;
192            yield 2;
193        });
194
195        assert_eq!(g.next(), Some(1));
196        assert_eq!(g.next(), Some(2));
197        assert_eq!(g.next(), None);
198    }
199
200    /// test `new` and all instance method,
201    /// and show that it won't panic when call `next()` even exhausted.
202    #[test]
203    fn gen_iter_return_works() {
204        let mut g = GenIterReturn::new(
205            #[coroutine]
206            || {
207                yield 1;
208                "done"
209            },
210        );
211
212        assert_eq!((&mut g).next(), Some(1));
213        assert!(!g.is_done());
214
215        g = match g.return_or_self() {
216            Ok(_) => panic!("coroutine is done but should not"),
217            Err(g) => g,
218        };
219
220        assert_eq!((&mut g).next(), None);
221        assert!(g.is_done());
222
223        assert_eq!((&mut g).next(), None); // it won't panic when call `next()` even exhausted.
224
225        assert_eq!(g.return_or_self().ok(), Some("done"));
226    }
227
228    #[test]
229    fn from_coroutine() {
230        let mut g = GenIterReturn::from(
231            #[coroutine]
232            || {
233                yield 1;
234                "done"
235            },
236        );
237
238        assert_eq!((&mut g).next(), Some(1));
239        assert_eq!((&mut g).next(), None);
240
241        assert!(g.is_done());
242        assert_eq!(g.return_or_self().ok(), Some("done"));
243    }
244
245    /// normal usage using macro `gen_iter_return`
246    #[test]
247    fn macro_usage() {
248        let mut g = gen_iter_return!(move {
249            yield 1;
250            yield 2;
251            return "done";
252        });
253
254        let (mut sum, mut count) = (0, 0);
255        for y in &mut g {
256            sum += y;
257            count += 1;
258        }
259        assert_eq!((sum, count), (3, 2));
260
261        assert!(g.is_done());
262        assert_eq!(g.return_or_self().ok(), Some("done"));
263    }
264}