summaryrefslogtreecommitdiffstats
path: root/tokio/src/executor/executor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tokio/src/executor/executor.rs')
-rw-r--r--tokio/src/executor/executor.rs181
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()
+ }
+}