deadpool_runtime/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![deny(
4    nonstandard_style,
5    rust_2018_idioms,
6    rustdoc::broken_intra_doc_links,
7    rustdoc::private_intra_doc_links
8)]
9#![forbid(non_ascii_idents, unsafe_code)]
10#![warn(
11    deprecated_in_future,
12    missing_copy_implementations,
13    missing_debug_implementations,
14    missing_docs,
15    unreachable_pub,
16    unused_import_braces,
17    unused_labels,
18    unused_lifetimes,
19    unused_qualifications,
20    unused_results
21)]
22#![allow(clippy::uninlined_format_args)]
23
24use std::{any::Any, fmt, future::Future, time::Duration};
25
26/// Enumeration for picking a runtime implementation.
27#[derive(Clone, Copy, Debug, Eq, PartialEq)]
28pub enum Runtime {
29    #[cfg(feature = "tokio_1")]
30    #[cfg_attr(docsrs, doc(cfg(feature = "tokio_1")))]
31    /// [`tokio` 1.0](tokio_1) runtime.
32    Tokio1,
33
34    #[cfg(feature = "async-std_1")]
35    #[cfg_attr(docsrs, doc(cfg(feature = "async-std_1")))]
36    /// [`async-std` 1.0](async_std_1) runtime.
37    AsyncStd1,
38}
39
40impl Runtime {
41    /// Requires a [`Future`] to complete before the specified `duration` has
42    /// elapsed.
43    ///
44    /// If the `future` completes before the `duration` has elapsed, then the
45    /// completed value is returned. Otherwise, an error is returned and
46    /// the `future` is canceled.
47    #[allow(unused_variables)]
48    pub async fn timeout<F>(&self, duration: Duration, future: F) -> Option<F::Output>
49    where
50        F: Future,
51    {
52        match self {
53            #[cfg(feature = "tokio_1")]
54            Self::Tokio1 => tokio_1::time::timeout(duration, future).await.ok(),
55            #[cfg(feature = "async-std_1")]
56            Self::AsyncStd1 => async_std_1::future::timeout(duration, future).await.ok(),
57            #[allow(unreachable_patterns)]
58            _ => unreachable!(),
59        }
60    }
61
62    /// Runs the given closure on a thread where blocking is acceptable.
63    ///
64    /// # Errors
65    ///
66    /// See [`SpawnBlockingError`] for details.
67    #[allow(unused_variables)]
68    pub async fn spawn_blocking<F, R>(&self, f: F) -> Result<R, SpawnBlockingError>
69    where
70        F: FnOnce() -> R + Send + 'static,
71        R: Send + 'static,
72    {
73        match self {
74            #[cfg(feature = "tokio_1")]
75            Self::Tokio1 => tokio_1::task::spawn_blocking(f)
76                .await
77                .map_err(|e| SpawnBlockingError::Panic(e.into_panic())),
78            #[cfg(feature = "async-std_1")]
79            Self::AsyncStd1 => Ok(async_std_1::task::spawn_blocking(f).await),
80            #[allow(unreachable_patterns)]
81            _ => unreachable!(),
82        }
83    }
84
85    /// Runs the given closure on a thread where blocking is acceptable.
86    ///
87    /// It works similar to [`Runtime::spawn_blocking()`] but doesn't return a
88    /// [`Future`] and is meant to be used for background tasks.
89    ///
90    /// # Errors
91    ///
92    /// See [`SpawnBlockingError`] for details.
93    #[allow(unused_variables)]
94    pub fn spawn_blocking_background<F>(&self, f: F) -> Result<(), SpawnBlockingError>
95    where
96        F: FnOnce() + Send + 'static,
97    {
98        match self {
99            #[cfg(feature = "tokio_1")]
100            Self::Tokio1 => {
101                drop(tokio_1::task::spawn_blocking(f));
102                Ok(())
103            }
104            #[cfg(feature = "async-std_1")]
105            Self::AsyncStd1 => {
106                drop(async_std_1::task::spawn_blocking(f));
107                Ok(())
108            }
109            #[allow(unreachable_patterns)]
110            _ => unreachable!(),
111        }
112    }
113}
114
115/// Error of spawning a task on a thread where blocking is acceptable.
116#[derive(Debug)]
117pub enum SpawnBlockingError {
118    /// Spawned task has panicked.
119    Panic(Box<dyn Any + Send + 'static>),
120}
121
122impl fmt::Display for SpawnBlockingError {
123    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124        match self {
125            Self::Panic(p) => write!(f, "SpawnBlockingError: Panic: {:?}", p),
126        }
127    }
128}
129
130impl std::error::Error for SpawnBlockingError {}