use turnframe_core::error::DomainRejection;
use turnframe_core::flow::WorkflowDefinition;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SimulatedTransition<S, E> {
Applied {
state: Option<S>,
events: Vec<E>,
},
Rejected(DomainRejection),
}
impl<S, E> SimulatedTransition<S, E> {
#[must_use]
pub fn applied(state: S, events: Vec<E>) -> Self {
Self::Applied {
state: Some(state),
events,
}
}
#[must_use]
pub fn removed(events: Vec<E>) -> Self {
Self::Applied {
state: None,
events,
}
}
#[must_use]
pub fn rejected(rejection: DomainRejection) -> Self {
Self::Rejected(rejection)
}
#[must_use]
pub fn is_applied(&self) -> bool {
matches!(self, Self::Applied { .. })
}
#[must_use]
pub fn next_state(&self) -> Option<&S> {
match self {
Self::Applied { state, .. } => state.as_ref(),
Self::Rejected(_) => None,
}
}
#[must_use]
pub fn events(&self) -> &[E] {
match self {
Self::Applied { events, .. } => events,
Self::Rejected(_) => &[],
}
}
#[must_use]
pub fn rejection(&self) -> Option<&DomainRejection> {
match self {
Self::Rejected(rejection) => Some(rejection),
Self::Applied { .. } => None,
}
}
}
pub trait WorkflowModel<W: WorkflowDefinition> {
fn initial_states(&self) -> Vec<Option<W::State>>;
fn candidate_commands(&self, state: Option<&W::State>) -> Vec<W::Command>;
fn simulate(
&self,
state: Option<&W::State>,
command: &W::Command,
) -> SimulatedTransition<W::State, W::Event>;
fn declared_outcomes(&self) -> Vec<W::Outcome> {
Vec::new()
}
}