async_gen/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3
4pub use futures_core;
5use pin_project_lite::pin_project;
6use std::{
7    cell::UnsafeCell,
8    future::Future,
9    pin::Pin,
10    sync::Arc,
11    task::{Context, Poll},
12};
13
14/// The result of a generator resumption.
15///
16/// This enum is returned from the `Generator::resume` method and indicates the
17/// possible return values of a generator. Currently this corresponds to either
18/// a suspension point (`Yielded`) or a termination point (`Complete`).
19#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
20pub enum GeneratorState<Y, R> {
21    /// The generator suspended with a value.
22    ///
23    /// This state indicates that a generator has been suspended, and typically
24    /// corresponds to a `yield` statement. The value provided in this variant
25    /// corresponds to the expression passed to `yield` and allows generators to
26    /// provide a value each time they yield.
27    Yielded(Y),
28
29    /// The generator completed with a return value.
30    ///
31    /// This state indicates that a generator has finished execution with the
32    /// provided value. Once a generator has returned `Complete` it is
33    /// considered a programmer error to call `resume` again.
34    Complete(R),
35}
36
37/// Generators, also commonly referred to as coroutines.
38pub trait AsyncGenerator {
39    /// The type of value this generator yields.
40    ///
41    /// This associated type corresponds to the `yield` expression and the
42    /// values which are allowed to be returned each time a generator yields.
43    /// For example an iterator-as-a-generator would likely have this type as
44    /// `T`, the type being iterated over.
45    type Yield;
46
47    /// The type of value this generator returns.
48    ///
49    /// This corresponds to the type returned from a generator either with a
50    /// `return` statement or implicitly as the last expression of a generator
51    /// literal. For example futures would use this as `Result<T, E>` as it
52    /// represents a completed future.
53    type Return;
54
55    /// Resumes the execution of this generator.
56    ///
57    /// This function will resume execution of the generator or start execution
58    /// if it hasn't already. This call will return back into the generator's
59    /// last suspension point, resuming execution from the latest `yield`. The
60    /// generator will continue executing until it either yields or returns, at
61    /// which point this function will return.
62    ///
63    /// # Return value
64    ///
65    /// The `GeneratorState` enum returned from this function indicates what
66    /// state the generator is in upon returning. If the `Yielded` variant is
67    /// returned then the generator has reached a suspension point and a value
68    /// has been yielded out. Generators in this state are available for
69    /// resumption at a later point.
70    ///
71    /// If `Complete` is returned then the generator has completely finished
72    /// with the value provided. It is invalid for the generator to be resumed
73    /// again.
74    ///
75    /// # Panics
76    ///
77    /// This function may panic if it is called after the `Complete` variant has
78    /// been returned previously. While generator literals in the language are
79    /// guaranteed to panic on resuming after `Complete`, this is not guaranteed
80    /// for all implementations of the `Generator` trait.
81    fn poll_resume(
82        self: Pin<&mut Self>,
83        cx: &mut Context<'_>,
84    ) -> Poll<GeneratorState<Self::Yield, Self::Return>>;
85}
86
87struct Inner<Y> {
88    data: UnsafeCell<Option<Y>>,
89}
90
91unsafe impl<Y: Send + Sync> Sync for Inner<Y> {}
92
93#[doc(hidden)]
94pub struct Yield<Y = ()> {
95    inner: Arc<Inner<Y>>,
96}
97
98#[doc(hidden)]
99pub struct Return<T = ()>(T);
100
101impl<Y> Yield<Y> {
102    /// Same as `yield` keyword.
103    ///
104    /// It pauses execution and the value is returned to the generator's caller.
105    pub async fn yield_(&mut self, val: Y) {
106        // SEAFTY: this function is marked with `&mut self`
107        //
108        // And `Yield<()>` can't escape from this closure:
109        //
110        // gen(|y: Yield<()>| async {
111        //     // `y` can't escape from this closure. and owned by `async` body
112        //     y.return_(())
113        // });
114        unsafe {
115            *self.inner.data.get() = Some(val);
116        }
117        std::future::poll_fn(|_| {
118            if unsafe { (*self.inner.data.get()).is_some() } {
119                return Poll::Pending;
120            }
121            Poll::Ready(())
122        })
123        .await
124    }
125
126    #[inline]
127    pub fn return_<R>(self, _v: R) -> Return<R> {
128        Return(_v)
129    }
130}
131
132pin_project! {
133    /// Represent an asyncronus generator. It implementations [`AsyncGenerator`] trait.
134    ///
135    /// This `struct` is created by [`gen()`]. See its documentation for more details.
136    pub struct AsyncGen<Fut, Y> {
137        inner: Arc<Inner<Y>>,
138        #[pin]
139        fut: Fut,
140    }
141}
142
143impl<Fut, Y, R> AsyncGen<Fut, Y>
144where
145    Fut: Future<Output = Return<R>>,
146{
147    /// See [`AsyncGenerator::poll_resume`] for more details.
148    #[doc(hidden)]
149    pub fn poll_resume(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<GeneratorState<Y, R>> {
150        let me = self.project();
151        match me.fut.poll(cx) {
152            Poll::Ready(Return(val)) => Poll::Ready(GeneratorState::Complete(val)),
153            Poll::Pending => {
154                // SEAFTY: We just return from `me.fut`,
155                // So this is safe and unique access to `me.inner.data`
156                unsafe {
157                    let data = &mut *me.inner.data.get();
158                    if data.is_some() {
159                        return Poll::Ready(GeneratorState::Yielded(data.take().unwrap()));
160                    }
161                }
162                Poll::Pending
163            }
164        }
165    }
166
167    #[inline]
168    /// See [`AsyncGenerator::poll_resume`] for more details.
169    pub async fn resume(self: &mut Pin<&mut Self>) -> GeneratorState<Y, R> {
170        std::future::poll_fn(|cx| self.as_mut().poll_resume(cx)).await
171    }
172}
173
174impl<Fut, Y> AsyncGen<Fut, Y>
175where
176    Fut: Future<Output = Return<()>>,
177{
178    #[inline]
179    /// Creates an async iterator from this generator.
180    ///
181    /// See [`AsyncIter`] for more details.
182    pub fn into_async_iter(self) -> AsyncIter<Self> {
183        AsyncIter::from(self)
184    }
185
186    #[doc(hidden)]
187    pub fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Y>> {
188        let me = self.project();
189        match me.fut.poll(cx) {
190            Poll::Ready(Return(())) => Poll::Ready(None),
191            Poll::Pending => {
192                // SEAFTY: We just return from `me.fut`,
193                // So this is safe and unique access to `me.inner.data`
194                unsafe {
195                    let data = &mut *me.inner.data.get();
196                    if data.is_some() {
197                        return Poll::Ready(data.take());
198                    }
199                }
200                Poll::Pending
201            }
202        }
203    }
204}
205
206impl<Fut, Y> futures_core::Stream for AsyncGen<Fut, Y>
207where
208    Fut: Future<Output = Return<()>>,
209{
210    type Item = Y;
211    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
212        AsyncGen::poll_next(self, cx)
213    }
214}
215
216impl<Fut, Y, R> AsyncGenerator for AsyncGen<Fut, Y>
217where
218    Fut: Future<Output = Return<R>>,
219{
220    type Yield = Y;
221    type Return = R;
222
223    fn poll_resume(
224        self: Pin<&mut Self>,
225        cx: &mut Context<'_>,
226    ) -> Poll<GeneratorState<Self::Yield, Self::Return>> {
227        AsyncGen::poll_resume(self, cx)
228    }
229}
230
231pin_project! {
232    /// An async iterator over the values yielded by an underlying generator.
233    ///
234    /// ## Example
235    ///
236    /// ```
237    /// use async_gen::{gen, AsyncIter};
238    /// use futures_core::Stream;
239    /// use futures_util::StreamExt;
240    ///
241    /// fn get_async_iter() -> impl Stream<Item = i32> {
242    ///     AsyncIter::from(gen! {
243    ///         yield 1;
244    ///         yield 2;
245    ///         yield 3;
246    ///     })
247    /// }
248    ///
249    /// #[tokio::main]
250    /// async fn main() {
251    ///     let it = get_async_iter();
252    ///     let v: Vec<_> = it.collect().await;
253    ///     assert_eq!(v, [1, 2, 3]);
254    /// }
255    /// ```
256    #[derive(Clone)]
257    pub struct AsyncIter<G> {
258        #[pin]
259        gen: G,
260    }
261}
262
263impl<G> From<G> for AsyncIter<G> {
264    #[inline]
265    fn from(gen: G) -> Self {
266        AsyncIter { gen }
267    }
268}
269
270impl<G: AsyncGenerator<Return = ()>> AsyncIter<G> {
271    /// Attempt to pull out the next value of this async iterator, registering the
272    /// current task for wakeup if the value is not yet available, and returning
273    /// `None` if the async iterator is exhausted.
274    ///
275    /// # Return value
276    ///
277    /// There are several possible return values, each indicating a distinct
278    /// async iterator state:
279    ///
280    /// - `Poll::Pending` means that this async iterator's next value is not ready
281    /// yet. Implementations will ensure that the current task will be notified
282    /// when the next value may be ready.
283    ///
284    /// - `Poll::Ready(Some(val))` means that the async iterator has successfully
285    /// produced a value, `val`, and may produce further values on subsequent
286    /// `poll_next` calls.
287    ///
288    /// - `Poll::Ready(None)` means that the async iterator has terminated, and
289    /// `poll_next` should not be invoked again.
290    ///
291    /// # Panics
292    ///
293    /// Once an async iterator has finished (returned `Ready(None)` from `poll_next`), calling its
294    /// `poll_next` method again may panic, block forever, or cause other kinds of
295    /// problems; the `AsyncIterator` trait places no requirements on the effects of
296    /// such a call. However, as the `poll_next` method is not marked `unsafe`,
297    /// Rust's usual rules apply: calls must never cause undefined behavior
298    /// (memory corruption, incorrect use of `unsafe` functions, or the like),
299    /// regardless of the async iterator's state.
300    pub fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<G::Yield>> {
301        self.project().gen.poll_resume(cx).map(|s| match s {
302            GeneratorState::Yielded(val) => Some(val),
303            GeneratorState::Complete(()) => None,
304        })
305    }
306}
307
308impl<G: AsyncGenerator<Return = ()>> futures_core::Stream for AsyncIter<G> {
309    type Item = G::Yield;
310    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
311        AsyncIter::poll_next(self, cx)
312    }
313}
314
315/// Creates a new generator, which implements the [`AsyncGenerator`] trait.
316///
317/// Also see [`gen!`] macro for more details.
318///
319/// ## Examples
320///
321/// ```
322/// use async_gen::{gen, AsyncGen, AsyncGenerator, Return};
323/// use std::future::Future;
324///
325/// fn example() {
326///     let g = gen(|mut c| async {
327///         c.yield_(42).await;
328///         c.return_("42")
329///     });
330///
331///     check_type_1(&g);
332///     check_type_2(&g);
333/// }
334/// fn check_type_1(_: &AsyncGen<impl Future<Output = Return<&'static str>>, i32>) {}
335/// fn check_type_2(_: &impl AsyncGenerator<Yield = i32, Return = &'static str>) {}
336/// ```
337pub fn gen<Fut, Y, R>(fut: impl FnOnce(Yield<Y>) -> Fut) -> AsyncGen<Fut, Y>
338where
339    Fut: Future<Output = Return<R>>,
340{
341    let inner = Arc::new(Inner {
342        data: UnsafeCell::new(None),
343    });
344    let fut = fut(Yield {
345        inner: inner.clone(),
346    });
347    AsyncGen { inner, fut }
348}
349
350/// A macro for creating generator.
351///
352/// Also see [`gen()`] function for more details.
353///
354/// ## Examples
355///
356/// ```
357/// use std::pin::pin;
358/// use async_gen::{gen, GeneratorState};
359///
360/// # #[tokio::main]
361/// # async fn main() {
362/// let gen = gen! {
363///     yield 42;
364///     return "42"
365/// };
366/// let mut g = pin!(gen);
367/// assert_eq!(g.resume().await, GeneratorState::Yielded(42));
368/// assert_eq!(g.resume().await, GeneratorState::Complete("42"));
369/// # }
370/// ```
371#[macro_export]
372macro_rules! gen {
373    ($($tt:tt)*) => {
374        $crate::__private::gen_inner!(($crate) $($tt)*)
375    }
376}
377
378#[doc(hidden)]
379pub mod __private {
380    pub use async_gen_macros::*;
381}