1 | use futures_task::{LocalSpawn, Spawn}; |
2 | |
3 | #[cfg (feature = "compat" )] |
4 | use crate::compat::Compat; |
5 | |
6 | #[cfg (feature = "channel" )] |
7 | #[cfg (feature = "std" )] |
8 | use crate::future::{FutureExt, RemoteHandle}; |
9 | #[cfg (feature = "alloc" )] |
10 | use alloc::boxed::Box; |
11 | #[cfg (feature = "alloc" )] |
12 | use futures_core::future::Future; |
13 | #[cfg (feature = "alloc" )] |
14 | use futures_task::{FutureObj, LocalFutureObj, SpawnError}; |
15 | |
16 | impl<Sp: ?Sized> SpawnExt for Sp where Sp: Spawn {} |
17 | impl<Sp: ?Sized> LocalSpawnExt for Sp where Sp: LocalSpawn {} |
18 | |
19 | /// Extension trait for `Spawn`. |
20 | pub trait SpawnExt: Spawn { |
21 | /// Spawns a task that polls the given future with output `()` to |
22 | /// completion. |
23 | /// |
24 | /// This method returns a [`Result`] that contains a [`SpawnError`] if |
25 | /// spawning fails. |
26 | /// |
27 | /// You can use [`spawn_with_handle`](SpawnExt::spawn_with_handle) if |
28 | /// you want to spawn a future with output other than `()` or if you want |
29 | /// to be able to await its completion. |
30 | /// |
31 | /// Note this method will eventually be replaced with the upcoming |
32 | /// `Spawn::spawn` method which will take a `dyn Future` as input. |
33 | /// Technical limitations prevent `Spawn::spawn` from being implemented |
34 | /// today. Feel free to use this method in the meantime. |
35 | /// |
36 | /// ``` |
37 | /// # { |
38 | /// use futures::executor::ThreadPool; |
39 | /// use futures::task::SpawnExt; |
40 | /// |
41 | /// let executor = ThreadPool::new().unwrap(); |
42 | /// |
43 | /// let future = async { /* ... */ }; |
44 | /// executor.spawn(future).unwrap(); |
45 | /// # } |
46 | /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 |
47 | /// ``` |
48 | #[cfg (feature = "alloc" )] |
49 | fn spawn<Fut>(&self, future: Fut) -> Result<(), SpawnError> |
50 | where |
51 | Fut: Future<Output = ()> + Send + 'static, |
52 | { |
53 | self.spawn_obj(FutureObj::new(Box::new(future))) |
54 | } |
55 | |
56 | /// Spawns a task that polls the given future to completion and returns a |
57 | /// future that resolves to the spawned future's output. |
58 | /// |
59 | /// This method returns a [`Result`] that contains a [`RemoteHandle`](crate::future::RemoteHandle), or, if |
60 | /// spawning fails, a [`SpawnError`]. [`RemoteHandle`](crate::future::RemoteHandle) is a future that |
61 | /// resolves to the output of the spawned future. |
62 | /// |
63 | /// ``` |
64 | /// # { |
65 | /// use futures::executor::{block_on, ThreadPool}; |
66 | /// use futures::future; |
67 | /// use futures::task::SpawnExt; |
68 | /// |
69 | /// let executor = ThreadPool::new().unwrap(); |
70 | /// |
71 | /// let future = future::ready(1); |
72 | /// let join_handle_fut = executor.spawn_with_handle(future).unwrap(); |
73 | /// assert_eq!(block_on(join_handle_fut), 1); |
74 | /// # } |
75 | /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 |
76 | /// ``` |
77 | #[cfg (feature = "channel" )] |
78 | #[cfg_attr (docsrs, doc(cfg(feature = "channel" )))] |
79 | #[cfg (feature = "std" )] |
80 | fn spawn_with_handle<Fut>(&self, future: Fut) -> Result<RemoteHandle<Fut::Output>, SpawnError> |
81 | where |
82 | Fut: Future + Send + 'static, |
83 | Fut::Output: Send, |
84 | { |
85 | let (future, handle) = future.remote_handle(); |
86 | self.spawn(future)?; |
87 | Ok(handle) |
88 | } |
89 | |
90 | /// Wraps a [`Spawn`] and makes it usable as a futures 0.1 `Executor`. |
91 | /// Requires the `compat` feature to enable. |
92 | #[cfg (feature = "compat" )] |
93 | #[cfg_attr (docsrs, doc(cfg(feature = "compat" )))] |
94 | fn compat(self) -> Compat<Self> |
95 | where |
96 | Self: Sized, |
97 | { |
98 | Compat::new(self) |
99 | } |
100 | } |
101 | |
102 | /// Extension trait for `LocalSpawn`. |
103 | pub trait LocalSpawnExt: LocalSpawn { |
104 | /// Spawns a task that polls the given future with output `()` to |
105 | /// completion. |
106 | /// |
107 | /// This method returns a [`Result`] that contains a [`SpawnError`] if |
108 | /// spawning fails. |
109 | /// |
110 | /// You can use [`spawn_with_handle`](SpawnExt::spawn_with_handle) if |
111 | /// you want to spawn a future with output other than `()` or if you want |
112 | /// to be able to await its completion. |
113 | /// |
114 | /// Note this method will eventually be replaced with the upcoming |
115 | /// `Spawn::spawn` method which will take a `dyn Future` as input. |
116 | /// Technical limitations prevent `Spawn::spawn` from being implemented |
117 | /// today. Feel free to use this method in the meantime. |
118 | /// |
119 | /// ``` |
120 | /// use futures::executor::LocalPool; |
121 | /// use futures::task::LocalSpawnExt; |
122 | /// |
123 | /// let executor = LocalPool::new(); |
124 | /// let spawner = executor.spawner(); |
125 | /// |
126 | /// let future = async { /* ... */ }; |
127 | /// spawner.spawn_local(future).unwrap(); |
128 | /// ``` |
129 | #[cfg (feature = "alloc" )] |
130 | fn spawn_local<Fut>(&self, future: Fut) -> Result<(), SpawnError> |
131 | where |
132 | Fut: Future<Output = ()> + 'static, |
133 | { |
134 | self.spawn_local_obj(LocalFutureObj::new(Box::new(future))) |
135 | } |
136 | |
137 | /// Spawns a task that polls the given future to completion and returns a |
138 | /// future that resolves to the spawned future's output. |
139 | /// |
140 | /// This method returns a [`Result`] that contains a [`RemoteHandle`](crate::future::RemoteHandle), or, if |
141 | /// spawning fails, a [`SpawnError`]. [`RemoteHandle`](crate::future::RemoteHandle) is a future that |
142 | /// resolves to the output of the spawned future. |
143 | /// |
144 | /// ``` |
145 | /// use futures::executor::LocalPool; |
146 | /// use futures::task::LocalSpawnExt; |
147 | /// |
148 | /// let mut executor = LocalPool::new(); |
149 | /// let spawner = executor.spawner(); |
150 | /// |
151 | /// let future = async { 1 }; |
152 | /// let join_handle_fut = spawner.spawn_local_with_handle(future).unwrap(); |
153 | /// assert_eq!(executor.run_until(join_handle_fut), 1); |
154 | /// ``` |
155 | #[cfg (feature = "channel" )] |
156 | #[cfg_attr (docsrs, doc(cfg(feature = "channel" )))] |
157 | #[cfg (feature = "std" )] |
158 | fn spawn_local_with_handle<Fut>( |
159 | &self, |
160 | future: Fut, |
161 | ) -> Result<RemoteHandle<Fut::Output>, SpawnError> |
162 | where |
163 | Fut: Future + 'static, |
164 | { |
165 | let (future, handle) = future.remote_handle(); |
166 | self.spawn_local(future)?; |
167 | Ok(handle) |
168 | } |
169 | } |
170 | |