use crate::Reporter;
use commonware_actor::Feedback;
use std::marker::PhantomData;
impl<A: Send, R: Reporter<Activity = A>> Reporter for Option<R> {
type Activity = A;
fn report(&mut self, activity: Self::Activity) -> Feedback {
let Some(reporter) = self else {
return Feedback::Ok;
};
reporter.report(activity)
}
}
#[derive(Clone)]
pub struct Reporters<A, R1, R2> {
r1: Option<R1>,
r2: Option<R2>,
_phantom: PhantomData<A>,
}
impl<A, R1, R2> Reporter for Reporters<A, R1, R2>
where
A: Clone + Send + 'static,
R1: Reporter<Activity = A>,
R2: Reporter<Activity = A>,
{
type Activity = A;
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<A, R1, R2> From<(Option<R1>, Option<R2>)> for Reporters<A, R1, R2> {
fn from((r1, r2): (Option<R1>, Option<R2>)) -> Self {
Self {
r1,
r2,
_phantom: PhantomData,
}
}
}
impl<A, R1, R2> From<(Option<R1>, R2)> for Reporters<A, R1, R2> {
fn from((r1, r2): (Option<R1>, R2)) -> Self {
Self {
r1,
r2: Some(r2),
_phantom: PhantomData,
}
}
}
impl<A, R1, R2> From<(R1, Option<R2>)> for Reporters<A, R1, R2> {
fn from((r1, r2): (R1, Option<R2>)) -> Self {
Self {
r1: Some(r1),
r2,
_phantom: PhantomData,
}
}
}
impl<A, R1, R2> From<(R1, R2)> for Reporters<A, R1, R2> {
fn from((r1, r2): (R1, R2)) -> Self {
Self {
r1: Some(r1),
r2: Some(r2),
_phantom: PhantomData,
}
}
}
#[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::<Exact, 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);
}
}