diff options
Diffstat (limited to 'tokio/src/executor/executor.rs')
-rw-r--r-- | tokio/src/executor/executor.rs | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/tokio/src/executor/executor.rs b/tokio/src/executor/executor.rs new file mode 100644 index 00000000..5eeb43a2 --- /dev/null +++ b/tokio/src/executor/executor.rs @@ -0,0 +1,181 @@ +use crate::executor::SpawnError; + +use futures_util::future::{FutureExt, RemoteHandle}; +use std::future::Future; +use std::pin::Pin; + +/// A value that executes futures. +/// +/// The [`spawn`] function is used to submit a future to an executor. Once +/// submitted, the executor takes ownership of the future and becomes +/// responsible for driving the future to completion. +/// +/// The strategy employed by the executor to handle the future is less defined +/// and is left up to the `Executor` implementation. The `Executor` instance is +/// expected to call [`poll`] on the future once it has been notified, however +/// the "when" and "how" can vary greatly. +/// +/// For example, the executor might be a thread pool, in which case a set of +/// threads have already been spawned up and the future is inserted into a +/// queue. A thread will acquire the future and poll it. +/// +/// The `Executor` trait is only for futures that **are** `Send`. These are most +/// common. There currently is no trait that describes executors that operate +/// entirely on the current thread (i.e., are able to spawn futures that are not +/// `Send`). Note that single threaded executors can still implement `Executor`, +/// but only futures that are `Send` can be spawned via the trait. +/// +/// This trait is primarily intended to implemented by executors and used to +/// back `tokio::spawn`. Libraries and applications **may** use this trait to +/// bound generics, but doing so will limit usage to futures that implement +/// `Send`. Instead, libraries and applications are recommended to use +/// [`TypedExecutor`] as a bound. +/// +/// # Errors +/// +/// The [`spawn`] function returns `Result` with an error type of `SpawnError`. +/// This error type represents the reason that the executor was unable to spawn +/// the future. The two current represented scenarios are: +/// +/// * An executor being at capacity or full. As such, the executor is not able +/// to accept a new future. This error state is expected to be transient. +/// * An executor has been shutdown and can no longer accept new futures. This +/// error state is expected to be permanent. +/// +/// If a caller encounters an at capacity error, the caller should try to shed +/// load. This can be as simple as dropping the future that was spawned. +/// +/// If the caller encounters a shutdown error, the caller should attempt to +/// gracefully shutdown. +/// +/// # Examples +/// +/// ``` +/// use tokio::executor::Executor; +/// +/// # fn docs(my_executor: &mut dyn Executor) { +/// my_executor.spawn(Box::pin(async { +/// println!("running on the executor"); +/// })).unwrap(); +/// # } +/// ``` +/// +/// [`spawn`]: #tymethod.spawn +/// [`poll`]: https://doc.rust-lang.org/std/future/trait.Future.html#tymethod.poll +/// [`TypedExecutor`]: ../trait.TypedExecutor.html +pub trait Executor { + /// Spawns a future object to run on this executor. + /// + /// `future` is passed to the executor, which will begin running it. The + /// future may run on the current thread or another thread at the discretion + /// of the `Executor` implementation. + /// + /// # Panics + /// + /// Implementations are encouraged to avoid panics. However, panics are + /// permitted and the caller should check the implementation specific + /// documentation for more details on possible panics. + /// + /// # Examples + /// + /// ``` + /// use tokio::executor::Executor; + /// + /// # fn docs(my_executor: &mut dyn Executor) { + /// my_executor.spawn(Box::pin(async { + /// println!("running on the executor"); + /// })).unwrap(); + /// # } + /// ``` + fn spawn(&mut self, future: Pin<Box<dyn Future<Output = ()> + Send>>) + -> Result<(), SpawnError>; + + /// Provides a best effort **hint** to whether or not `spawn` will succeed. + /// + /// This function may return both false positives **and** false negatives. + /// If `status` returns `Ok`, then a call to `spawn` will *probably* + /// succeed, but may fail. If `status` returns `Err`, a call to `spawn` will + /// *probably* fail, but may succeed. + /// + /// This allows a caller to avoid creating the task if the call to `spawn` + /// has a high likelihood of failing. + /// + /// # Panics + /// + /// This function must not panic. Implementers must ensure that panics do + /// not happen. + /// + /// # Examples + /// + /// ``` + /// use tokio::executor::Executor; + /// + /// # fn docs(my_executor: &mut dyn Executor) { + /// if my_executor.status().is_ok() { + /// my_executor.spawn(Box::pin(async { + /// println!("running on the executor"); + /// })).unwrap(); + /// } else { + /// println!("the executor is not in a good state"); + /// } + /// # } + /// ``` + fn status(&self) -> Result<(), SpawnError> { + Ok(()) + } +} + +impl dyn Executor { + /// Spawns a future object to run on this executor, returning a result of + /// its `RemoteHandle`. + /// + /// `future` is passed to the executor, which will begin running it. The + /// future may run on the current thread or another thread at the discretion + /// of the `Executor` implementation. + /// + /// # Panics + /// + /// Implementations are encouraged to avoid panics. However, panics are + /// permitted and the caller should check the implementation specific + /// documentation for more details on possible panics. + /// + /// # Examples + /// + /// ``` + /// use tokio::executor::Executor; + /// use futures_util::future::FutureExt; + /// + /// # fn docs(my_executor: &'static mut (dyn Executor + 'static)) { + /// let handle = my_executor.spawn_with_handle(Box::pin(async { + /// println!("running on the executor"); + /// })).unwrap(); + /// + /// let handle = handle.map(|_| println!("the future has completed")); + /// # } + /// ``` + pub fn spawn_with_handle<Fut>( + &mut self, + future: Fut, + ) -> Result<RemoteHandle<Fut::Output>, SpawnError> + where + Fut: Future + Send + 'static, + Fut::Output: Send, + { + let (future, handle) = future.remote_handle(); + self.spawn(Box::pin(future))?; + Ok(handle) + } +} + +impl<E: Executor + ?Sized> Executor for Box<E> { + fn spawn( + &mut self, + future: Pin<Box<dyn Future<Output = ()> + Send>>, + ) -> Result<(), SpawnError> { + (**self).spawn(future) + } + + fn status(&self) -> Result<(), SpawnError> { + (**self).status() + } +} |