Skip to main content

datafusion_execution/
async_stream.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use futures::Stream;
19use futures::future::FusedFuture;
20use futures::stream::FusedStream;
21use parking_lot::Mutex;
22use pin_project_lite::pin_project;
23use std::ops::DerefMut;
24use std::pin::Pin;
25use std::sync::Arc;
26use std::task::{Context, Poll};
27
28/// Creates a [`Stream`] from an async generator function.
29///
30/// The `generator` closure receives an [`Emitter<T>`] and runs as an async
31/// block. Each `emitter.emit(value).await` call suspends the generator and
32/// produces the next item in the stream. The stream ends when the generator
33/// future resolves.
34///
35/// # Example
36///
37/// ```
38/// use datafusion_execution::async_stream;
39/// use futures::StreamExt;
40///
41/// # #[tokio::main(flavor = "current_thread")]
42/// # async fn main() {
43/// let stream = async_stream(|mut emitter| async move {
44///     for i in 0_i32..3 {
45///         emitter.emit(i).await;
46///     }
47/// });
48///
49/// let values: Vec<i32> = stream.collect().await;
50/// assert_eq!(values, vec![0, 1, 2]);
51/// # }
52/// ```
53pub fn async_stream<T, F: Future<Output = ()>>(
54    generator: impl FnOnce(Emitter<T>) -> F,
55) -> impl FusedStream<Item = T> {
56    let (emitter, receiver) = tx_rx();
57    AsyncStream::new(receiver, generator(emitter))
58}
59
60/// Creates a fallible [`Stream`] from an async generator function.
61///
62/// The `generator` closure receives a [`TryEmitter<T, E>`] and runs as an
63/// async block that returns `Result<(), E>`. Each `emitter.emit(value).await`
64/// call suspends the generator and produces `Ok(value)` as the next stream
65/// item. The `?` operator can be used inside the generator to short-circuit on
66/// errors: the error is emitted as the final `Err(e)` item and the stream
67/// ends. The stream also ends when the generator future resolves to `Ok(())`.
68///
69/// # Example
70///
71/// ```
72/// use datafusion_execution::async_try_stream;
73/// use futures::StreamExt;
74///
75/// # #[tokio::main(flavor = "current_thread")]
76/// # async fn main() {
77/// let stream = async_try_stream(|mut emitter| async move {
78///     emitter.emit(1_i32).await;
79///     emitter.emit(2_i32).await;
80///     Err::<(), _>("something went wrong")?;
81///     emitter.emit(3_i32).await; // never reached
82///     Ok(())
83/// });
84///
85/// let values: Vec<Result<i32, &str>> = stream.collect().await;
86/// assert_eq!(values, vec![Ok(1), Ok(2), Err("something went wrong")]);
87/// # }
88/// ```
89pub fn async_try_stream<T, E, F: Future<Output = Result<(), E>>>(
90    generator: impl FnOnce(TryEmitter<T, E>) -> F,
91) -> impl FusedStream<Item = Result<T, E>> {
92    let (try_emitter, mut emitter, receiver) = try_tx_rx::<T, E>();
93    AsyncStream::new(receiver, async move {
94        if let Err(e) = generator(try_emitter).await {
95            // Fill the slot without suspending so this future completes in the same
96            // poll that yields `Err(e)`: the stream terminates immediately and the
97            // emitter state is dropped (a consumer may never poll again after an
98            // error, which would otherwise keep this future suspended inside `emit`)
99            emitter.set(Err(e));
100        }
101    })
102}
103
104/// Creates an `Emitter`/`Receiver` pair
105fn tx_rx<T>() -> (Emitter<T>, Receiver<T>) {
106    let slot = Arc::new(Mutex::new(None));
107    (
108        Emitter {
109            slot: Arc::clone(&slot),
110        },
111        Receiver { slot },
112    )
113}
114
115/// Creates an `TryEmitter`/`Emitter`/`Receiver` triplet
116#[expect(
117    clippy::type_complexity,
118    reason = "three-element tuple is clearer than an alias here"
119)]
120fn try_tx_rx<T, E>() -> (
121    TryEmitter<T, E>,
122    Emitter<Result<T, E>>,
123    Receiver<Result<T, E>>,
124) {
125    let slot = Arc::new(Mutex::new(None));
126    (
127        TryEmitter {
128            slot: Arc::clone(&slot),
129        },
130        Emitter {
131            slot: Arc::clone(&slot),
132        },
133        Receiver { slot },
134    )
135}
136
137/// Value slot shared between [`Emitter`] and [`Receiver`].
138/// Use `Arc<Mutex>` to ensure the created `Stream` implementations
139/// are both `Send` and `Sync`.
140type SlotRef<T> = Arc<Mutex<Option<T>>>;
141
142/// A handle for emitting values from an [`async_stream`] generator.
143///
144/// The generator closure receives an `Emitter<T>` as its argument.
145pub struct Emitter<T> {
146    slot: SlotRef<T>,
147}
148
149/// A handle for emitting values from an [`async_try_stream`] generator.
150///
151/// The generator closure receives a `TryEmitter<T, E>` as its argument.
152pub struct TryEmitter<T, E> {
153    slot: SlotRef<Result<T, E>>,
154}
155
156struct Receiver<T> {
157    slot: SlotRef<T>,
158}
159
160impl<T> Emitter<T> {
161    /// Returns a `Future` that emits `value` as the next stream item.
162    ///
163    /// The returned future **must be awaited immediately**. On its first poll it
164    /// yields `Poll::Pending`, handing control back to the stream consumer so it
165    /// can observe the emitted value. On the next poll (triggered by the
166    /// consumer calling `poll_next` again) it completes with `Poll::Ready(())`,
167    /// resuming the generator.
168    ///
169    /// # Panics
170    ///
171    /// Panics if `emit` is called a second time before the previous future has
172    /// been awaited, because doing so would silently overwrite the unconsumed
173    /// value.
174    pub fn emit(&mut self, value: T) -> impl FusedFuture<Output = ()> {
175        self.set(value);
176        Emit { done: false }
177    }
178
179    /// Places `value` in the slot without suspending the generator. Only useful
180    /// as the very last action before the generator future completes, since
181    /// nothing yields control back to the consumer in between.
182    fn set(&mut self, value: T) {
183        let mut guard = self.slot.lock();
184        match guard.deref_mut() {
185            Some(_) => panic!("Misuse: await was not called after calling emit"),
186            slot => *slot = Some(value),
187        }
188    }
189}
190
191impl<T, E> TryEmitter<T, E> {
192    /// Emits `Ok(value)` as the next stream item and suspends the generator.
193    ///
194    /// Behaves identically to [`Emitter::emit`]: the returned future must be
195    /// awaited immediately and yields `Poll::Pending` on its first poll to
196    /// transfer control to the stream consumer.
197    ///
198    /// # Panics
199    ///
200    /// Panics if called before the previous emit future has been awaited.
201    pub fn emit(&mut self, value: T) -> impl FusedFuture<Output = ()> {
202        let mut guard = self.slot.lock();
203        match guard.deref_mut() {
204            Some(_) => panic!("Misuse: await was not called after calling emit"),
205            slot => *slot = Some(Ok::<T, E>(value)),
206        }
207
208        Emit { done: false }
209    }
210}
211
212struct Emit {
213    done: bool,
214}
215
216impl FusedFuture for Emit {
217    fn is_terminated(&self) -> bool {
218        self.done
219    }
220}
221
222impl Future for Emit {
223    type Output = ();
224
225    fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
226        if !self.done {
227            self.done = true;
228            // Poll::Pending causes the generator to yield, returning control back to the
229            // calling Stream
230            Poll::Pending
231        } else {
232            Poll::Ready(())
233        }
234    }
235}
236
237pin_project! {
238    struct AsyncStream<T, U> {
239        rx: Receiver<T>,
240        done: bool,
241        #[pin]
242        generator: U,
243    }
244}
245
246impl<T, U> AsyncStream<T, U> {
247    fn new(rx: Receiver<T>, generator: U) -> AsyncStream<T, U> {
248        AsyncStream {
249            rx,
250            done: false,
251            generator,
252        }
253    }
254}
255
256impl<T, U> FusedStream for AsyncStream<T, U>
257where
258    U: Future<Output = ()>,
259{
260    fn is_terminated(&self) -> bool {
261        self.done
262    }
263}
264
265impl<T, U> Stream for AsyncStream<T, U>
266where
267    U: Future<Output = ()>,
268{
269    type Item = T;
270
271    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
272        let this = self.project();
273
274        if *this.done {
275            return Poll::Ready(None);
276        }
277
278        // The `Option::take` call below ensures the next time poll is called the slot is
279        // already set to None
280        debug_assert!(this.rx.slot.lock().is_none());
281        let res = this.generator.poll(cx);
282        *this.done = res.is_ready();
283
284        match this.rx.slot.lock().take() {
285            // Generator filled slot -> return next stream item
286            Some(v) => Poll::Ready(Some(v)),
287            // Generator did not fill slot and completed -> return None to indicate end of stream
288            None if *this.done => Poll::Ready(None),
289            // Generator did not fill slot and not completed -> return Pending since some Future
290            // other than Emit returned Pending.
291            None => Poll::Pending,
292        }
293    }
294
295    fn size_hint(&self) -> (usize, Option<usize>) {
296        if self.done { (0, Some(0)) } else { (0, None) }
297    }
298}
299
300#[cfg(test)]
301mod test {
302    use crate::async_stream::Emitter;
303    use crate::{async_stream, async_try_stream};
304    use futures::stream::FusedStream;
305    use futures::{Stream, StreamExt, pin_mut};
306    use std::assert_matches;
307    use std::pin::Pin;
308    use std::sync::Arc;
309    use std::sync::atomic::{AtomicUsize, Ordering};
310    use std::task::{Context, Poll};
311    use tokio::sync::mpsc;
312
313    #[tokio::test]
314    async fn noop_stream() {
315        let s = async_stream(|_: Emitter<()>| async {});
316        pin_mut!(s);
317
318        assert_eq!(s.next().await, None);
319    }
320
321    #[tokio::test]
322    async fn empty_stream() {
323        let mut ran = false;
324
325        {
326            let r = &mut ran;
327            let s = async_stream(|_: Emitter<()>| async {
328                *r = true;
329                println!("hello world!");
330            });
331            pin_mut!(s);
332
333            assert_eq!(s.next().await, None);
334        }
335
336        assert!(ran);
337    }
338
339    #[tokio::test]
340    async fn emit_single_value() {
341        let s = async_stream(|mut emitter| async move {
342            emitter.emit("hello").await;
343        });
344
345        let values: Vec<_> = s.collect().await;
346
347        assert_eq!(1, values.len());
348        assert_eq!("hello", values[0]);
349    }
350
351    #[tokio::test]
352    async fn fused() {
353        let s = async_stream(|mut emitter| async move {
354            emitter.emit("hello").await;
355        });
356        pin_mut!(s);
357
358        assert!(!s.is_terminated());
359        assert_eq!(s.next().await, Some("hello"));
360        assert_eq!(s.next().await, None);
361
362        assert!(s.is_terminated());
363        // This should return None from now on
364        assert_eq!(s.next().await, None);
365    }
366
367    #[tokio::test]
368    async fn emit_multi_value() {
369        let s = async_stream(|mut emitter| async move {
370            emitter.emit("hello").await;
371            emitter.emit("world").await;
372            emitter.emit("dizzy").await;
373        });
374
375        let values: Vec<_> = s.collect().await;
376
377        assert_eq!(3, values.len());
378        assert_eq!("hello", values[0]);
379        assert_eq!("world", values[1]);
380        assert_eq!("dizzy", values[2]);
381    }
382
383    #[tokio::test]
384    #[should_panic = "await was not called after calling emit"]
385    async fn emit_without_await() {
386        let s = async_stream(|mut emitter| async move {
387            #[expect(clippy::let_underscore_future)]
388            {
389                let _ = emitter.emit("hello");
390                let _ = emitter.emit("world");
391            }
392        });
393
394        let _: Vec<_> = s.collect().await;
395    }
396
397    #[tokio::test]
398    async fn unit_emit_in_select() {
399        use tokio::select;
400
401        #[expect(clippy::unused_async)]
402        async fn do_stuff_async() {}
403
404        let s = async_stream(|mut emitter| async move {
405            select! {
406                _ = do_stuff_async() => emitter.emit(()).await,
407                else => emitter.emit(()).await,
408            }
409        });
410
411        let values: Vec<_> = s.collect().await;
412        assert_eq!(values.len(), 1);
413    }
414
415    #[tokio::test]
416    async fn emit_with_select() {
417        use tokio::select;
418
419        #[expect(clippy::unused_async)]
420        async fn do_stuff_async() {}
421        #[expect(clippy::unused_async)]
422        async fn more_async_work() {}
423
424        let s = async_stream(|mut emitter| async move {
425            select! {
426                _ = do_stuff_async() => emitter.emit("hey").await,
427                _ = more_async_work() => emitter.emit("hey").await,
428                else => emitter.emit("hey").await,
429            }
430        });
431
432        let values: Vec<_> = s.collect().await;
433        assert_eq!(values, vec!["hey"]);
434    }
435
436    #[tokio::test]
437    async fn return_stream() {
438        fn build_stream() -> impl Stream<Item = u32> {
439            async_stream(|mut emitter| async move {
440                emitter.emit(1).await;
441                emitter.emit(2).await;
442                emitter.emit(3).await;
443            })
444        }
445
446        let s = build_stream();
447
448        let values: Vec<_> = s.collect().await;
449        assert_eq!(3, values.len());
450        assert_eq!(1, values[0]);
451        assert_eq!(2, values[1]);
452        assert_eq!(3, values[2]);
453    }
454
455    #[tokio::test]
456    async fn consume_channel() {
457        let (tx, mut rx) = mpsc::channel(10);
458
459        let s = async_stream(|mut emitter| async move {
460            while let Some(v) = rx.recv().await {
461                emitter.emit(v).await;
462            }
463        });
464
465        pin_mut!(s);
466
467        for i in 0..3 {
468            assert_matches!(tx.send(i).await, Ok(_));
469            assert_eq!(Some(i), s.next().await);
470        }
471
472        drop(tx);
473        assert_eq!(None, s.next().await);
474    }
475
476    #[tokio::test]
477    async fn borrow_self() {
478        struct Data(String);
479
480        impl Data {
481            fn stream(&self) -> impl Stream<Item = &str> + '_ {
482                async_stream(move |mut emitter| async move {
483                    emitter.emit(&self.0[..]).await;
484                })
485            }
486        }
487
488        let data = Data("hello".to_string());
489        let s = data.stream();
490        pin_mut!(s);
491
492        assert_eq!(Some("hello"), s.next().await);
493    }
494
495    #[tokio::test]
496    async fn stream_in_stream() {
497        let s = async_stream(|mut emitter| async move {
498            let s = async_stream(|mut inner_emitter| async move {
499                for i in 0..3 {
500                    inner_emitter.emit(i).await;
501                }
502            });
503
504            pin_mut!(s);
505            while let Some(v) = s.next().await {
506                emitter.emit(v).await;
507            }
508        });
509
510        let values: Vec<_> = s.collect().await;
511        assert_eq!(3, values.len());
512    }
513
514    // Demonstrates that capturing an outer Emitter<T> inside an inner async_stream with a
515    // different item type is no longer undefined behaviour: the outer emitter writes to its own
516    // typed slot, so the inner stream never sees any values.  The outer stream receives the
517    // "foo" strings instead because they land in its slot.
518    #[tokio::test]
519    async fn stream_in_stream_misuse() {
520        let s = async_stream(|mut emitter| async move {
521            let s = async_stream(|_inner_emitter: Emitter<i32>| async move {
522                for _i in 0..3 {
523                    emitter.emit("foo").await;
524                }
525            });
526
527            pin_mut!(s);
528            while let Some(v) = s.next().await {
529                println!("{v}");
530            }
531        });
532
533        let values: Vec<_> = s.collect().await;
534        assert_eq!(3, values.len());
535    }
536
537    #[tokio::test]
538    async fn emit_non_unpin_value() {
539        let s: Vec<_> = async_stream(|mut emitter| async move {
540            for i in 0..3 {
541                emitter.emit(async move { i }).await;
542            }
543        })
544        .buffered(1)
545        .collect()
546        .await;
547
548        assert_eq!(s, vec![0, 1, 2]);
549    }
550
551    #[tokio::test]
552    async fn should_not_call_handler_function_if_not_polled() {
553        let _ = async_stream(|_: Emitter<()>| async move {
554            panic!("should not be called");
555        });
556    }
557
558    #[tokio::test]
559    async fn should_not_continue_until_next_poll() {
560        let s = async_stream(|mut emitter| async move {
561            emitter.emit("hey").await;
562            panic!("make sure poll based and not push based");
563        });
564        pin_mut!(s);
565        let _ = s.next().await;
566    }
567
568    #[test]
569    fn inner_try_stream() {
570        use tokio::select;
571
572        #[expect(clippy::unused_async)]
573        async fn do_stuff_async() {}
574
575        let _ = async_stream(|mut emitter| async move {
576            select! {
577                _ = do_stuff_async() => {
578                    let another_s = async_try_stream(|mut inner_emitter| async move {
579                        inner_emitter.emit(()).await;
580                        Ok(())
581                    });
582                    let _: Result<(), ()> = Box::pin(another_s).next().await.unwrap();
583                },
584                else => {},
585            }
586            emitter.emit(()).await;
587        });
588    }
589
590    #[tokio::test]
591    async fn single_err() {
592        let s = async_try_stream(|mut emitter| async move {
593            if true {
594                Err("hello")?;
595            } else {
596                emitter.emit("world").await;
597            }
598
599            unreachable!();
600        });
601
602        let values: Vec<_> = s.collect().await;
603        assert_eq!(1, values.len());
604        assert_eq!(Err("hello"), values[0]);
605    }
606
607    #[tokio::test]
608    async fn emit_then_err() {
609        let s = async_try_stream(|mut emitter| async move {
610            emitter.emit("hello").await;
611            Err("world")?;
612            unreachable!();
613        });
614
615        let values: Vec<_> = s.collect().await;
616        assert_eq!(2, values.len());
617        assert_eq!(Ok("hello"), values[0]);
618        assert_eq!(Err("world"), values[1]);
619    }
620
621    #[tokio::test]
622    async fn convert_err() {
623        struct ErrorA(u8);
624        #[derive(PartialEq, Debug)]
625        struct ErrorB(u8);
626        impl From<ErrorA> for ErrorB {
627            fn from(a: ErrorA) -> ErrorB {
628                ErrorB(a.0)
629            }
630        }
631
632        fn test() -> impl Stream<Item = Result<&'static str, ErrorB>> {
633            async_try_stream(|mut emitter| async move {
634                if true {
635                    Err(ErrorA(1))?;
636                } else {
637                    Err(ErrorB(2))?;
638                }
639                emitter.emit("unreachable").await;
640                Ok(())
641            })
642        }
643
644        let values: Vec<_> = test().collect().await;
645        assert_eq!(1, values.len());
646        assert_eq!(Err(ErrorB(1)), values[0]);
647    }
648
649    #[tokio::test]
650    async fn multi_try() {
651        fn test() -> impl Stream<Item = Result<i32, String>> {
652            async_try_stream(|mut emitter| async move {
653                let a = Ok::<_, String>(Ok::<_, String>(123))??;
654                for _ in 1..10 {
655                    emitter.emit(a).await;
656                }
657                Ok(())
658            })
659        }
660        let values: Vec<_> = test().collect().await;
661        assert_eq!(9, values.len());
662        assert_eq!(
663            std::iter::repeat_n(123, 9).map(Ok).collect::<Vec<_>>(),
664            values
665        );
666    }
667
668    struct DropGuard(Arc<AtomicUsize>);
669
670    impl Drop for DropGuard {
671        fn drop(&mut self) {
672            self.0.fetch_add(1, Ordering::SeqCst);
673        }
674    }
675
676    #[tokio::test]
677    async fn generator_freed_on_done() {
678        let drops = Arc::new(AtomicUsize::new(0));
679        let guard = DropGuard(Arc::clone(&drops));
680
681        let s = async_stream(|mut emitter| async move {
682            let _guard = guard;
683            emitter.emit(1).await;
684        });
685        pin_mut!(s);
686
687        assert_eq!(s.next().await, Some(1));
688        assert_eq!(s.next().await, None);
689
690        // State captured by the generator is dropped as soon as it completes
691        // (async blocks drop their locals on return), even though the stream
692        // itself is still alive
693        assert_eq!(drops.load(Ordering::SeqCst), 1);
694        assert_eq!(s.next().await, None);
695    }
696
697    #[tokio::test]
698    async fn generator_freed_on_emitted_error() {
699        let drops = Arc::new(AtomicUsize::new(0));
700        let guard = DropGuard(Arc::clone(&drops));
701
702        let s = async_try_stream(|mut emitter| async move {
703            let _guard = guard;
704            emitter.emit(1).await;
705            Err("boom")
706        });
707        pin_mut!(s);
708
709        assert_eq!(s.next().await, Some(Ok(1)));
710        assert_eq!(s.next().await, Some(Err("boom")));
711
712        // The stream terminates in the same poll that yields the error, so the
713        // generator state is freed even if the consumer never polls again
714        assert!(s.is_terminated());
715        assert_eq!(drops.load(Ordering::SeqCst), 1);
716
717        // Polling again after the error just returns None
718        assert_eq!(s.next().await, None);
719    }
720
721    use pin_project_lite::pin_project;
722
723    pin_project! {
724        struct MyStream<T: Stream> {
725            #[pin]
726            input: T,
727        }
728    }
729
730    impl<T: Stream> Stream for MyStream<T> {
731        type Item = T::Item;
732
733        fn poll_next(
734            self: Pin<&mut Self>,
735            cx: &mut Context<'_>,
736        ) -> Poll<Option<Self::Item>> {
737            let this = self.project();
738            this.input.poll_next(cx)
739        }
740    }
741
742    #[tokio::test]
743    async fn emit_does_not_hold_on_value() {
744        let waker = futures::task::noop_waker_ref();
745        let mut cx = Context::from_waker(waker);
746
747        let run = Arc::<AtomicUsize>::new(AtomicUsize::new(0));
748        let moved = Arc::clone(&run);
749        let s = async_stream(|mut emitter| async move {
750            for _ in 0..2 {
751                let before = moved.fetch_add(1, Ordering::SeqCst);
752                emitter.emit(before).await;
753            }
754        });
755
756        let mut my_stream = Box::pin(MyStream { input: s });
757
758        #[derive(Debug, PartialEq)]
759        struct Item {
760            before: usize,
761            result: Poll<Option<usize>>,
762            after: usize,
763        }
764
765        let mut results = vec![];
766
767        assert_eq!(run.load(Ordering::SeqCst), 0);
768
769        while run.load(Ordering::SeqCst) < 2 {
770            let before = run.load(Ordering::SeqCst);
771            let result = my_stream.poll_next_unpin(&mut cx);
772            let after = run.load(Ordering::SeqCst);
773            results.push(Item {
774                before,
775                result,
776                after,
777            });
778        }
779
780        assert_eq!(
781            results,
782            vec![
783                Item {
784                    before: 0,
785                    result: Poll::Ready(Some(0)),
786                    after: 1,
787                },
788                Item {
789                    before: 1,
790                    result: Poll::Ready(Some(1)),
791                    after: 2,
792                }
793            ]
794        );
795    }
796}