use crate::Reporter;
use commonware_actor::Feedback;
impl<R: Reporter> Reporter for Option<R> {
type Activity = R::Activity;
fn report(&mut self, activity: Self::Activity) -> Feedback {
let Some(reporter) = self else {
return Feedback::Ok;
};
reporter.report(activity)
}
}
#[derive(Clone)]
pub struct Reporters<R1, R2> {
r1: Option<R1>,
r2: Option<R2>,
}
impl<R1, R2> Reporter for Reporters<R1, R2>
where
R1: Reporter,
R2: Reporter<Activity = R1::Activity>,
R1::Activity: Clone,
{
type Activity = R1::Activity;
fn report(&mut self, activity: Self::Activity) -> Feedback {
match (&mut self.r1, &mut self.r2) {
(Some(r1), Some(r2)) => combine(r1.report(activity.clone()), r2.report(activity)),
(Some(r1), None) => r1.report(activity),
(None, Some(r2)) => r2.report(activity),
(None, None) => Feedback::Ok,
}
}
}
const fn combine(a: Feedback, b: Feedback) -> Feedback {
match (a, b) {
(Feedback::Closed, _) | (_, Feedback::Closed) => Feedback::Closed,
(Feedback::Backoff, _) | (_, Feedback::Backoff) => Feedback::Backoff,
(Feedback::Ok, Feedback::Ok) => Feedback::Ok,
}
}
impl<R1, R2> From<(Option<R1>, Option<R2>)> for Reporters<R1, R2> {
fn from((r1, r2): (Option<R1>, Option<R2>)) -> Self {
Self { r1, r2 }
}
}
impl<R1, R2> From<(Option<R1>, R2)> for Reporters<R1, R2> {
fn from((r1, r2): (Option<R1>, R2)) -> Self {
Self { r1, r2: Some(r2) }
}
}
impl<R1, R2> From<(R1, Option<R2>)> for Reporters<R1, R2> {
fn from((r1, r2): (R1, Option<R2>)) -> Self {
Self { r1: Some(r1), r2 }
}
}
impl<R1, R2> From<(R1, R2)> for Reporters<R1, R2> {
fn from((r1, r2): (R1, R2)) -> Self {
Self {
r1: Some(r1),
r2: Some(r2),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use commonware_actor::Feedback;
use commonware_utils::acknowledgement::{Acknowledgement, Exact};
use futures::FutureExt;
#[derive(Clone, Debug)]
struct SimpleAcknowledger;
impl crate::Reporter for SimpleAcknowledger {
type Activity = Exact;
fn report(&mut self, activity: Self::Activity) -> Feedback {
activity.acknowledge();
Feedback::Ok
}
}
#[test]
fn optional_branch_acknowledges() {
let mut reporters = Reporters::<SimpleAcknowledger, SimpleAcknowledger>::from((
Some(SimpleAcknowledger),
None,
));
let (ack, waiter) = Exact::handle();
assert_eq!(reporters.report(ack), Feedback::Ok);
assert!(
waiter.now_or_never().unwrap().is_ok(),
"Waiter did not resolve successfully"
);
}
#[test]
fn absent_reporter_ignores_activity() {
let mut reporter = Option::<SimpleAcknowledger>::None;
let (ack, waiter) = Exact::handle();
assert_eq!(reporter.report(ack), Feedback::Ok);
assert!(waiter.now_or_never().unwrap().is_err());
}
#[test]
fn combine_returns_worst_feedback() {
assert_eq!(
combine(Feedback::Closed, Feedback::Backoff),
Feedback::Closed
);
assert_eq!(combine(Feedback::Backoff, Feedback::Ok), Feedback::Backoff);
assert_eq!(combine(Feedback::Ok, Feedback::Ok), Feedback::Ok);
}
}