use std::any::TypeId;
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use crate::clone_any::CloneAny;
use crate::context::FlowContext;
use crate::error::FlowError;
pub trait FlowState: Clone + Copy + Eq + Hash + Debug + Send + Sync + 'static {
fn is_terminal(&self) -> bool;
fn is_initial(&self) -> bool;
fn all_states() -> &'static [Self];
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TransitionType { Auto, External, Branch, SubFlow }
pub enum GuardOutput {
Accepted { data: HashMap<TypeId, Box<dyn CloneAny>> },
Rejected { reason: String },
Expired,
}
impl GuardOutput {
pub fn accepted_empty() -> Self {
GuardOutput::Accepted { data: HashMap::new() }
}
pub fn accept_with<T: CloneAny + 'static>(item: T) -> Self {
let mut data = HashMap::new();
data.insert(TypeId::of::<T>(), Box::new(item) as Box<dyn CloneAny>);
GuardOutput::Accepted { data }
}
pub fn accepted(data: HashMap<TypeId, Box<dyn CloneAny>>) -> Self {
GuardOutput::Accepted { data }
}
pub fn rejected(reason: impl Into<String>) -> Self {
GuardOutput::Rejected { reason: reason.into() }
}
}
pub trait StateProcessor<S: FlowState>: Send + Sync {
fn name(&self) -> &str;
fn requires(&self) -> Vec<TypeId>;
fn produces(&self) -> Vec<TypeId>;
fn process(&self, ctx: &mut FlowContext) -> Result<(), FlowError>;
}
pub trait TransitionGuard<S: FlowState>: Send + Sync {
fn name(&self) -> &str;
fn requires(&self) -> Vec<TypeId>;
fn produces(&self) -> Vec<TypeId>;
fn validate(&self, ctx: &FlowContext) -> GuardOutput;
}
pub trait BranchProcessor<S: FlowState>: Send + Sync {
fn name(&self) -> &str;
fn requires(&self) -> Vec<TypeId>;
fn decide(&self, ctx: &FlowContext) -> String;
}
pub struct Transition<S: FlowState> {
pub from: S,
pub to: S,
pub transition_type: TransitionType,
pub processor: Option<Box<dyn StateProcessor<S>>>,
pub guard: Option<Box<dyn TransitionGuard<S>>>,
pub branch: Option<Box<dyn BranchProcessor<S>>>,
pub branch_targets: HashMap<String, S>,
pub branch_label: Option<String>,
pub sub_flow: Option<crate::sub_flow::SubFlowConfig<S>>,
pub timeout: Option<std::time::Duration>,
}