Skip to main content

zbus/abstractions/
mod.rs

1//! This mod contains a bunch of abstractions.
2//!
3//! These abstractions allow us to make use of the appropriate API depending on which features are
4//! enabled.
5
6/// Evaluates the `tokio` or `async-io` expression for the active backend.
7///
8/// With a single backend it resolves to that backend's expression at compile time; with both it
9/// picks at runtime via [`use_tokio`]. The inactive arm is `cfg`-stripped, so each arm only needs
10/// to be valid in the configurations where its backend is compiled in.
11///
12/// The choice is re-evaluated on every call, so this is only safe where it doesn't need to match a
13/// particular connection's backend. A connection latches its backend once at build time (see
14/// [`Executor::new`]); use that instead of this macro for anything tied to the socket's reactor.
15/// The current call sites (timers, the blocking pool) are independent of the socket, so a per-call
16/// decision is fine.
17macro_rules! select_runtime {
18    (tokio: $tokio:expr, async_io: $async_io:expr $(,)?) => {{
19        #[cfg(all(feature = "tokio", feature = "async-io"))]
20        {
21            if $crate::abstractions::use_tokio() {
22                $tokio
23            } else {
24                $async_io
25            }
26        }
27        #[cfg(all(feature = "tokio", not(feature = "async-io")))]
28        {
29            $tokio
30        }
31        #[cfg(all(feature = "async-io", not(feature = "tokio")))]
32        {
33            $async_io
34        }
35    }};
36}
37pub(crate) use select_runtime;
38
39/// Whether zbus should use tokio (rather than `async-io`) for its I/O.
40///
41/// Only consulted when `async-io` is compiled in, since that's the only time there's a choice. With
42/// both backends we use tokio when a tokio runtime is active on the current thread; with only
43/// `async-io` the answer is always `false`. This keeps the features additive: enabling `tokio`
44/// elsewhere in the dependency graph doesn't force every zbus user into a tokio runtime.
45#[cfg(feature = "async-io")]
46pub(crate) fn use_tokio() -> bool {
47    #[cfg(feature = "tokio")]
48    {
49        tokio::runtime::Handle::try_current().is_ok()
50    }
51    #[cfg(not(feature = "tokio"))]
52    {
53        false
54    }
55}
56
57mod executor;
58pub use executor::*;
59mod async_drop;
60pub(crate) mod async_lock;
61pub use async_drop::*;
62pub(crate) mod timeout;
63
64// Not unix-specific itself but only used on unix.
65#[cfg(target_family = "unix")]
66pub(crate) mod process;
67
68#[cfg(all(test, feature = "tokio", feature = "async-io"))]
69mod tests {
70    #[test]
71    fn use_tokio_reflects_active_runtime() {
72        assert!(!super::use_tokio(), "no runtime is active here");
73        let runtime = tokio::runtime::Runtime::new().unwrap();
74        assert!(
75            runtime.block_on(async { super::use_tokio() }),
76            "a tokio runtime is active",
77        );
78    }
79}