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