use crate::StateMachine;
use eyre::Report;
use nodo::{
app::AppSetupScheduleContext,
codelet::{Lifecycle, Transition, Vise, ViseTrait},
monitors::SharedAppMonitor,
prelude::{Outcome, ParameterId, ParameterSet, ParameterWithPropertiesSet, RUNNING},
};
pub(crate) struct SequenceExecutor {
schedule_name: String,
sequence_name: String,
items: Vec<StateMachine<Vise>>,
monitor: SharedAppMonitor,
}
impl SequenceExecutor {
pub fn new<'a, I: IntoIterator<Item = Vise>>(
context: &mut AppSetupScheduleContext<'a>,
schedule_name: String,
sequence_name: String,
vises: I,
) -> Self {
context.on_begin_sequence(sequence_name.clone());
let mut items = Vec::new();
for mut vise in vises.into_iter() {
context.on_node(&mut vise);
items.push(StateMachine::new(vise));
}
context.on_end_sequence();
Self {
schedule_name,
sequence_name,
items,
monitor: context.monitor(),
}
}
pub fn get_parameters_with_properties(
&self,
) -> ParameterWithPropertiesSet<String, &'static str> {
let mut result = ParameterWithPropertiesSet::default();
for item in self.items.iter() {
result.extend(item.inner().get_parameters_with_properties().map_into(
|(ParameterId((), b), v)| (ParameterId(item.inner().name().to_string(), b), v),
));
}
result
}
pub fn configure(&mut self, config: &ParameterSet<String, String>) {
for (key, value) in config.iter() {
if let Some(vise) = self.find_vise_by_name_mut(key.node()) {
if let Err(err) = vise.configure(key.param(), value) {
log::error!("{err:?}");
}
}
}
}
fn find_vise_by_name_mut(&mut self, needle: &str) -> Option<&mut Vise> {
self.items
.iter_mut()
.map(|sm| sm.inner_mut())
.find(|vise| vise.name() == needle)
}
}
impl Lifecycle for SequenceExecutor {
fn cycle(&mut self, transition: Transition) -> Outcome {
let mut result = SequenceExecutorCycleResult::new();
for csm in self.items.iter_mut() {
match csm.transition(transition) {
Err(err) => {
result.mark(csm.inner(), err.into());
}
Ok(_) => {}
}
}
match result.into() {
Some(err) => Err(err),
None => RUNNING,
}
}
}
struct SequenceExecutorCycleResult {
maybe: Option<SequenceExecutorCycleError>,
}
impl SequenceExecutorCycleResult {
fn new() -> Self {
SequenceExecutorCycleResult { maybe: None }
}
fn mark(&mut self, vise: &Vise, error: Report) {
if self.maybe.is_none() {
self.maybe = Some(SequenceExecutorCycleError::new());
}
self.maybe.as_mut().unwrap().mark(vise, error);
}
}
#[derive(thiserror::Error, Debug)]
#[error("SequenceExecutorCycleError({:?})", self.failures)]
struct SequenceExecutorCycleError {
failures: Vec<(String, Report)>,
}
impl SequenceExecutorCycleError {
fn new() -> Self {
SequenceExecutorCycleError {
failures: Vec::new(),
}
}
fn mark(&mut self, vise: &Vise, error: Report) {
self.failures.push((vise.name().to_string(), error));
}
}
impl From<SequenceExecutorCycleResult> for Option<eyre::Report> {
fn from(value: SequenceExecutorCycleResult) -> Self {
match value.maybe {
Some(x) => Some(x.into()),
None => None,
}
}
}