Skip to main content

async_rs/util/
runtime.rs

1use crate::{
2    sys::AsSysFd,
3    traits::{Executor, Reactor, RuntimeKit},
4    util::Task,
5};
6use futures_core::Stream;
7use futures_io::{AsyncRead, AsyncWrite};
8use std::{
9    fmt,
10    future::Future,
11    io::{self, Read, Write},
12    net::SocketAddr,
13    time::{Duration, Instant},
14};
15
16/// A [`RuntimeKit`] composed of independent [`Executor`] and [`Reactor`] instances.
17///
18/// Use this when you want to pair two existing implementations that were not originally
19/// designed as a single unit — for example a custom executor with a smol reactor.
20/// For the common case where both sides come from the same backend, the concrete
21/// runtime aliases (`SmolRuntime`, `TokioRuntime`, …) are simpler.
22#[derive(Clone, Debug)]
23pub struct RuntimeParts<E: Executor, R: Reactor> {
24    executor: E,
25    reactor: R,
26}
27
28impl<E: Executor, R: Reactor> RuntimeParts<E, R> {
29    /// Create new RuntimeParts from separate Executor and Reactor
30    pub fn new(executor: E, reactor: R) -> Self {
31        Self { executor, reactor }
32    }
33}
34
35impl<E: Executor + fmt::Debug, R: Reactor + fmt::Debug> RuntimeKit for RuntimeParts<E, R> {}
36
37impl<E: Executor, R: Reactor> Executor for RuntimeParts<E, R> {
38    type Task<T: Send + 'static> = E::Task<T>;
39
40    fn block_on<T, F: Future<Output = T>>(&self, f: F) -> T {
41        self.executor.block_on(f)
42    }
43
44    fn spawn<T: Send + 'static, F: Future<Output = T> + Send + 'static>(
45        &self,
46        f: F,
47    ) -> Task<Self::Task<T>> {
48        self.executor.spawn(f)
49    }
50
51    fn spawn_blocking<T: Send + 'static, F: FnOnce() -> T + Send + 'static>(
52        &self,
53        f: F,
54    ) -> Task<Self::Task<T>> {
55        self.executor.spawn_blocking(f)
56    }
57}
58
59impl<E: Executor, R: Reactor> Reactor for RuntimeParts<E, R> {
60    type TcpStream = R::TcpStream;
61    type Sleep = R::Sleep;
62
63    fn register<H: Read + Write + AsSysFd + Send + 'static>(
64        &self,
65        socket: H,
66    ) -> io::Result<impl AsyncRead + AsyncWrite + Send + Unpin + 'static> {
67        self.reactor.register(socket)
68    }
69
70    fn sleep(&self, dur: Duration) -> Self::Sleep {
71        self.reactor.sleep(dur)
72    }
73
74    fn interval(&self, dur: Duration) -> impl Stream<Item = Instant> + Send + 'static {
75        self.reactor.interval(dur)
76    }
77
78    fn tcp_connect_addr(
79        &self,
80        addr: SocketAddr,
81    ) -> impl Future<Output = io::Result<Self::TcpStream>> + Send + 'static {
82        self.reactor.tcp_connect_addr(addr)
83    }
84}