use crate::Reporter;
use futures::join;
use std::marker::PhantomData;
impl<A: Send, R: Reporter<Activity = A>> Reporter for Option<R> {
type Activity = A;
async fn report(&mut self, activity: Self::Activity) {
let Some(reporter) = self else {
return;
};
reporter.report(activity).await;
}
}
#[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;
async fn report(&mut self, activity: Self::Activity) {
match (&mut self.r1, &mut self.r2) {
(Some(r1), Some(r2)) => join!(r1.report(activity.clone()), r2.report(activity)),
(Some(r1), None) => (r1.report(activity).await, ()),
(None, Some(r2)) => ((), r2.report(activity).await),
(None, None) => ((), ()),
};
}
}
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_macros::test_async;
use commonware_utils::acknowledgement::{Acknowledgement, Exact};
use futures::FutureExt;
#[derive(Clone, Debug)]
struct SimpleAcknowledger;
impl crate::Reporter for SimpleAcknowledger {
type Activity = Exact;
async fn report(&mut self, activity: Self::Activity) {
activity.acknowledge();
}
}
#[test_async]
async fn optional_branch_acknowledges() {
let mut reporters = Reporters::<Exact, SimpleAcknowledger, SimpleAcknowledger>::from((
Some(SimpleAcknowledger),
None,
));
let (ack, waiter) = Exact::handle();
reporters.report(ack).await;
assert!(
waiter.now_or_never().unwrap().is_ok(),
"Waiter did not resolve successfully"
);
}
}