futures_util/task/
spawn.rs

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}