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_target_has_atomic! { 172 use alloc::{ sync::Arc }; 173 174 impl<Sp: ?Sized + Spawn> Spawn for Arc<Sp> { 175 fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { 176 (**self).spawn_obj(future) 177 } 178 179 fn status(&self) -> Result<(), SpawnError> { 180 (**self).status() 181 } 182 } 183 184 impl<Sp: ?Sized + LocalSpawn> LocalSpawn for Arc<Sp> { 185 fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { 186 (**self).spawn_local_obj(future) 187 } 188 189 fn status_local(&self) -> Result<(), SpawnError> { 190 (**self).status_local() 191 } 192 } 193 } 194 } 195