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}