Make current/create functions into runtime member functions.

This should help avoid some amount of temptation towards API
proliferation.
This commit is contained in:
Nick Mathewson 2022-01-26 08:40:35 -05:00
parent 2333d0466e
commit 6f29d485e4
9 changed files with 128 additions and 105 deletions

View File

@ -371,7 +371,7 @@ fn main() -> Result<()> {
concurrent: parallel,
upload_payload,
download_payload,
runtime: tor_rtcompat::tokio::create_runtime()?,
runtime: tor_rtcompat::tokio::TokioNativeTlsRuntime::create()?,
results: Default::default(),
};

View File

@ -1,6 +1,7 @@
use anyhow::Result;
use arti_client::{TorClient, TorClientConfig};
use tokio_crate as tokio;
use tor_rtcompat::tokio::TokioNativeTlsRuntime;
use futures::io::{AsyncReadExt, AsyncWriteExt};
@ -16,7 +17,7 @@ async fn main() -> Result<()> {
let config = TorClientConfig::default();
// Arti needs an async runtime handle to spawn async tasks.
// (See "Multiple runtime support" below.)
let rt = tor_rtcompat::tokio::current_runtime()?;
let rt = TokioNativeTlsRuntime::current()?;
eprintln!("connecting to Tor...");

View File

@ -260,7 +260,7 @@ impl TorClient<TokioNativeTlsRuntime> {
pub async fn bootstrap_with_tokio(
config: TorClientConfig,
) -> Result<TorClient<TokioNativeTlsRuntime>> {
let rt = tor_rtcompat::tokio::current_runtime().expect("called outside of Tokio runtime");
let rt = TokioNativeTlsRuntime::current().expect("called outside of Tokio runtime");
Self::bootstrap(rt, config).await
}
}
@ -277,8 +277,7 @@ impl TorClient<AsyncStdNativeTlsRuntime> {
config: TorClientConfig,
) -> Result<TorClient<AsyncStdNativeTlsRuntime>> {
// FIXME(eta): not actually possible for this to fail
let rt =
tor_rtcompat::async_std::current_runtime().expect("failed to get async-std runtime");
let rt = AsyncStdNativeTlsRuntime::current().expect("failed to get async-std runtime");
Self::bootstrap(rt, config).await
}
}

View File

@ -60,7 +60,7 @@
//! let config = TorClientConfig::default();
//! // Arti needs a handle to an async runtime in order to spawn tasks and use the
//! // network. (See "Multiple runtime support" below.)
//! let rt = tor_rtcompat::tokio::current_runtime()?;
//! let rt = tor_rtcompat::tokio::TokioNativeTlsRuntime::current()?;
//!
//! // Start the Arti client, and let it bootstrap a connection to the Tor network.
//! // (This takes a while to gather the necessary directory information.

View File

@ -229,10 +229,12 @@ fn main() -> Result<()> {
process::use_max_file_limit();
#[cfg(feature = "tokio")]
let runtime = tor_rtcompat::tokio::create_runtime()?;
#[cfg(all(feature = "async-std", not(feature = "tokio")))]
let runtime = tor_rtcompat::async_std::create_runtime()?;
use tor_rtcompat::tokio::AsyncStdNativeTlsRuntime as ChosenRuntime;
#[cfg(feature = "tokio")]
use tor_rtcompat::tokio::TokioNativeTlsRuntime as ChosenRuntime;
let runtime = ChosenRuntime::create()?;
let rt_copy = runtime.clone();
rt_copy.block_on(run(runtime, socks_port, client_config))?;

View File

@ -1,6 +1,7 @@
//! Entry points for use with async_std runtimes.
pub use crate::impls::async_std::create_runtime as create_runtime_impl;
use crate::{compound::CompoundRuntime, SpawnBlocking};
use std::io::Result as IoResult;
use crate::impls::native_tls::NativeTlsProvider;
@ -41,32 +42,53 @@ crate::opaque::implement_opaque_runtime! {
AsyncStdRustlsRuntime { inner: RustlsInner }
}
/// Return a new async-std-based [`Runtime`](crate::Runtime).
///
/// Generally you should call this function only once, and then use
/// [`Clone::clone()`] to create additional references to that
/// runtime.
pub fn create_runtime() -> std::io::Result<AsyncStdNativeTlsRuntime> {
let rt = create_runtime_impl();
Ok(AsyncStdNativeTlsRuntime {
inner: CompoundRuntime::new(rt, rt, rt, NativeTlsProvider::default()),
})
impl AsyncStdNativeTlsRuntime {
/// Return a new [`AsyncStdNativeTlsRuntime`]
///
/// Generally you should call this function only once, and then use
/// [`Clone::clone()`] to create additional references to that
/// runtime.
pub fn create() -> IoResult<Self> {
let rt = create_runtime_impl();
Ok(AsyncStdNativeTlsRuntime {
inner: CompoundRuntime::new(rt, rt, rt, NativeTlsProvider::default()),
})
}
/// Return an [`AsyncStdNativeTlsRuntime`] for the currently running
/// `async_std` executor.
///
/// Note that since async_std executors are global, there is no distinction
/// between this method and [`AsyncStdNativeTlsRuntime::create()`]: it is
/// provided only for API consistency with the Tokio runtimes.
pub fn current() -> IoResult<Self> {
Self::create()
}
}
/// Return a new [`Runtime`](crate::Runtime) based on `async_std` and `rustls`.
#[cfg(feature = "rustls")]
pub fn create_rustls_runtime() -> std::io::Result<AsyncStdRustlsRuntime> {
let rt = create_runtime_impl();
Ok(AsyncStdRustlsRuntime {
inner: CompoundRuntime::new(rt, rt, rt, RustlsProvider::default()),
})
}
impl AsyncStdRustlsRuntime {
/// Return a new [`AsyncStdRustlsRuntime`]
///
/// Generally you should call this function only once, and then use
/// [`Clone::clone()`] to create additional references to that
/// runtime.
pub fn create() -> IoResult<Self> {
let rt = create_runtime_impl();
Ok(AsyncStdRustlsRuntime {
inner: CompoundRuntime::new(rt, rt, rt, RustlsProvider::default()),
})
}
/// Try to return an instance of the currently running async_std
/// [`Runtime`](crate::Runtime).
pub fn current_runtime() -> std::io::Result<AsyncStdNativeTlsRuntime> {
// In async_std, the runtime is a global singleton.
create_runtime()
/// Return an [`AsyncStdRustlsRuntime`] for the currently running
/// `async_std` executor.
///
/// Note that since async_std executors are global, there is no distinction
/// between this method and [`AsyncStdNativeTlsRuntime::create()`]: it is
/// provided only for API consistency with the Tokio runtimes.
pub fn current() -> IoResult<Self> {
Self::create()
}
}
/// Run a test function using a freshly created async_std runtime.
@ -75,6 +97,7 @@ where
P: FnOnce(AsyncStdNativeTlsRuntime) -> F,
F: futures::Future<Output = O>,
{
let runtime = current_runtime().expect("Couldn't get global async_std runtime?");
let runtime =
AsyncStdNativeTlsRuntime::create().expect("Couldn't get global async_std runtime?");
runtime.clone().block_on(func(runtime))
}

View File

@ -192,11 +192,11 @@ pub use compound::CompoundRuntime;
pub fn current_user_runtime() -> std::io::Result<impl Runtime> {
#[cfg(feature = "tokio")]
{
crate::tokio::current_runtime()
crate::tokio::TokioNativeTlsRuntime::current()
}
#[cfg(all(feature = "async-std", not(feature = "tokio")))]
{
crate::async_std::current_runtime()
crate::async_std::AsyncStdNativeTlsRuntime::current()
}
}
@ -218,11 +218,11 @@ pub fn current_user_runtime() -> std::io::Result<impl Runtime> {
pub fn create_runtime() -> std::io::Result<impl Runtime> {
#[cfg(feature = "tokio")]
{
crate::tokio::create_runtime()
crate::tokio::TokioNativeTlsRuntime::create()
}
#[cfg(all(feature = "async-std", not(feature = "tokio")))]
{
crate::async_std::create_runtime()
crate::async_std::AsyncStdNativeTlsRuntime::create()
}
}

View File

@ -225,7 +225,7 @@ macro_rules! runtime_tests {
$(
#[test]
fn $id() -> IoResult<()> {
super::$id(&crate::tokio::create_runtime()?)
super::$id(&crate::tokio::TokioNativeTlsRuntime::create()?)
}
)*
}
@ -235,7 +235,7 @@ macro_rules! runtime_tests {
$(
#[test]
fn $id() -> IoResult<()> {
super::$id(&crate::async_std::create_runtime()?)
super::$id(&crate::async_std::AsyncStdNativeTlsRuntime::create()?)
}
)*
}
@ -250,7 +250,7 @@ macro_rules! tls_runtime_tests {
$(
#[test]
fn $id() -> IoResult<()> {
super::$id(&crate::tokio::create_runtime()?)
super::$id(&crate::tokio::TokioNativeTlsRuntime::create()?)
}
)*
}
@ -260,7 +260,7 @@ macro_rules! tls_runtime_tests {
$(
#[test]
fn $id() -> IoResult<()> {
super::$id(&crate::async_std::create_runtime()?)
super::$id(&crate::async_std::AsyncStdNativeTlsRuntime::create()?)
}
)*
}
@ -271,7 +271,7 @@ macro_rules! tls_runtime_tests {
$(
#[test]
fn $id() -> IoResult<()> {
super::$id(&crate::tokio::create_rustls_runtime()?)
super::$id(&crate::tokio::TokioRustlsRuntime::create()?)
}
)*
}
@ -281,7 +281,7 @@ macro_rules! tls_runtime_tests {
$(
#[test]
fn $id() -> IoResult<()> {
super::$id(&crate::async_std::create_rustls_runtime()?)
super::$id(&crate::async_std::AsyncStdRustlsRuntime::create()?)
}
)*
}

View File

@ -2,7 +2,7 @@
use crate::impls::native_tls::NativeTlsProvider;
use crate::impls::tokio::TokioRuntimeHandle as Handle;
use crate::{CompoundRuntime, Runtime, SpawnBlocking};
use crate::{CompoundRuntime, SpawnBlocking};
use std::io::{Error as IoError, ErrorKind, Result as IoResult};
#[cfg(feature = "rustls")]
@ -65,71 +65,69 @@ impl From<tokio_crate::runtime::Handle> for TokioRustlsRuntime {
}
}
/// Create and return a new Tokio multithreaded runtime.
fn create_tokio_runtime() -> IoResult<TokioNativeTlsRuntime> {
crate::impls::tokio::create_runtime().map(|r| TokioNativeTlsRuntime {
inner: CompoundRuntime::new(r.clone(), r.clone(), r, NativeTlsProvider::default()),
})
impl TokioNativeTlsRuntime {
/// Create a new [`TokioNativeTlsRuntime`].
///
/// The return value will own the underlying Tokio runtime object, which
/// will be dropped when the last copy of this handle is freed.
///
/// If you want to use a currently running runtime instead, call
/// [`TokioNativeTlsRuntime::current()`].
pub fn create() -> IoResult<Self> {
crate::impls::tokio::create_runtime().map(|r| TokioNativeTlsRuntime {
inner: CompoundRuntime::new(r.clone(), r.clone(), r, NativeTlsProvider::default()),
})
}
/// Return a [`TokioNativeTlsRuntime`] wrapping the currently running
/// Tokio runtime.
///
/// # Usage note
///
/// We should never call this from inside other Arti crates, or from library
/// crates that want to support multiple runtimes! This function is for
/// Arti _users_ who want to wrap some existing Tokio runtime as a
/// [`Runtime`]. It is not for library crates that want to work with
/// multiple runtimes.
///
/// Once you have a runtime returned by this function, you should just
/// create more handles to it via [`Clone`].
pub fn current() -> IoResult<Self> {
Ok(current_handle()?.into())
}
}
/// Create and return a new Tokio multithreaded runtime configured to use `rustls`.
#[cfg(feature = "rustls")]
fn create_tokio_rustls_runtime() -> IoResult<TokioRustlsRuntime> {
crate::impls::tokio::create_runtime().map(|r| TokioRustlsRuntime {
inner: CompoundRuntime::new(r.clone(), r.clone(), r, RustlsProvider::default()),
})
}
impl TokioRustlsRuntime {
/// Create a new [`TokioRustlsRuntime`].
///
/// The return value will own the underlying Tokio runtime object, which
/// will be dropped when the last copy of this handle is freed.
///
/// If you want to use a currently running runtime instead, call
/// [`TokioRustlsRuntime::current()`].
pub fn create() -> IoResult<Self> {
crate::impls::tokio::create_runtime().map(|r| TokioRustlsRuntime {
inner: CompoundRuntime::new(r.clone(), r.clone(), r, RustlsProvider::default()),
})
}
/// Create a new Tokio-based [`Runtime`].
///
/// Generally you should call this function only once, and then use
/// [`Clone::clone()`] to create additional references to that
/// runtime.
///
/// Tokio users may want to avoid this function and instead make a
/// runtime using [`current_runtime()`]: this function always _builds_ a
/// runtime, and if you already have a runtime, that isn't what you
/// want with Tokio.
pub fn create_runtime() -> std::io::Result<impl Runtime> {
create_tokio_runtime()
}
/// Create a new Tokio-based [`Runtime`] with `rustls`.
///
/// Generally you should call this function only once, and then use
/// [`Clone::clone()`] to create additional references to that
/// runtime.
///
/// Tokio users may want to avoid this function and instead make a
/// runtime using [`current_runtime()`]: this function always _builds_ a
/// runtime, and if you already have a runtime, that isn't what you
/// want with Tokio.
#[cfg(feature = "rustls")]
pub fn create_rustls_runtime() -> std::io::Result<impl Runtime> {
create_tokio_rustls_runtime()
}
/// Try to return an instance of the currently running tokio [`Runtime`].
///
/// # Usage note
///
/// We should never call this from inside other Arti crates, or from
/// library crates that want to support multiple runtimes! This
/// function is for Arti _users_ who want to wrap some existing Tokio
/// runtime as a [`Runtime`]. It is not for library
/// crates that want to work with multiple runtimes.
///
/// Once you have a runtime returned by this function, you should
/// just create more handles to it via [`Clone`].
pub fn current_runtime() -> std::io::Result<TokioNativeTlsRuntime> {
Ok(current_handle()?.into())
}
/// Return an instance of the currently running tokio [`Runtime`], wrapped to
/// use `rustls`.
#[cfg(feature = "rustls")]
pub fn current_runtime_rustls() -> std::io::Result<TokioRustlsRuntime> {
Ok(current_handle()?.into())
/// Return a [`TokioRustlsRuntime`] wrapping the currently running
/// Tokio runtime.
///
/// # Usage note
///
/// We should never call this from inside other Arti crates, or from library
/// crates that want to support multiple runtimes! This function is for
/// Arti _users_ who want to wrap some existing Tokio runtime as a
/// [`Runtime`]. It is not for library crates that want to work with
/// multiple runtimes.
///
/// Once you have a runtime returned by this function, you should just
/// create more handles to it via [`Clone`].
pub fn current() -> IoResult<Self> {
Ok(current_handle()?.into())
}
}
/// As `Handle::try_current()`, but return an IoError on failure.
@ -147,6 +145,6 @@ where
P: FnOnce(TokioNativeTlsRuntime) -> F,
F: futures::Future<Output = O>,
{
let runtime = create_tokio_runtime().expect("Failed to create a tokio runtime");
let runtime = TokioNativeTlsRuntime::create().expect("Failed to create a tokio runtime");
runtime.clone().block_on(func(runtime))
}