use std::fmt::{self, Debug, Formatter};
use futures::future::BoxFuture;
use prometheus::Registry;
use super::network::NetworkedReactor;
use crate::{
effect::{EffectBuilder, Effects},
reactor::{EventQueueHandle, Finalize, Reactor},
NodeRng,
};
pub struct ConditionCheckReactor<R: Reactor> {
reactor: R,
condition_checker: Option<Box<dyn Fn(&R::Event) -> bool + Send>>,
condition_result: bool,
}
impl<R: Reactor> ConditionCheckReactor<R> {
pub fn set_condition_checker(
&mut self,
condition_checker: Box<dyn Fn(&R::Event) -> bool + Send>,
) {
self.condition_checker = Some(condition_checker);
}
pub fn condition_result(&self) -> bool {
self.condition_result
}
pub fn inner(&self) -> &R {
&self.reactor
}
pub fn inner_mut(&mut self) -> &mut R {
&mut self.reactor
}
}
impl<R: Reactor> Reactor for ConditionCheckReactor<R> {
type Event = R::Event;
type Config = R::Config;
type Error = R::Error;
fn new(
config: Self::Config,
registry: &Registry,
event_queue: EventQueueHandle<Self::Event>,
rng: &mut NodeRng,
) -> Result<(Self, Effects<Self::Event>), Self::Error> {
let (reactor, effects) = R::new(config, registry, event_queue, rng)?;
Ok((
Self {
reactor,
condition_checker: None,
condition_result: false,
},
effects,
))
}
fn dispatch_event(
&mut self,
effect_builder: EffectBuilder<Self::Event>,
rng: &mut NodeRng,
event: Self::Event,
) -> Effects<Self::Event> {
self.condition_result = self
.condition_checker
.as_ref()
.map(|condition_checker| condition_checker(&event))
.unwrap_or_default();
if self.condition_result {
self.condition_checker = None;
}
self.reactor.dispatch_event(effect_builder, rng, event)
}
}
impl<R: Reactor + Finalize> Finalize for ConditionCheckReactor<R> {
fn finalize(self) -> BoxFuture<'static, ()> {
self.reactor.finalize()
}
}
impl<R: Reactor + NetworkedReactor> NetworkedReactor for ConditionCheckReactor<R> {
type NodeId = R::NodeId;
fn node_id(&self) -> Self::NodeId {
self.reactor.node_id()
}
}
impl<R: Reactor + Debug> Debug for ConditionCheckReactor<R> {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
formatter
.debug_struct("ConditionCheckReactor")
.field("reactor", &self.reactor)
.field("condition_check_result", &self.condition_result)
.finish()
}
}