summaryrefslogtreecommitdiff
path: root/crates/tor-rtmock/src/util.rs
blob: 6142bf4f21929343e313b07de409672762345a1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! Internal utilities for `tor_rtmock`

use derive_deftly::define_derive_deftly;

define_derive_deftly! {
/// Implements `Runtime` for a struct made of multiple sub-providers
///
/// The type must be a struct containing
/// field(s) which implement `SleepProvider`, `NetProvider`, etc.
///
/// The corresponding fields must be decorated with:
///
///  * `#[deftly(mock(task))]` to indicate the field implementing `Spawn + BlockOn`
///  * `#[deftly(mock(net))]` to indicate the field implementing `NetProvider`
///  * `#[deftly(mock(sleep))]` to indicate the field implementing `SleepProvider`
///     and `CoarseTimeProvider`.
// This could perhaps be further reduced:
// ambassador might be able to remove most of the body (although does it do async well?)
    SomeMockRuntime for struct, expect items:

 $(
  ${when fmeta(mock(task))}

    impl <$tgens> Spawn for $ttype {
        fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
            self.$fname.spawn_obj(future)
        }
    }

    impl <$tgens> BlockOn for $ttype {
        fn block_on<F: Future>(&self, future: F) -> F::Output {
            self.$fname.block_on(future)
        }
    }

 )
 $(
  ${when fmeta(mock(net))}

    #[async_trait]
    impl <$tgens> TcpProvider for $ttype {
        type TcpStream = <$ftype as TcpProvider>::TcpStream;
        type TcpListener = <$ftype as TcpProvider>::TcpListener;

        async fn connect(&self, addr: &SocketAddr) -> IoResult<Self::TcpStream> {
            self.$fname.connect(addr).await
        }
        async fn listen(&self, addr: &SocketAddr) -> IoResult<Self::TcpListener> {
            self.$fname.listen(addr).await
        }
    }

    impl <$tgens> TlsProvider<<$ftype as TcpProvider>::TcpStream> for $ttype {
        type Connector = <$ftype as TlsProvider<
            <$ftype as TcpProvider>::TcpStream
            >>::Connector;
        type TlsStream = <$ftype as TlsProvider<
            <$ftype as TcpProvider>::TcpStream
            >>::TlsStream;
        fn tls_connector(&self) -> Self::Connector {
            self.$fname.tls_connector()
        }
        fn supports_keying_material_export(&self) -> bool {
            self.$fname.supports_keying_material_export()
        }
    }

    #[async_trait]
    impl <$tgens> UdpProvider for $ttype {
        type UdpSocket = <$ftype as UdpProvider>::UdpSocket;

        #[inline]
        async fn bind(&self, addr: &SocketAddr) -> IoResult<Self::UdpSocket> {
            self.$fname.bind(addr).await
        }
    }

 )
 $(
  ${when fmeta(mock(sleep))}

    impl <$tgens> SleepProvider for $ttype {
        type SleepFuture = <$ftype as SleepProvider>::SleepFuture;

        fn sleep(&self, dur: Duration) -> Self::SleepFuture {
            self.$fname.sleep(dur)
        }
        fn now(&self) -> Instant {
            self.$fname.now()
        }
        fn wallclock(&self) -> SystemTime {
            self.$fname.wallclock()
        }
        fn block_advance<T: Into<String>>(&self, reason: T) {
            self.$fname.block_advance(reason);
        }
        fn release_advance<T: Into<String>>(&self, reason: T) {
            self.$fname.release_advance(reason);
        }
        fn allow_one_advance(&self, dur: Duration) {
            self.$fname.allow_one_advance(dur);
        }
    }

    impl <$tgens> CoarseTimeProvider for $ttype {
        fn now_coarse(&self) -> CoarseInstant {
            self.$fname.now_coarse()
        }
    }

 )

   // TODO this wants to be assert_impl but it fails at generics
   const _: fn() = || {
       fn x(_: impl Runtime) { }
       fn check_impl_runtime<$tgens>(t: $ttype) { x(t) }
   };
}

/// Prelude that must be imported to derive
/// [`SomeMockRuntime`](derive_deftly_template_SomeMockRuntime)
//
// This could have been part of the expansion of `impl_runtime!`,
// but it seems rather too exciting for a macro to import things as a side gig.
//
// Arguably this ought to be an internal crate::prelude instead.
// But crate-internal preludes are controversial within the Arti team.  -Diziet
//
// For macro visibility reasons, this must come *lexically after* the macro,
// to allow it to refer to the macro in the doc comment.
pub(crate) mod impl_runtime_prelude {
    pub(crate) use async_trait::async_trait;
    pub(crate) use derive_deftly::Deftly;
    pub(crate) use futures::task::{FutureObj, Spawn, SpawnError};
    pub(crate) use futures::Future;
    pub(crate) use std::io::Result as IoResult;
    pub(crate) use std::net::SocketAddr;
    pub(crate) use std::time::{Duration, Instant, SystemTime};
    pub(crate) use tor_rtcompat::{
        BlockOn, CoarseInstant, CoarseTimeProvider, Runtime, SleepProvider, TcpProvider,
        TlsProvider, UdpProvider,
    };
}