1
//! Internal utilities for `tor_rtmock`
2

            
3
use derive_deftly::define_derive_deftly;
4
use futures::channel::mpsc;
5

            
6
define_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
84835
        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
56
        fn spawn_blocking<F, T>(&self, f: F) -> <$ftype as Blocking>::ThreadHandle<T>
40
56
        where
41
56
            F: FnOnce() -> T + Send + 'static,
42
56
            T: Send + 'static {
43
            self.$fname.spawn_blocking(f)
44
        }
45

            
46
1804
        fn reenter_block_on<F>(&self, future: F) -> F::Output
47
1804
        where
48
1804
            F: Future,
49
1804
            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
580
        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
884
        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
76578
        fn sleep(&self, dur: Duration) -> Self::SleepFuture {
160
            self.$fname.sleep(dur)
161
        }
162
3907960
        fn now(&self) -> Instant {
163
            self.$fname.now()
164
        }
165
122180
        fn wallclock(&self) -> SystemTime {
166
            self.$fname.wallclock()
167
        }
168
168
        fn block_advance<T: Into<String>>(&self, reason: T) {
169
            self.$fname.block_advance(reason);
170
        }
171
112
        fn release_advance<T: Into<String>>(&self, reason: T) {
172
            self.$fname.release_advance(reason);
173
        }
174
1564
        fn allow_one_advance(&self, dur: Duration) {
175
            self.$fname.allow_one_advance(dur);
176
        }
177
    }
178

            
179
    impl <$tgens> CoarseTimeProvider for $ttype {
180
284242
        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.
206
pub(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)]
227
7192
pub(crate) fn mpsc_channel<T>(buffer: usize) -> (mpsc::Sender<T>, mpsc::Receiver<T>) {
228
7192
    mpsc::channel(buffer)
229
7192
}