use super::{
MachineDescriptor, MachineGraph, MachineStateIdentity, StateDescriptor, TransitionDescriptor,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct TransitionTelemetryLabels {
pub machine: &'static str,
pub from_state: &'static str,
pub transition: &'static str,
pub chosen_state: &'static str,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RecordedTransition<S: 'static, T: 'static> {
pub machine: MachineDescriptor,
pub from: S,
pub transition: T,
pub chosen: S,
}
impl<S, T> RecordedTransition<S, T>
where
S: 'static,
T: 'static,
{
pub const fn new(machine: MachineDescriptor, from: S, transition: T, chosen: S) -> Self {
Self {
machine,
from,
transition,
chosen,
}
}
pub fn transition_in<'a>(
&self,
graph: &'a MachineGraph<S, T>,
) -> Option<&'a TransitionDescriptor<S, T>>
where
S: Copy + Eq,
T: Copy + Eq,
{
if self.machine != graph.machine {
return None;
}
let descriptor = graph.transition(self.transition)?;
if descriptor.from == self.from && descriptor.to.contains(&self.chosen) {
Some(descriptor)
} else {
None
}
}
pub fn source_state_in<'a>(
&self,
graph: &'a MachineGraph<S, T>,
) -> Option<&'a StateDescriptor<S>>
where
S: Copy + Eq,
T: Copy + Eq,
{
self.transition_in(graph)?;
graph.state(self.from)
}
pub fn chosen_state_in<'a>(
&self,
graph: &'a MachineGraph<S, T>,
) -> Option<&'a StateDescriptor<S>>
where
S: Copy + Eq,
T: Copy + Eq,
{
self.transition_in(graph)?;
graph.state(self.chosen)
}
pub fn telemetry_labels_in(
&self,
graph: &MachineGraph<S, T>,
) -> Option<TransitionTelemetryLabels>
where
S: Copy + Eq,
T: Copy + Eq,
{
let transition = self.transition_in(graph)?;
let from_state = graph.state(self.from)?;
let chosen_state = graph.state(self.chosen)?;
Some(TransitionTelemetryLabels {
machine: graph.machine_label(),
from_state: from_state.rust_name,
transition: transition.method_name,
chosen_state: chosen_state.rust_name,
})
}
}
pub trait MachineTransitionRecorder: MachineStateIdentity {
fn try_record_transition(
transition: Self::TransitionId,
chosen: Self::StateId,
) -> Option<RecordedTransition<Self::StateId, Self::TransitionId>> {
let graph = Self::GRAPH;
let descriptor = graph.transition(transition)?;
if descriptor.from != Self::STATE_ID || !descriptor.to.contains(&chosen) {
return None;
}
Some(RecordedTransition::new(
graph.machine,
Self::STATE_ID,
transition,
chosen,
))
}
fn try_record_transition_to<Next>(
transition: Self::TransitionId,
) -> Option<RecordedTransition<Self::StateId, Self::TransitionId>>
where
Next: MachineStateIdentity<StateId = Self::StateId, TransitionId = Self::TransitionId>,
{
Self::try_record_transition(transition, Next::STATE_ID)
}
}
impl<M> MachineTransitionRecorder for M where M: MachineStateIdentity {}