1 use crate::{FutureObj, LocalFutureObj};
2 use core::fmt;
3 
4 /// The `Spawn` trait allows for pushing futures onto an executor that will
5 /// run them to completion.
6 pub 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.
spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError>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]
status(&self) -> Result<(), SpawnError>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`.
31 pub 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.
spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError>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]
status_local(&self) -> Result<(), SpawnError>49     fn status_local(&self) -> Result<(), SpawnError> {
50         Ok(())
51     }
52 }
53 
54 /// An error that occurred during spawning.
55 pub struct SpawnError {
56     _priv: (),
57 }
58 
59 impl fmt::Debug for SpawnError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result60     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61         f.debug_tuple("SpawnError").field(&"shutdown").finish()
62     }
63 }
64 
65 impl fmt::Display for SpawnError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result66     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67         write!(f, "Executor is shutdown")
68     }
69 }
70 
71 #[cfg(feature = "std")]
72 impl std::error::Error for SpawnError {}
73 
74 impl SpawnError {
75     /// Spawning failed because the executor has been shut down.
shutdown() -> Self76     pub fn shutdown() -> Self {
77         Self { _priv: () }
78     }
79 
80     /// Check whether spawning failed to the executor being shut down.
is_shutdown(&self) -> bool81     pub fn is_shutdown(&self) -> bool {
82         true
83     }
84 }
85 
86 impl<Sp: ?Sized + Spawn> Spawn for &Sp {
spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError>87     fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
88         Sp::spawn_obj(self, future)
89     }
90 
status(&self) -> Result<(), SpawnError>91     fn status(&self) -> Result<(), SpawnError> {
92         Sp::status(self)
93     }
94 }
95 
96 impl<Sp: ?Sized + Spawn> Spawn for &mut Sp {
spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError>97     fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
98         Sp::spawn_obj(self, future)
99     }
100 
status(&self) -> Result<(), SpawnError>101     fn status(&self) -> Result<(), SpawnError> {
102         Sp::status(self)
103     }
104 }
105 
106 impl<Sp: ?Sized + LocalSpawn> LocalSpawn for &Sp {
spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError>107     fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
108         Sp::spawn_local_obj(self, future)
109     }
110 
status_local(&self) -> Result<(), SpawnError>111     fn status_local(&self) -> Result<(), SpawnError> {
112         Sp::status_local(self)
113     }
114 }
115 
116 impl<Sp: ?Sized + LocalSpawn> LocalSpawn for &mut Sp {
spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError>117     fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
118         Sp::spawn_local_obj(self, future)
119     }
120 
status_local(&self) -> Result<(), SpawnError>121     fn status_local(&self) -> Result<(), SpawnError> {
122         Sp::status_local(self)
123     }
124 }
125 
126 #[cfg(feature = "alloc")]
127 mod if_alloc {
128     use super::*;
129     use alloc::{boxed::Box, rc::Rc};
130 
131     impl<Sp: ?Sized + Spawn> Spawn for Box<Sp> {
spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError>132         fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
133             (**self).spawn_obj(future)
134         }
135 
status(&self) -> Result<(), SpawnError>136         fn status(&self) -> Result<(), SpawnError> {
137             (**self).status()
138         }
139     }
140 
141     impl<Sp: ?Sized + LocalSpawn> LocalSpawn for Box<Sp> {
spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError>142         fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
143             (**self).spawn_local_obj(future)
144         }
145 
status_local(&self) -> Result<(), SpawnError>146         fn status_local(&self) -> Result<(), SpawnError> {
147             (**self).status_local()
148         }
149     }
150 
151     impl<Sp: ?Sized + Spawn> Spawn for Rc<Sp> {
spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError>152         fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
153             (**self).spawn_obj(future)
154         }
155 
status(&self) -> Result<(), SpawnError>156         fn status(&self) -> Result<(), SpawnError> {
157             (**self).status()
158         }
159     }
160 
161     impl<Sp: ?Sized + LocalSpawn> LocalSpawn for Rc<Sp> {
spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError>162         fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
163             (**self).spawn_local_obj(future)
164         }
165 
status_local(&self) -> Result<(), SpawnError>166         fn status_local(&self) -> Result<(), SpawnError> {
167             (**self).status_local()
168         }
169     }
170 
171     #[cfg(not(futures_no_atomic_cas))]
172     impl<Sp: ?Sized + Spawn> Spawn for alloc::sync::Arc<Sp> {
spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError>173         fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
174             (**self).spawn_obj(future)
175         }
176 
status(&self) -> Result<(), SpawnError>177         fn status(&self) -> Result<(), SpawnError> {
178             (**self).status()
179         }
180     }
181 
182     #[cfg(not(futures_no_atomic_cas))]
183     impl<Sp: ?Sized + LocalSpawn> LocalSpawn for alloc::sync::Arc<Sp> {
spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError>184         fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
185             (**self).spawn_local_obj(future)
186         }
187 
status_local(&self) -> Result<(), SpawnError>188         fn status_local(&self) -> Result<(), SpawnError> {
189             (**self).status_local()
190         }
191     }
192 }
193