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
        pub(crate) async fn run(mut self) -> $crate::Result<()> {
31
            let unique_id = self.unique_id;
32

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

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

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

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

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

            
60
            result
61
        }
62
    }
63
}
64

            
65
pub(crate) use derive_deftly_template_CircuitReactor;