aboutsummaryrefslogtreecommitdiff
path: root/crates/tor-rtmock/src/util.rs
blob: f353fd1972027fa397a43dd0f9d6b1e4f903acfb (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
//! Internal utilities for `tor_rtmock`

use derive_adhoc::define_derive_adhoc;

define_derive_adhoc! {
/// 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:
///
///  * `#[adhoc(mock(task))]` to indicate the field implementing `Spawn + BlockOn`
///  * `#[adhoc(mock(net))]` to indicate the field implementing `NetProvider`
///  * `#[adhoc(mock(sleep))]` to indicate the field implementing `SleepProvider`
// It would be nice to be able to reject misspelled or obsolete `#[adhoc(mock(THING))]`,
// but derive-adhoc only allows us to look up known entries, not iterate.
// However, a misspelling would result in a missing trait impl, leading to compile error.
// Likewise, duplicates result in duplicate trait impls.
//
// 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()
        }
    }

    #[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);
        }
    }

 )

   // 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_adhoc_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_adhoc::Adhoc;
    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, Runtime, SleepProvider, TcpProvider, TlsProvider, UdpProvider,
    };
}