1//! Internal utilities for `tor_rtmock`
23use derive_deftly::define_derive_deftly;
4use futures::channel::mpsc;
56define_derive_deftly! {
7/// Implements `Runtime` for a struct made of multiple sub-providers
8///
9/// The type must be a struct containing
10/// field(s) which implement `SleepProvider`, `NetProvider`, etc.
11///
12/// The corresponding fields must be decorated with:
13///
14/// * `#[deftly(mock(task))]` to indicate the field implementing `Spawn + BlockOn`
15/// * `#[deftly(mock(net))]` to indicate the field implementing `NetProvider`
16/// * `#[deftly(mock(sleep))]` to indicate the field implementing `SleepProvider`
17/// and `CoarseTimeProvider`.
18/// * `#[deftly(mock(toplevel))]` to indicate the field implementing `ToplevelBlockOn`
19/// unconditionally.
20/// * `#[deftly(mock(toplevel_where = "BOUND"))]` to indicate the field implementing
21/// `ToplevelBlockOn` only if BOUND is satisfied.
22/// For example, `#[deftly(mock(toplevel_where = "R: ToplevelBlockOn"))] runtime: R,`.
23// This could perhaps be further reduced:
24// ambassador might be able to remove most of the body (although does it do async well?)
25SomeMockRuntime for struct, expect items, beta_deftly:
2627 $(
28 ${when fmeta(mock(task))}
2930impl <$tgens> Spawn for $ttype {
31fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
32self.$fname.spawn_obj(future)
33 }
34 }
3536impl <$tgens> Blocking for $ttype {
37type ThreadHandle<T: Send + 'static> = <$ftype as Blocking>::ThreadHandle<T>;
3839fn spawn_blocking<F, T>(&self, f: F) -> <$ftype as Blocking>::ThreadHandle<T>
40where
41F: FnOnce() -> T + Send + 'static,
42 T: Send + 'static {
43self.$fname.spawn_blocking(f)
44 }
4546fn reenter_block_on<F>(&self, future: F) -> F::Output
47where
48F: Future,
49 F::Output: Send + 'static
50{
51self.$fname.reenter_block_on(future)
52 }
53 }
5455 )
56 $(
57 ${when any(fmeta(mock(toplevel)), fmeta(mock(toplevel_where)))}
5859impl <$tgens> ToplevelBlockOn for $ttype
60where ${fmeta(mock(toplevel_where)) as token_stream, default {}}
61 {
62fn block_on<F: Future>(&self, future: F) -> F::Output {
63self.$fname.block_on(future)
64 }
65 }
6667 )
68 $(
69 ${when fmeta(mock(net))}
7071#[async_trait]
72impl <$tgens> NetStreamProvider for $ttype {
73type Stream = <$ftype as NetStreamProvider>::Stream;
74type Listener = <$ftype as NetStreamProvider>::Listener;
7576async fn connect(&self, addr: &SocketAddr) -> IoResult<Self::Stream> {
77self.$fname.connect(addr).await
78}
79async fn listen(&self, addr: &SocketAddr) -> IoResult<Self::Listener> {
80self.$fname.listen(addr).await
81}
82 }
8384#[async_trait]
85impl <$tgens> NetStreamProvider<tor_general_addr::unix::SocketAddr> for $ttype {
86type Stream = FakeStream;
87type Listener = FakeListener<tor_general_addr::unix::SocketAddr>;
8889async fn connect(&self, _addr: &tor_general_addr::unix::SocketAddr) -> IoResult<Self::Stream> {
90Err(tor_general_addr::unix::NoAfUnixSocketSupport::default().into())
91 }
92async fn listen(&self, _addr: &tor_general_addr::unix::SocketAddr) -> IoResult<Self::Listener> {
93Err(tor_general_addr::unix::NoAfUnixSocketSupport::default().into())
94 }
95 }
9697impl <$tgens> TlsProvider<<$ftype as NetStreamProvider>::Stream> for $ttype {
98type Connector = <$ftype as TlsProvider<
99 <$ftype as NetStreamProvider>::Stream
100 >>::Connector;
101type TlsStream = <$ftype as TlsProvider<
102 <$ftype as NetStreamProvider>::Stream
103 >>::TlsStream;
104fn tls_connector(&self) -> Self::Connector {
105self.$fname.tls_connector()
106 }
107fn supports_keying_material_export(&self) -> bool {
108self.$fname.supports_keying_material_export()
109 }
110 }
111112#[async_trait]
113impl <$tgens> UdpProvider for $ttype {
114type UdpSocket = <$ftype as UdpProvider>::UdpSocket;
115116#[inline]
117async fn bind(&self, addr: &SocketAddr) -> IoResult<Self::UdpSocket> {
118self.$fname.bind(addr).await
119}
120 }
121122 )
123 $(
124 ${when fmeta(mock(sleep))}
125126impl <$tgens> SleepProvider for $ttype {
127type SleepFuture = <$ftype as SleepProvider>::SleepFuture;
128129fn sleep(&self, dur: Duration) -> Self::SleepFuture {
130self.$fname.sleep(dur)
131 }
132fn now(&self) -> Instant {
133self.$fname.now()
134 }
135fn wallclock(&self) -> SystemTime {
136self.$fname.wallclock()
137 }
138fn block_advance<T: Into<String>>(&self, reason: T) {
139self.$fname.block_advance(reason);
140 }
141fn release_advance<T: Into<String>>(&self, reason: T) {
142self.$fname.release_advance(reason);
143 }
144fn allow_one_advance(&self, dur: Duration) {
145self.$fname.allow_one_advance(dur);
146 }
147 }
148149impl <$tgens> CoarseTimeProvider for $ttype {
150fn now_coarse(&self) -> CoarseInstant {
151self.$fname.now_coarse()
152 }
153 }
154155 )
156157// TODO this wants to be assert_impl but it fails at generics
158const _: fn() = || {
159fn x(_: impl Runtime) { }
160fn check_impl_runtime<$tgens>(t: $ttype) { x(t) }
161 };
162}
163164/// Prelude that must be imported to derive
165/// [`SomeMockRuntime`](derive_deftly_template_SomeMockRuntime)
166//
167// This could have been part of the expansion of `impl_runtime!`,
168// but it seems rather too exciting for a macro to import things as a side gig.
169//
170// Arguably this ought to be an internal crate::prelude instead.
171// But crate-internal preludes are controversial within the Arti team. -Diziet
172//
173// For macro visibility reasons, this must come *lexically after* the macro,
174// to allow it to refer to the macro in the doc comment.
175pub(crate) mod impl_runtime_prelude {
176pub(crate) use async_trait::async_trait;
177pub(crate) use derive_deftly::Deftly;
178pub(crate) use futures::task::{FutureObj, Spawn, SpawnError};
179pub(crate) use futures::Future;
180pub(crate) use std::io::Result as IoResult;
181pub(crate) use std::net::SocketAddr;
182pub(crate) use std::time::{Duration, Instant, SystemTime};
183pub(crate) use tor_rtcompat::{
184 unimpl::FakeListener, unimpl::FakeStream, Blocking, CoarseInstant, CoarseTimeProvider,
185 NetStreamProvider, Runtime, SleepProvider, TlsProvider, ToplevelBlockOn, UdpProvider,
186 };
187}
188189/// Wrapper for `futures::channel::mpsc::channel` that embodies the `#[allow]`
190///
191/// We don't care about mq tracking in this test crate.
192///
193/// Exactly like `tor_async_utils::mpsc_channel_no_memquota`,
194/// but we can't use that here for crate hierarchy reasons.
195#[allow(clippy::disallowed_methods)]
196pub(crate) fn mpsc_channel<T>(buffer: usize) -> (mpsc::Sender<T>, mpsc::Receiver<T>) {
197 mpsc::channel(buffer)
198}