1//! Entry points for use with Tokio runtimes.
2use crate::impls::tokio::TokioRuntimeHandle as Handle;
34use crate::{CompoundRuntime, RealCoarseTimeProvider, ToplevelBlockOn};
5use std::io::{Error as IoError, Resultas IoResult};
67#[cfg(feature = "native-tls")]
8use crate::impls::native_tls::NativeTlsProvider;
9#[cfg(feature = "rustls")]
10use crate::impls::rustls::RustlsProvider;
1112/// An alias for the Tokio runtime that we prefer to use, based on whatever TLS
13/// implementation has been enabled.
14///
15/// If only one of `native_tls` and `rustls` bas been enabled within the
16/// `tor-rtcompat` crate, that will be the TLS backend that this uses.
17///
18/// Currently, `native_tls` is preferred over `rustls` when both are available,
19/// because of its maturity within Arti. However, this might change in the
20/// future.
21#[cfg(feature = "native-tls")]
22pub use TokioNativeTlsRuntime as PreferredRuntime;
23#[cfg(all(feature = "rustls", not(feature = "native-tls")))]
24pub use TokioRustlsRuntime as PreferredRuntime;
2526/// A [`Runtime`](crate::Runtime) built around a Handle to a tokio runtime, and `native_tls`.
27///
28/// # Limitations
29///
30/// Note that Arti requires that the runtime should have working
31/// implementations for Tokio's time, net, and io facilities, but we have
32/// no good way to check that when creating this object.
33#[derive(Clone)]
34#[cfg(feature = "native-tls")]
35pub struct TokioNativeTlsRuntime {
36/// The actual [`CompoundRuntime`] that implements this.
37inner: HandleInner,
38}
3940/// Implementation type for a TokioRuntimeHandle.
41#[cfg(feature = "native-tls")]
42type HandleInner = CompoundRuntime<
43 Handle,
44 Handle,
45 RealCoarseTimeProvider,
46 Handle,
47 Handle,
48 NativeTlsProvider,
49 Handle,
50>;
5152/// A [`Runtime`](crate::Runtime) built around a Handle to a tokio runtime, and `rustls`.
53#[derive(Clone)]
54#[cfg(feature = "rustls")]
55pub struct TokioRustlsRuntime {
56/// The actual [`CompoundRuntime`] that implements this.
57inner: RustlsHandleInner,
58}
5960/// Implementation for a TokioRuntimeRustlsHandle
61#[cfg(feature = "rustls")]
62type RustlsHandleInner =
63 CompoundRuntime<Handle, Handle, RealCoarseTimeProvider, Handle, Handle, RustlsProvider, Handle>;
6465#[cfg(feature = "native-tls")]
66crate::opaque::implement_opaque_runtime! {
67 TokioNativeTlsRuntime { inner : HandleInner }
68}
6970#[cfg(feature = "rustls")]
71crate::opaque::implement_opaque_runtime! {
72 TokioRustlsRuntime { inner : RustlsHandleInner }
73}
7475#[cfg(feature = "native-tls")]
76impl From<tokio_crate::runtime::Handle> for TokioNativeTlsRuntime {
77fn from(h: tokio_crate::runtime::Handle) -> Self {
78let h = Handle::new(h);
79 TokioNativeTlsRuntime {
80 inner: CompoundRuntime::new(
81 h.clone(),
82 h.clone(),
83 RealCoarseTimeProvider::new(),
84 h.clone(),
85 h.clone(),
86 NativeTlsProvider::default(),
87 h,
88 ),
89 }
90 }
91}
9293#[cfg(feature = "rustls")]
94impl From<tokio_crate::runtime::Handle> for TokioRustlsRuntime {
95fn from(h: tokio_crate::runtime::Handle) -> Self {
96let h = Handle::new(h);
97 TokioRustlsRuntime {
98 inner: CompoundRuntime::new(
99 h.clone(),
100 h.clone(),
101 RealCoarseTimeProvider::new(),
102 h.clone(),
103 h.clone(),
104 RustlsProvider::default(),
105 h,
106 ),
107 }
108 }
109}
110111#[cfg(feature = "native-tls")]
112impl TokioNativeTlsRuntime {
113/// Create a new [`TokioNativeTlsRuntime`].
114 ///
115 /// The return value will own the underlying Tokio runtime object, which
116 /// will be dropped when the last copy of this handle is freed.
117 ///
118 /// If you want to use a currently running runtime instead, call
119 /// [`TokioNativeTlsRuntime::current()`].
120pub fn create() -> IoResult<Self> {
121crate::impls::tokio::create_runtime().map(|r| TokioNativeTlsRuntime {
122 inner: CompoundRuntime::new(
123 r.clone(),
124 r.clone(),
125 RealCoarseTimeProvider::new(),
126 r.clone(),
127 r.clone(),
128 NativeTlsProvider::default(),
129 r,
130 ),
131 })
132 }
133134/// Return a [`TokioNativeTlsRuntime`] wrapping the currently running
135 /// Tokio runtime.
136 ///
137 /// # Usage note
138 ///
139 /// We should never call this from inside other Arti crates, or from library
140 /// crates that want to support multiple runtimes! This function is for
141 /// Arti _users_ who want to wrap some existing Tokio runtime as a
142 /// [`Runtime`](crate::Runtime). It is not for library crates that want to work with
143 /// multiple runtimes.
144 ///
145 /// Once you have a runtime returned by this function, you should just
146 /// create more handles to it via [`Clone`].
147pub fn current() -> IoResult<Self> {
148Ok(current_handle()?.into())
149 }
150151/// Helper to run a single test function in a freshly created runtime.
152 ///
153 /// # Panics
154 ///
155 /// Panics if we can't create this runtime.
156 ///
157 /// # Warning
158 ///
159 /// This API is **NOT** for consumption outside Arti. Semver guarantees are not provided.
160#[doc(hidden)]
161pub fn run_test<P, F, O>(func: P) -> O
162where
163P: FnOnce(Self) -> F,
164 F: futures::Future<Output = O>,
165 {
166let runtime = Self::create().expect("Failed to create runtime");
167 runtime.clone().block_on(func(runtime))
168 }
169}
170171#[cfg(feature = "rustls")]
172impl TokioRustlsRuntime {
173/// Create a new [`TokioRustlsRuntime`].
174 ///
175 /// The return value will own the underlying Tokio runtime object, which
176 /// will be dropped when the last copy of this handle is freed.
177 ///
178 /// If you want to use a currently running runtime instead, call
179 /// [`TokioRustlsRuntime::current()`].
180pub fn create() -> IoResult<Self> {
181crate::impls::tokio::create_runtime().map(|r| TokioRustlsRuntime {
182 inner: CompoundRuntime::new(
183 r.clone(),
184 r.clone(),
185 RealCoarseTimeProvider::new(),
186 r.clone(),
187 r.clone(),
188 RustlsProvider::default(),
189 r,
190 ),
191 })
192 }
193194/// Return a [`TokioRustlsRuntime`] wrapping the currently running
195 /// Tokio runtime.
196 ///
197 /// # Usage note
198 ///
199 /// We should never call this from inside other Arti crates, or from library
200 /// crates that want to support multiple runtimes! This function is for
201 /// Arti _users_ who want to wrap some existing Tokio runtime as a
202 /// [`Runtime`](crate::Runtime). It is not for library crates that want to work with
203 /// multiple runtimes.
204 ///
205 /// Once you have a runtime returned by this function, you should just
206 /// create more handles to it via [`Clone`].
207pub fn current() -> IoResult<Self> {
208Ok(current_handle()?.into())
209 }
210211/// Helper to run a single test function in a freshly created runtime.
212 ///
213 /// # Panics
214 ///
215 /// Panics if we can't create this runtime.
216 ///
217 /// # Warning
218 ///
219 /// This API is **NOT** for consumption outside Arti. Semver guarantees are not provided.
220#[doc(hidden)]
221pub fn run_test<P, F, O>(func: P) -> O
222where
223P: FnOnce(Self) -> F,
224 F: futures::Future<Output = O>,
225 {
226let runtime = Self::create().expect("Failed to create runtime");
227 runtime.clone().block_on(func(runtime))
228 }
229}
230231/// As `Handle::try_current()`, but return an IoError on failure.
232#[cfg(any(feature = "native-tls", feature = "rustls"))]
233fn current_handle() -> std::io::Result<tokio_crate::runtime::Handle> {
234 tokio_crate::runtime::Handle::try_current().map_err(IoError::other)
235}
236237#[cfg(all(
238 test,
239 not(miri), // tokio makes some syscalls that don't work with miri
240))]
241mod test {
242// @@ begin test lint list maintained by maint/add_warning @@
243#![allow(clippy::bool_assert_comparison)]
244 #![allow(clippy::clone_on_copy)]
245 #![allow(clippy::dbg_macro)]
246 #![allow(clippy::mixed_attributes_style)]
247 #![allow(clippy::print_stderr)]
248 #![allow(clippy::print_stdout)]
249 #![allow(clippy::single_char_pattern)]
250 #![allow(clippy::unwrap_used)]
251 #![allow(clippy::unchecked_duration_subtraction)]
252 #![allow(clippy::useless_vec)]
253 #![allow(clippy::needless_pass_by_value)]
254//! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
255use super::*;
256257#[test]
258fn no_current() {
259// There should be no running tokio runtime in this context.
260261#[cfg(feature = "native-tls")]
262assert!(TokioNativeTlsRuntime::current().is_err());
263264#[cfg(feature = "rustls")]
265assert!(TokioRustlsRuntime::current().is_err());
266 }
267268#[test]
269fn current() {
270// Now start a tokio runtime and make sure that the "current" functions do work in that case.
271let runtime = PreferredRuntime::create().unwrap();
272 runtime.block_on(async {
273#[cfg(feature = "native-tls")]
274assert!(TokioNativeTlsRuntime::current().is_ok());
275276#[cfg(feature = "rustls")]
277assert!(TokioRustlsRuntime::current().is_ok());
278 });
279 }
280281#[test]
282fn debug() {
283#[cfg(feature = "native-tls")]
284assert_eq!(
285format!("{:?}", TokioNativeTlsRuntime::create().unwrap()),
286"TokioNativeTlsRuntime { .. }"
287);
288#[cfg(feature = "rustls")]
289assert_eq!(
290format!("{:?}", TokioRustlsRuntime::create().unwrap()),
291"TokioRustlsRuntime { .. }"
292);
293294// Just for fun, let's try the Debug output for the Compound.
295assert_eq!(
296format!("{:?}", PreferredRuntime::create().unwrap().inner),
297"CompoundRuntime { .. }"
298);
299 }
300}