Skip to main content

tor_rtmock/
util.rs

1//! Internal utilities for `tor_rtmock`
2
3use derive_deftly::define_derive_deftly;
4use futures::channel::mpsc;
5
6define_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?)
25    SomeMockRuntime for struct, expect items, beta_deftly:
26
27 $(
28  ${when fmeta(mock(task))}
29
30    impl <$tgens> Spawn for $ttype {
31        fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
32            self.$fname.spawn_obj(future)
33        }
34    }
35
36    impl <$tgens> Blocking for $ttype {
37        type ThreadHandle<T: Send + 'static> = <$ftype as Blocking>::ThreadHandle<T>;
38
39        fn spawn_blocking<F, T>(&self, f: F) -> <$ftype as Blocking>::ThreadHandle<T>
40        where
41            F: FnOnce() -> T + Send + 'static,
42            T: Send + 'static {
43            self.$fname.spawn_blocking(f)
44        }
45
46        fn reenter_block_on<F>(&self, future: F) -> F::Output
47        where
48            F: Future,
49            F::Output: Send + 'static
50        {
51            self.$fname.reenter_block_on(future)
52        }
53    }
54
55 )
56 $(
57  ${when any(fmeta(mock(toplevel)), fmeta(mock(toplevel_where)))}
58
59    impl <$tgens> ToplevelBlockOn for $ttype
60    where ${fmeta(mock(toplevel_where)) as token_stream, default {}}
61    {
62        fn block_on<F: Future>(&self, future: F) -> F::Output {
63            self.$fname.block_on(future)
64        }
65    }
66
67 )
68 $(
69  ${when fmeta(mock(net))}
70
71    #[async_trait]
72    impl <$tgens> NetStreamProvider for $ttype {
73        type Stream = <$ftype as NetStreamProvider>::Stream;
74        type Listener = <$ftype as NetStreamProvider>::Listener;
75        type ConnectOptions = <$ftype as NetStreamProvider>::ConnectOptions;
76        type ListenOptions = <$ftype as NetStreamProvider>::ListenOptions;
77
78        async fn connect(
79            &self,
80            addr: &SocketAddr,
81            options: &Self::ConnectOptions,
82        ) -> IoResult<Self::Stream> {
83            self.$fname.connect(addr, options).await
84        }
85        async fn listen(
86            &self,
87            addr: &SocketAddr,
88            options: &Self::ListenOptions,
89        ) -> IoResult<Self::Listener> {
90            self.$fname.listen(addr, options).await
91        }
92    }
93
94    #[async_trait]
95    impl <$tgens> NetStreamProvider<tor_general_addr::unix::SocketAddr> for $ttype {
96        type Stream = FakeStream;
97        type Listener = FakeListener<tor_general_addr::unix::SocketAddr>;
98        type ConnectOptions = tor_rtcompat::UnixConnectOptions;
99        type ListenOptions = tor_rtcompat::UnixListenOptions;
100
101        async fn connect(
102            &self,
103            _addr: &tor_general_addr::unix::SocketAddr,
104            _options: &Self::ConnectOptions,
105        ) -> IoResult<Self::Stream> {
106            Err(tor_general_addr::unix::NoAfUnixSocketSupport::default().into())
107        }
108        async fn listen(
109            &self,
110            _addr: &tor_general_addr::unix::SocketAddr,
111            _options: &Self::ListenOptions,
112        ) -> IoResult<Self::Listener> {
113            Err(tor_general_addr::unix::NoAfUnixSocketSupport::default().into())
114        }
115    }
116
117    impl <$tgens> TlsProvider<<$ftype as NetStreamProvider>::Stream> for $ttype {
118        type Connector = <$ftype as TlsProvider<
119            <$ftype as NetStreamProvider>::Stream
120            >>::Connector;
121        type TlsStream = <$ftype as TlsProvider<
122            <$ftype as NetStreamProvider>::Stream
123            >>::TlsStream;
124        type Acceptor = <$ftype as TlsProvider<
125            <$ftype as NetStreamProvider>::Stream
126            >>::Acceptor;
127        type TlsServerStream = <$ftype as TlsProvider<
128            <$ftype as NetStreamProvider>::Stream
129            >>::TlsServerStream;
130
131        fn tls_connector(&self) -> Self::Connector {
132            self.$fname.tls_connector()
133        }
134        fn tls_acceptor(&self, settings: tor_rtcompat::tls::TlsAcceptorSettings) -> std::io::Result<Self::Acceptor> {
135            self.$fname.tls_acceptor(settings)
136        }
137        fn supports_keying_material_export(&self) -> bool {
138            self.$fname.supports_keying_material_export()
139        }
140    }
141
142    #[async_trait]
143    impl <$tgens> UdpProvider for $ttype {
144        type UdpSocket = <$ftype as UdpProvider>::UdpSocket;
145
146        #[inline]
147        async fn bind(&self, addr: &SocketAddr) -> IoResult<Self::UdpSocket> {
148            self.$fname.bind(addr).await
149        }
150    }
151
152 )
153 $(
154  ${when fmeta(mock(sleep))}
155
156    impl <$tgens> SleepProvider for $ttype {
157        type SleepFuture = <$ftype as SleepProvider>::SleepFuture;
158
159        fn sleep(&self, dur: Duration) -> Self::SleepFuture {
160            self.$fname.sleep(dur)
161        }
162        fn now(&self) -> Instant {
163            self.$fname.now()
164        }
165        fn wallclock(&self) -> SystemTime {
166            self.$fname.wallclock()
167        }
168        fn block_advance<T: Into<String>>(&self, reason: T) {
169            self.$fname.block_advance(reason);
170        }
171        fn release_advance<T: Into<String>>(&self, reason: T) {
172            self.$fname.release_advance(reason);
173        }
174        fn allow_one_advance(&self, dur: Duration) {
175            self.$fname.allow_one_advance(dur);
176        }
177    }
178
179    impl <$tgens> CoarseTimeProvider for $ttype {
180        fn now_coarse(&self) -> CoarseInstant {
181            self.$fname.now_coarse()
182        }
183    }
184
185 )
186
187   // TODO this wants to be assert_impl but it fails at generics
188   #[allow(unused)]
189   const _: fn() = || {
190       fn x(_: impl Runtime) { }
191       fn check_impl_runtime<$tgens>(t: $ttype) { x(t) }
192   };
193}
194
195/// Prelude that must be imported to derive
196/// [`SomeMockRuntime`](derive_deftly_template_SomeMockRuntime)
197//
198// This could have been part of the expansion of `impl_runtime!`,
199// but it seems rather too exciting for a macro to import things as a side gig.
200//
201// Arguably this ought to be an internal crate::prelude instead.
202// But crate-internal preludes are controversial within the Arti team.  -Diziet
203//
204// For macro visibility reasons, this must come *lexically after* the macro,
205// to allow it to refer to the macro in the doc comment.
206pub(crate) mod impl_runtime_prelude {
207    pub(crate) use async_trait::async_trait;
208    pub(crate) use derive_deftly::Deftly;
209    pub(crate) use futures::Future;
210    pub(crate) use futures::task::{FutureObj, Spawn, SpawnError};
211    pub(crate) use std::io::Result as IoResult;
212    pub(crate) use std::net::SocketAddr;
213    pub(crate) use tor_rtcompat::{
214        Blocking, CoarseInstant, CoarseTimeProvider, NetStreamProvider, Runtime, SleepProvider,
215        TlsProvider, ToplevelBlockOn, UdpProvider, unimpl::FakeListener, unimpl::FakeStream,
216    };
217    pub(crate) use web_time_compat::{Duration, Instant, SystemTime, SystemTimeExt};
218}
219
220/// Wrapper for `futures::channel::mpsc::channel` that embodies the `#[allow]`
221///
222/// We don't care about mq tracking in this test crate.
223///
224/// Exactly like `tor_async_utils::mpsc_channel_no_memquota`,
225/// but we can't use that here for crate hierarchy reasons.
226#[allow(clippy::disallowed_methods)]
227pub(crate) fn mpsc_channel<T>(buffer: usize) -> (mpsc::Sender<T>, mpsc::Receiver<T>) {
228    mpsc::channel(buffer)
229}