async_scoped/
usage.rs

1use crate::spawner::*;
2use crate::Scope;
3
4impl<'a, T, Sp: Spawner<T> + Blocker + Default> Scope<'a, T, Sp> {
5    /// Creates a `Scope` to spawn non-'static futures. The
6    /// function is called with a block which takes an `&mut
7    /// Scope`. The `spawn` method on this arg. can be used to
8    /// spawn "local" futures.
9    ///
10    /// # Returns
11    ///
12    /// The function returns the created `Scope`, and the return
13    /// value of the block passed to it. The returned stream and
14    /// is expected to be driven completely before being
15    /// forgotten. Dropping this stream causes the stream to be
16    /// driven _while blocking the current thread_. The values
17    /// returned from the stream are the output of the futures
18    /// spawned.
19    ///
20    /// # Safety
21    ///
22    /// The returned stream is expected to be run to completion
23    /// before being forgotten. Dropping it is okay, but blocks
24    /// the current thread until all spawned futures complete.
25    pub unsafe fn scope<R, F>(f: F) -> (Self, R)
26    where
27        T: Send + 'static,
28        Sp: Spawner<T> + Blocker,
29        F: FnOnce(&mut Scope<'a, T, Sp>) -> R,
30    {
31        let mut scope = Scope::create(Default::default());
32        let op = f(&mut scope);
33        (scope, op)
34    }
35
36    /// A function that creates a scope and immediately awaits,
37    /// _blocking the current thread_ for spawned futures to
38    /// complete. The outputs of the futures are collected as a
39    /// `Vec` and returned along with the output of the block.
40    ///
41    /// # Safety
42    ///
43    /// This function is safe to the best of our understanding
44    /// as it blocks the current thread until the stream is
45    /// driven to completion, implying that all the spawned
46    /// futures have completed too. However, care must be taken
47    /// to ensure a recursive usage of this function doesn't
48    /// lead to deadlocks.
49    ///
50    /// When scope is used recursively, you may also use the
51    /// unsafe `scope_and_*` functions as long as this function
52    /// is used at the top level. In this case, either the
53    /// recursively spawned should have the same lifetime as the
54    /// top-level scope, or there should not be any spurious
55    /// future cancellations within the top level scope.
56    pub fn scope_and_block<R, F>(f: F) -> (R, Vec<Sp::FutureOutput>)
57    where
58        T: Send + 'static,
59        Sp: Spawner<T> + Blocker,
60        F: FnOnce(&mut Scope<'a, T, Sp>) -> R,
61    {
62        let (mut stream, block_output) = unsafe { Self::scope(f) };
63        let proc_outputs = Sp::default().block_on(stream.collect());
64        (block_output, proc_outputs)
65    }
66
67    /// An asynchronous function that creates a scope and
68    /// immediately awaits the stream. The outputs of the
69    /// futures are collected as a `Vec` and returned along with
70    /// the output of the block.
71    ///
72    /// # Safety
73    ///
74    /// This function is _not completely safe_: please see
75    /// `cancellation_soundness` in [tests.rs][tests-src] for a
76    /// test-case that suggests how this can lead to invalid
77    /// memory access if not dealt with care.
78    ///
79    /// The caller must ensure that the lifetime 'a is valid
80    /// until the returned future is fully driven. Dropping the
81    /// future is okay, but blocks the current thread until all
82    /// spawned futures complete.
83    ///
84    /// [tests-src]: https://github.com/rmanoka/async-scoped/blob/master/src/tests.rs
85    pub async unsafe fn scope_and_collect<R, F>(f: F) -> (R, Vec<Sp::FutureOutput>)
86    where
87        T: Send + 'static,
88        F: FnOnce(&mut Scope<'a, T, Sp>) -> R,
89    {
90        let (mut stream, block_output) = Self::scope(f);
91        let proc_outputs = stream.collect().await;
92        (block_output, proc_outputs)
93    }
94}