Skip to content
Snippets Groups Projects
Commit dd726076 authored by Nick Mathewson's avatar Nick Mathewson :game_die:
Browse files

Add a CompoundRuntime type for runtime construction.

This type can solve two problems at once.

First, it lets users replace parts of an existing runtime
implementation without replacing the whole thing.  For example, you
can use it to override your TcpProvider implementation to solve
problems like #235.

Second, we can use it internally to tor-rtcompat to define Runtimes
piece-by-piece.  Mostly we'll use this to separate our Tls
implementations from our implementations of the rest of the Runtime.
parent 9a77b23c
No related branches found
No related tags found
1 merge request!251Refactor our Runtime implementations to allow replacement parts
//! Define a [`CompoundRuntime`] part that can be built from several component
//! pieces.
use std::{net::SocketAddr, sync::Arc, time::Duration};
use crate::traits::*;
use async_trait::async_trait;
use futures::{future::FutureObj, task::Spawn};
use std::io::Result as IoResult;
/// A runtime made of several parts, each of which implements one trait-group.
///
/// The `SpawnR` component should implements [`Spawn`] and [`SpawnBlocking`];
/// the `SleepR` component should implement [`SleepProvider`]; the `TcpR`
/// component should implement [`TcpProvider`]; and the `TlsR` component should
/// implement [`TlsProvider`].
///
/// You can use this structure to create new runtimes in two ways: either by
/// overriding a single part of an existing runtime, or by building an entirely
/// new runtime from pieces.
#[derive(Clone)]
pub struct CompoundRuntime<SpawnR, SleepR, TcpR, TlsR> {
/// The actual collection of Runtime objects.
///
/// We wrap this in an Arc rather than requiring that each item implement
/// Clone, though we could change our minds later on.
inner: Arc<Inner<SpawnR, SleepR, TcpR, TlsR>>,
}
/// A collection of objects implementing that traits that make up a [`Runtime`]
struct Inner<SpawnR, SleepR, TcpR, TlsR> {
/// A `Spawn` and `SpawnBlocking` implementation.
spawn: SpawnR,
/// A `SleepProvider` implementation.
sleep: SleepR,
/// A `TcpProvider` implementation
tcp: TcpR,
/// A `TcpProvider<TcpR::TcpStream>` implementation.
tls: TlsR,
}
impl<SpawnR, SleepR, TcpR, TlsR> CompoundRuntime<SpawnR, SleepR, TcpR, TlsR> {
/// Construct a new CompoundRuntime from its components.
pub fn new(spawn: SpawnR, sleep: SleepR, tcp: TcpR, tls: TlsR) -> Self {
CompoundRuntime {
inner: Arc::new(Inner {
spawn,
sleep,
tcp,
tls,
}),
}
}
}
impl<SpawnR, SleepR, TcpR, TlsR> Spawn for CompoundRuntime<SpawnR, SleepR, TcpR, TlsR>
where
SpawnR: Spawn,
{
#[inline]
fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), futures::task::SpawnError> {
self.inner.spawn.spawn_obj(future)
}
}
impl<SpawnR, SleepR, TcpR, TlsR> SpawnBlocking for CompoundRuntime<SpawnR, SleepR, TcpR, TlsR>
where
SpawnR: SpawnBlocking,
{
#[inline]
fn block_on<F: futures::Future>(&self, future: F) -> F::Output {
self.inner.spawn.block_on(future)
}
}
impl<SpawnR, SleepR, TcpR, TlsR> SleepProvider for CompoundRuntime<SpawnR, SleepR, TcpR, TlsR>
where
SleepR: SleepProvider,
{
type SleepFuture = SleepR::SleepFuture;
#[inline]
fn sleep(&self, duration: Duration) -> Self::SleepFuture {
self.inner.sleep.sleep(duration)
}
}
#[async_trait]
impl<SpawnR, SleepR, TcpR, TlsR> TcpProvider for CompoundRuntime<SpawnR, SleepR, TcpR, TlsR>
where
TcpR: TcpProvider,
SpawnR: Send + Sync + 'static,
SleepR: Send + Sync + 'static,
TcpR: Send + Sync + 'static,
TlsR: Send + Sync + 'static,
{
type TcpStream = TcpR::TcpStream;
type TcpListener = TcpR::TcpListener;
#[inline]
async fn connect(&self, addr: &SocketAddr) -> IoResult<Self::TcpStream> {
self.inner.tcp.connect(addr).await
}
#[inline]
async fn listen(&self, addr: &SocketAddr) -> IoResult<Self::TcpListener> {
self.inner.tcp.listen(addr).await
}
}
impl<SpawnR, SleepR, TcpR, TlsR> TlsProvider<TcpR::TcpStream>
for CompoundRuntime<SpawnR, SleepR, TcpR, TlsR>
where
TcpR: TcpProvider,
TlsR: TlsProvider<TcpR::TcpStream>,
{
type Connector = TlsR::Connector;
type TlsStream = TlsR::TlsStream;
#[inline]
fn tls_connector(&self) -> Self::Connector {
self.inner.tls.tls_connector()
}
}
impl<SpawnR, SleepR, TcpR, TlsR> std::fmt::Debug for CompoundRuntime<SpawnR, SleepR, TcpR, TlsR> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CompoundRuntime").finish_non_exhaustive()
}
}
......@@ -143,6 +143,7 @@
pub(crate) mod impls;
pub mod task;
mod compound;
mod timer;
mod traits;
......@@ -167,6 +168,8 @@ pub mod tokio;
#[cfg(feature = "async-std")]
pub mod async_std;
pub use compound::CompoundRuntime;
/// Try to return an instance of the currently running [`Runtime`].
///
/// # Limitations
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment