1
//! Helper macros for the circuit reactors.
2

            
3
derive_deftly::define_derive_deftly! {
4
    /// Helper for deriving the boilerplate `run()` function of a circuit reactor.
5
    ///
6
    ///
7
    /// ### Custom attributes
8
    ///
9
    ///  * **`#[deftly(reactor_name = "...")]`** (toplevel):
10
    ///    The name of the reactor, for logging purposes.
11
    ///    Must be a literal string.
12
    ///
13
    ///  * **`#[deftly(run_inner_fn = "FUNCTION")]`** (toplevel):
14
    ///    The function to run from `run()`, possibly in a loop.
15
    ///    `FUNCTION` is a function with the signature
16
    ///    `async fn run_once(&mut Self) -> Result<(), ReactorError>`
17
    ///
18
    ///  * **`#[deftly(only_run_once)]`** (toplevel):
19
    ///    Whether the `run()` function should only run `run_inner_fn` once
20
    export CircuitReactor expect items:
21

            
22
    impl<$tgens> $ttype where
23
        $twheres
24
    {
25
        /// Launch the reactor, and run until the circuit closes or we
26
        /// encounter an error.
27
        ///
28
        /// Once this method returns, the circuit is dead and cannot be
29
        /// used again.
30
216
        pub(crate) async fn run(mut self) -> $crate::Result<()> {
31
            let unique_id = self.unique_id;
32

            
33
            tracing::debug!(
34
                circ_uniq_id = %unique_id,
35
                backward_circ_id = %self.circ_id,
36
                "Running {}", ${tmeta(reactor_name) as str}
37
            );
38

            
39
            let result: $crate::Result<()> = loop {
40

            
41
                match ${tmeta(run_inner_fn) as expr}(&mut self).await {
42

            
43
                    Ok(()) => {
44
                        ${if tmeta(only_run_once) {
45
                            break Ok(());
46
                        }}
47
                    },
48
                    Err(ReactorError::Shutdown) => break Ok(()),
49
                    Err(ReactorError::Err(e)) => break Err(e),
50
                }
51
            };
52

            
53
            // Log that the reactor stopped, possibly with the associated error as a report.
54
            // May log at a higher level depending on the error kind.
55
            let msg = format!("{} shut down", ${tmeta(reactor_name) as str});
56
            match &result {
57
                Ok(()) => tracing::trace!(
58
                    circ_uniq_id = %unique_id,
59
                    backward_circ_id = %self.circ_id,
60
                    "{msg}"
61
                ),
62
                Err(e) => tor_error::debug_report!(
63
                    e,
64
                    circ_uniq_id = %unique_id,
65
                    backward_circ_id = %self.circ_id,
66
                    "{msg}"
67
                ),
68
            }
69

            
70
            result
71
        }
72
    }
73
}
74

            
75
pub(crate) use derive_deftly_template_CircuitReactor;