commonware_consensus/
reporter.rs1use crate::Reporter;
4use commonware_actor::Feedback;
5
6impl<R: Reporter> Reporter for Option<R> {
11 type Activity = R::Activity;
12
13 fn report(&mut self, activity: Self::Activity) -> Feedback {
14 let Some(reporter) = self else {
15 return Feedback::Ok;
16 };
17 reporter.report(activity)
18 }
19}
20
21#[derive(Clone)]
23pub struct Reporters<R1, R2> {
24 r1: Option<R1>,
25 r2: Option<R2>,
26}
27
28impl<R1, R2> Reporter for Reporters<R1, R2>
29where
30 R1: Reporter,
31 R2: Reporter<Activity = R1::Activity>,
32 R1::Activity: Clone,
33{
34 type Activity = R1::Activity;
35
36 fn report(&mut self, activity: Self::Activity) -> Feedback {
37 match (&mut self.r1, &mut self.r2) {
39 (Some(r1), Some(r2)) => combine(r1.report(activity.clone()), r2.report(activity)),
40 (Some(r1), None) => r1.report(activity),
41 (None, Some(r2)) => r2.report(activity),
42 (None, None) => Feedback::Ok,
43 }
44 }
45}
46
47const fn combine(a: Feedback, b: Feedback) -> Feedback {
48 match (a, b) {
49 (Feedback::Closed, _) | (_, Feedback::Closed) => Feedback::Closed,
50 (Feedback::Backoff, _) | (_, Feedback::Backoff) => Feedback::Backoff,
51 (Feedback::Ok, Feedback::Ok) => Feedback::Ok,
52 }
53}
54
55impl<R1, R2> From<(Option<R1>, Option<R2>)> for Reporters<R1, R2> {
56 fn from((r1, r2): (Option<R1>, Option<R2>)) -> Self {
57 Self { r1, r2 }
58 }
59}
60
61impl<R1, R2> From<(Option<R1>, R2)> for Reporters<R1, R2> {
62 fn from((r1, r2): (Option<R1>, R2)) -> Self {
63 Self { r1, r2: Some(r2) }
64 }
65}
66
67impl<R1, R2> From<(R1, Option<R2>)> for Reporters<R1, R2> {
68 fn from((r1, r2): (R1, Option<R2>)) -> Self {
69 Self { r1: Some(r1), r2 }
70 }
71}
72
73impl<R1, R2> From<(R1, R2)> for Reporters<R1, R2> {
74 fn from((r1, r2): (R1, R2)) -> Self {
75 Self {
76 r1: Some(r1),
77 r2: Some(r2),
78 }
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use commonware_actor::Feedback;
86 use commonware_utils::acknowledgement::{Acknowledgement, Exact};
87 use futures::FutureExt;
88
89 #[derive(Clone, Debug)]
90 struct SimpleAcknowledger;
91
92 impl crate::Reporter for SimpleAcknowledger {
93 type Activity = Exact;
94
95 fn report(&mut self, activity: Self::Activity) -> Feedback {
96 activity.acknowledge();
97 Feedback::Ok
98 }
99 }
100
101 #[test]
102 fn optional_branch_acknowledges() {
103 let mut reporters = Reporters::<SimpleAcknowledger, SimpleAcknowledger>::from((
104 Some(SimpleAcknowledger),
105 None,
106 ));
107
108 let (ack, waiter) = Exact::handle();
109 assert_eq!(reporters.report(ack), Feedback::Ok);
110
111 assert!(
112 waiter.now_or_never().unwrap().is_ok(),
113 "Waiter did not resolve successfully"
114 );
115 }
116
117 #[test]
118 fn absent_reporter_ignores_activity() {
119 let mut reporter = Option::<SimpleAcknowledger>::None;
120 let (ack, waiter) = Exact::handle();
121 assert_eq!(reporter.report(ack), Feedback::Ok);
122 assert!(waiter.now_or_never().unwrap().is_err());
123 }
124
125 #[test]
126 fn combine_returns_worst_feedback() {
127 assert_eq!(
128 combine(Feedback::Closed, Feedback::Backoff),
129 Feedback::Closed
130 );
131 assert_eq!(combine(Feedback::Backoff, Feedback::Ok), Feedback::Backoff);
132 assert_eq!(combine(Feedback::Ok, Feedback::Ok), Feedback::Ok);
133 }
134}