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")]
spawn<Fut>(&self, future: Fut) -> Result<(), SpawnError> where Fut: Future<Output = ()> + Send + 'static,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")]
spawn_with_handle<Fut>(&self, future: Fut) -> Result<RemoteHandle<Fut::Output>, SpawnError> where Fut: Future + Send + 'static, Fut::Output: Send,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")))]
compat(self) -> Compat<Self> where Self: Sized,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")]
spawn_local<Fut>(&self, future: Fut) -> Result<(), SpawnError> where Fut: Future<Output = ()> + 'static,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")]
spawn_local_with_handle<Fut>( &self, future: Fut, ) -> Result<RemoteHandle<Fut::Output>, SpawnError> where Fut: Future + 'static,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