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(name:"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}
193