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}