/ crates / tor-rtmock / src / util.rs
util.rs
  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  // This could perhaps be further reduced:
 19  // ambassador might be able to remove most of the body (although does it do async well?)
 20      SomeMockRuntime for struct, expect items:
 21  
 22   $(
 23    ${when fmeta(mock(task))}
 24  
 25      impl <$tgens> Spawn for $ttype {
 26          fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
 27              self.$fname.spawn_obj(future)
 28          }
 29      }
 30  
 31      impl <$tgens> SpawnBlocking for $ttype {
 32          type Handle<T: Send + 'static> = <$ftype as SpawnBlocking>::Handle<T>;
 33  
 34          fn spawn_blocking<F, T>(&self, f: F) -> <$ftype as SpawnBlocking>::Handle<T>
 35          where
 36              F: FnOnce() -> T + Send + 'static,
 37              T: Send + 'static {
 38              self.$fname.spawn_blocking(f)
 39          }
 40      }
 41  
 42      impl <$tgens> BlockOn for $ttype {
 43          fn block_on<F: Future>(&self, future: F) -> F::Output {
 44              self.$fname.block_on(future)
 45          }
 46      }
 47  
 48   )
 49   $(
 50    ${when fmeta(mock(net))}
 51  
 52      #[async_trait]
 53      impl <$tgens> NetStreamProvider for $ttype {
 54          type Stream = <$ftype as NetStreamProvider>::Stream;
 55          type Listener = <$ftype as NetStreamProvider>::Listener;
 56  
 57          async fn connect(&self, addr: &SocketAddr) -> IoResult<Self::Stream> {
 58              self.$fname.connect(addr).await
 59          }
 60          async fn listen(&self, addr: &SocketAddr) -> IoResult<Self::Listener> {
 61              self.$fname.listen(addr).await
 62          }
 63      }
 64  
 65      #[async_trait]
 66      impl <$tgens> NetStreamProvider<tor_general_addr::unix::SocketAddr> for $ttype {
 67          type Stream = FakeStream;
 68          type Listener = FakeListener<tor_general_addr::unix::SocketAddr>;
 69  
 70          async fn connect(&self, _addr: &tor_general_addr::unix::SocketAddr) -> IoResult<Self::Stream> {
 71              Err(tor_general_addr::unix::NoUnixAddressSupport::default().into())
 72          }
 73          async fn listen(&self, _addr: &tor_general_addr::unix::SocketAddr) -> IoResult<Self::Listener> {
 74              Err(tor_general_addr::unix::NoUnixAddressSupport::default().into())
 75          }
 76      }
 77  
 78      impl <$tgens> TlsProvider<<$ftype as NetStreamProvider>::Stream> for $ttype {
 79          type Connector = <$ftype as TlsProvider<
 80              <$ftype as NetStreamProvider>::Stream
 81              >>::Connector;
 82          type TlsStream = <$ftype as TlsProvider<
 83              <$ftype as NetStreamProvider>::Stream
 84              >>::TlsStream;
 85          fn tls_connector(&self) -> Self::Connector {
 86              self.$fname.tls_connector()
 87          }
 88          fn supports_keying_material_export(&self) -> bool {
 89              self.$fname.supports_keying_material_export()
 90          }
 91      }
 92  
 93      #[async_trait]
 94      impl <$tgens> UdpProvider for $ttype {
 95          type UdpSocket = <$ftype as UdpProvider>::UdpSocket;
 96  
 97          #[inline]
 98          async fn bind(&self, addr: &SocketAddr) -> IoResult<Self::UdpSocket> {
 99              self.$fname.bind(addr).await
100          }
101      }
102  
103   )
104   $(
105    ${when fmeta(mock(sleep))}
106  
107      impl <$tgens> SleepProvider for $ttype {
108          type SleepFuture = <$ftype as SleepProvider>::SleepFuture;
109  
110          fn sleep(&self, dur: Duration) -> Self::SleepFuture {
111              self.$fname.sleep(dur)
112          }
113          fn now(&self) -> Instant {
114              self.$fname.now()
115          }
116          fn wallclock(&self) -> SystemTime {
117              self.$fname.wallclock()
118          }
119          fn block_advance<T: Into<String>>(&self, reason: T) {
120              self.$fname.block_advance(reason);
121          }
122          fn release_advance<T: Into<String>>(&self, reason: T) {
123              self.$fname.release_advance(reason);
124          }
125          fn allow_one_advance(&self, dur: Duration) {
126              self.$fname.allow_one_advance(dur);
127          }
128      }
129  
130      impl <$tgens> CoarseTimeProvider for $ttype {
131          fn now_coarse(&self) -> CoarseInstant {
132              self.$fname.now_coarse()
133          }
134      }
135  
136   )
137  
138     // TODO this wants to be assert_impl but it fails at generics
139     const _: fn() = || {
140         fn x(_: impl Runtime) { }
141         fn check_impl_runtime<$tgens>(t: $ttype) { x(t) }
142     };
143  }
144  
145  /// Prelude that must be imported to derive
146  /// [`SomeMockRuntime`](derive_deftly_template_SomeMockRuntime)
147  //
148  // This could have been part of the expansion of `impl_runtime!`,
149  // but it seems rather too exciting for a macro to import things as a side gig.
150  //
151  // Arguably this ought to be an internal crate::prelude instead.
152  // But crate-internal preludes are controversial within the Arti team.  -Diziet
153  //
154  // For macro visibility reasons, this must come *lexically after* the macro,
155  // to allow it to refer to the macro in the doc comment.
156  pub(crate) mod impl_runtime_prelude {
157      pub(crate) use async_trait::async_trait;
158      pub(crate) use derive_deftly::Deftly;
159      pub(crate) use futures::task::{FutureObj, Spawn, SpawnError};
160      pub(crate) use futures::Future;
161      pub(crate) use std::io::Result as IoResult;
162      pub(crate) use std::net::SocketAddr;
163      pub(crate) use std::time::{Duration, Instant, SystemTime};
164      pub(crate) use tor_rtcompat::{
165          unimpl::FakeListener, unimpl::FakeStream, BlockOn, CoarseInstant, CoarseTimeProvider,
166          NetStreamProvider, Runtime, SleepProvider, SpawnBlocking, TlsProvider, UdpProvider,
167      };
168  }
169  
170  /// Wrapper for `futures::channel::mpsc::channel` that embodies the `#[allow]`
171  ///
172  /// We don't care about mq tracking in this test crate.
173  ///
174  /// Exactly like `tor_async_utils::mpsc_channel_no_memquota`,
175  /// but we can't use that here for crate hierarchy reasons.
176  #[allow(clippy::disallowed_methods)]
177  pub(crate) fn mpsc_channel<T>(buffer: usize) -> (mpsc::Sender<T>, mpsc::Receiver<T>) {
178      mpsc::channel(buffer)
179  }