use crate::{
AggregateLogic, Causable, CausableCollectionAccessor, CausalityError, CausalityErrorEnum,
MonadicCausable, NumericalValue, StatefulMonadicCausable, monadic_collection_utils,
};
use deep_causality_core::{EffectValue, PropagatingProcess};
use deep_causality_haft::LogAppend;
use std::fmt::Debug;
pub trait StatefulMonadicCausableCollection<I, O, S, C, T>:
CausableCollectionAccessor<I, O, T>
where
T: MonadicCausable<I, O> + StatefulMonadicCausable<I, O, S, C> + Causable,
I: Clone,
O: monadic_collection_utils::Aggregatable + Clone + Default + Send + Sync + 'static + Debug,
S: Clone + Default,
C: Clone,
{
fn evaluate_collection_stateful(
&self,
incoming: &PropagatingProcess<I, S, C>,
logic: &AggregateLogic,
threshold_value: Option<NumericalValue>,
) -> PropagatingProcess<O, S, C> {
if let Some(err) = incoming.error.clone() {
return PropagatingProcess {
value: EffectValue::None,
state: incoming.state.clone(),
context: incoming.context.clone(),
error: Some(err),
logs: incoming.logs.clone(),
};
}
let items = self.get_all_items();
if items.is_empty() {
return PropagatingProcess {
value: EffectValue::None,
state: incoming.state.clone(),
context: incoming.context.clone(),
error: Some(CausalityError(CausalityErrorEnum::Custom(
"Cannot evaluate an empty collection".to_string(),
))),
logs: incoming.logs.clone(),
};
}
let mut acc_values: Vec<EffectValue<O>> = Vec::with_capacity(items.len());
let mut acc_state: S = incoming.state.clone();
let mut acc_context: Option<C> = incoming.context.clone();
let mut acc_logs = incoming.logs.clone();
for item in items.into_iter() {
let item_in: PropagatingProcess<I, S, C> = PropagatingProcess {
value: incoming.value.clone(),
state: acc_state.clone(),
context: acc_context.clone(),
error: None,
logs: Default::default(),
};
let mut item_out = item.evaluate_stateful(&item_in);
acc_logs.append(&mut item_out.logs);
if let Some(err) = item_out.error.take() {
return PropagatingProcess {
value: EffectValue::None,
state: acc_state,
context: acc_context,
error: Some(err),
logs: acc_logs,
};
}
acc_state = item_out.state;
acc_context = item_out.context;
acc_values.push(item_out.value);
}
match monadic_collection_utils::aggregate_effects(&acc_values, logic, threshold_value) {
Ok(aggregated_value) => PropagatingProcess {
value: aggregated_value,
state: acc_state,
context: acc_context,
error: None,
logs: acc_logs,
},
Err(e) => PropagatingProcess {
value: EffectValue::None,
state: acc_state,
context: acc_context,
error: Some(e),
logs: acc_logs,
},
}
}
}