1use futures_task::{LocalSpawn, Spawn};
2
3#[cfg(feature = "compat")]
4use crate::compat::Compat;
5
6#[cfg(feature = "channel")]
7#[cfg(feature = "std")]
8use crate::future::{FutureExt, RemoteHandle};
9#[cfg(feature = "alloc")]
10use alloc::boxed::Box;
11#[cfg(feature = "alloc")]
12use futures_core::future::Future;
13#[cfg(feature = "alloc")]
14use futures_task::{FutureObj, LocalFutureObj, SpawnError};
15
16impl<Sp: ?Sized> SpawnExt for Sp where Sp: Spawn {}
17impl<Sp: ?Sized> LocalSpawnExt for Sp where Sp: LocalSpawn {}
18
19/// Extension trait for `Spawn`.
20pub 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`.
103pub 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