futures_task/
spawn.rs

1use crate::{FutureObj, LocalFutureObj};
2use core::fmt;
3
4/// The `Spawn` trait allows for pushing futures onto an executor that will
5/// run them to completion.
6pub trait Spawn {
7    /// Spawns a future that will be run to completion.
8    ///
9    /// # Errors
10    ///
11    /// The executor may be unable to spawn tasks. Spawn errors should
12    /// represent relatively rare scenarios, such as the executor
13    /// having been shut down so that it is no longer able to accept
14    /// tasks.
15    fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError>;
16
17    /// Determines whether the executor is able to spawn new tasks.
18    ///
19    /// This method will return `Ok` when the executor is *likely*
20    /// (but not guaranteed) to accept a subsequent spawn attempt.
21    /// Likewise, an `Err` return means that `spawn` is likely, but
22    /// not guaranteed, to yield an error.
23    #[inline]
24    fn status(&self) -> Result<(), SpawnError> {
25        Ok(())
26    }
27}
28
29/// The `LocalSpawn` is similar to [`Spawn`], but allows spawning futures
30/// that don't implement `Send`.
31pub trait LocalSpawn {
32    /// Spawns a future that will be run to completion.
33    ///
34    /// # Errors
35    ///
36    /// The executor may be unable to spawn tasks. Spawn errors should
37    /// represent relatively rare scenarios, such as the executor
38    /// having been shut down so that it is no longer able to accept
39    /// tasks.
40    fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError>;
41
42    /// Determines whether the executor is able to spawn new tasks.
43    ///
44    /// This method will return `Ok` when the executor is *likely*
45    /// (but not guaranteed) to accept a subsequent spawn attempt.
46    /// Likewise, an `Err` return means that `spawn` is likely, but
47    /// not guaranteed, to yield an error.
48    #[inline]
49    fn status_local(&self) -> Result<(), SpawnError> {
50        Ok(())
51    }
52}
53
54/// An error that occurred during spawning.
55pub struct SpawnError {
56    _priv: (),
57}
58
59impl fmt::Debug for SpawnError {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        f.debug_tuple("SpawnError").field(&"shutdown").finish()
62    }
63}
64
65impl fmt::Display for SpawnError {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(f, "Executor is shutdown")
68    }
69}
70
71#[cfg(feature = "std")]
72impl std::error::Error for SpawnError {}
73
74impl SpawnError {
75    /// Spawning failed because the executor has been shut down.
76    pub fn shutdown() -> Self {
77        Self { _priv: () }
78    }
79
80    /// Check whether spawning failed to the executor being shut down.
81    pub fn is_shutdown(&self) -> bool {
82        true
83    }
84}
85
86impl<Sp: ?Sized + Spawn> Spawn for &Sp {
87    fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
88        Sp::spawn_obj(self, future)
89    }
90
91    fn status(&self) -> Result<(), SpawnError> {
92        Sp::status(self)
93    }
94}
95
96impl<Sp: ?Sized + Spawn> Spawn for &mut Sp {
97    fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
98        Sp::spawn_obj(self, future)
99    }
100
101    fn status(&self) -> Result<(), SpawnError> {
102        Sp::status(self)
103    }
104}
105
106impl<Sp: ?Sized + LocalSpawn> LocalSpawn for &Sp {
107    fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
108        Sp::spawn_local_obj(self, future)
109    }
110
111    fn status_local(&self) -> Result<(), SpawnError> {
112        Sp::status_local(self)
113    }
114}
115
116impl<Sp: ?Sized + LocalSpawn> LocalSpawn for &mut Sp {
117    fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
118        Sp::spawn_local_obj(self, future)
119    }
120
121    fn status_local(&self) -> Result<(), SpawnError> {
122        Sp::status_local(self)
123    }
124}
125
126#[cfg(feature = "alloc")]
127mod if_alloc {
128    use super::*;
129    use alloc::{boxed::Box, rc::Rc};
130
131    impl<Sp: ?Sized + Spawn> Spawn for Box<Sp> {
132        fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
133            (**self).spawn_obj(future)
134        }
135
136        fn status(&self) -> Result<(), SpawnError> {
137            (**self).status()
138        }
139    }
140
141    impl<Sp: ?Sized + LocalSpawn> LocalSpawn for Box<Sp> {
142        fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
143            (**self).spawn_local_obj(future)
144        }
145
146        fn status_local(&self) -> Result<(), SpawnError> {
147            (**self).status_local()
148        }
149    }
150
151    impl<Sp: ?Sized + Spawn> Spawn for Rc<Sp> {
152        fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
153            (**self).spawn_obj(future)
154        }
155
156        fn status(&self) -> Result<(), SpawnError> {
157            (**self).status()
158        }
159    }
160
161    impl<Sp: ?Sized + LocalSpawn> LocalSpawn for Rc<Sp> {
162        fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
163            (**self).spawn_local_obj(future)
164        }
165
166        fn status_local(&self) -> Result<(), SpawnError> {
167            (**self).status_local()
168        }
169    }
170
171    #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
172    impl<Sp: ?Sized + Spawn> Spawn for alloc::sync::Arc<Sp> {
173        fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
174            (**self).spawn_obj(future)
175        }
176
177        fn status(&self) -> Result<(), SpawnError> {
178            (**self).status()
179        }
180    }
181
182    #[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
183    impl<Sp: ?Sized + LocalSpawn> LocalSpawn for alloc::sync::Arc<Sp> {
184        fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
185            (**self).spawn_local_obj(future)
186        }
187
188        fn status_local(&self) -> Result<(), SpawnError> {
189            (**self).status_local()
190        }
191    }
192}