tor_proto/circuit/reactor/macros.rs
1//! Helper macros for the circuit reactors.
2
3derive_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
65pub(crate) use derive_deftly_template_CircuitReactor;