use crate::action::Action;
use crate::transition::Transition;
use crate::{Context, Event, EventTrait};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use std::fmt::{Debug, Display};
use std::hash::Hash;
use uuid::Uuid;
pub trait StateTrait:
Serialize + DeserializeOwned + Clone + Debug + Display + Hash + Eq + Send + Sync + 'static
{
fn id(&self) -> &Self;
}
impl StateTrait for String {
fn id(&self) -> &Self {
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub enum StateType {
Normal,
Compound,
Parallel,
Final,
History,
DeepHistory,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub enum HistoryType {
Shallow,
Deep,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(bound(
serialize = "S: Serialize",
deserialize = "S: StateTrait + DeserializeOwned + Eq + Hash"
))]
pub struct State<S = String, C = Context, E = Event>
where
S: StateTrait
+ Serialize
+ DeserializeOwned
+ Clone
+ Debug
+ Display
+ Hash
+ Eq
+ Send
+ Sync
+ 'static,
C: Send + Sync + 'static + Default + Clone + Debug + Serialize + DeserializeOwned,
E: EventTrait + Send + Sync + 'static + Eq + Clone + Debug + Serialize + DeserializeOwned,
{
pub id: S,
#[serde(rename = "type")]
pub state_type: StateType,
pub parent: Option<S>,
#[serde(bound(deserialize = "S: StateTrait + Eq + Hash + DeserializeOwned"))]
pub children: HashMap<String, State<S, C, E>>,
pub initial: Option<S>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub data: Option<Value>,
#[serde(default = "Uuid::new_v4")]
pub(crate) uuid: Uuid,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub meta: Option<Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub history: Option<HistoryType>,
#[serde(skip, default, skip_serializing_if = "Vec::is_empty")]
pub entry: Vec<Action<C, E>>,
#[serde(skip, default, skip_serializing_if = "Vec::is_empty")]
pub exit: Vec<Action<C, E>>,
#[serde(skip, default, skip_serializing_if = "HashMap::is_empty")]
pub on: HashMap<String, Vec<Transition<S, C, E>>>,
}
impl<S, C, E> State<S, C, E>
where
S: StateTrait
+ Serialize
+ DeserializeOwned
+ Clone
+ Debug
+ Display
+ Hash
+ Eq
+ Send
+ Sync
+ 'static,
C: Clone + Default + Send + Sync + Debug + 'static + Serialize + DeserializeOwned,
E: EventTrait + Send + Sync + 'static + Eq + Clone + Debug + Serialize + DeserializeOwned,
{
pub fn new(id: S) -> Self {
Self {
id,
state_type: StateType::Normal,
parent: None,
children: HashMap::new(),
initial: None,
data: None,
uuid: Uuid::new_v4(),
meta: None,
history: None,
entry: Vec::new(),
exit: Vec::new(),
on: HashMap::new(),
}
}
pub fn new_compound(id: S, initial: S) -> Self {
Self {
id,
state_type: StateType::Compound,
parent: None,
children: HashMap::new(),
initial: Some(initial),
data: None,
uuid: Uuid::new_v4(),
meta: None,
history: None,
entry: Vec::new(),
exit: Vec::new(),
on: HashMap::new(),
}
}
pub fn new_parallel(id: S) -> Self {
Self {
id,
state_type: StateType::Parallel,
parent: None,
children: HashMap::new(),
initial: None,
data: None,
uuid: Uuid::new_v4(),
meta: None,
history: None,
entry: Vec::new(),
exit: Vec::new(),
on: HashMap::new(),
}
}
pub fn new_final(id: S) -> Self {
Self {
id,
state_type: StateType::Final,
parent: None,
children: HashMap::new(),
initial: None,
data: None,
uuid: Uuid::new_v4(),
meta: None,
history: None,
entry: Vec::new(),
exit: Vec::new(),
on: HashMap::new(),
}
}
pub fn new_history(id: S, history_type: HistoryType) -> Self {
Self {
id,
state_type: StateType::History,
parent: None,
children: HashMap::new(),
initial: None,
data: None,
uuid: Uuid::new_v4(),
meta: None,
history: Some(history_type),
entry: Vec::new(),
exit: Vec::new(),
on: HashMap::new(),
}
}
pub fn add_child(&mut self, mut child_state: State<S, C, E>) -> &mut Self {
child_state.parent = Some(self.id.clone());
self.children
.insert(child_state.id.to_string(), child_state);
self
}
pub fn add_entry(&mut self, action: impl Into<Action<C, E>>) -> &mut Self {
self.entry.push(action.into());
self
}
pub fn add_exit(&mut self, action: impl Into<Action<C, E>>) -> &mut Self {
self.exit.push(action.into());
self
}
pub fn add_transition(
&mut self,
event: impl Into<String>,
transition: impl Into<Transition<S, C, E>>,
) -> &mut Self {
self.on
.entry(event.into())
.or_default()
.push(transition.into());
self
}
pub fn with_data(mut self, data: Value) -> Self {
self.data = Some(data);
self
}
pub fn with_parent(mut self, parent_id: S) -> Self {
self.parent = Some(parent_id);
self
}
pub fn with_initial(mut self, initial_id: S) -> Self {
self.initial = Some(initial_id);
self
}
pub fn with_meta(mut self, meta: Value) -> Self {
self.meta = Some(meta);
self
}
pub fn id(&self) -> &S {
&self.id
}
pub fn state_type(&self) -> StateType {
self.state_type.clone()
}
pub fn parent(&self) -> Option<&S> {
self.parent.as_ref()
}
pub fn children(&self) -> &HashMap<String, State<S, C, E>> {
&self.children
}
pub fn initial(&self) -> Option<&S> {
self.initial.as_ref()
}
pub fn data(&self) -> Option<&Value> {
self.data.as_ref()
}
pub fn meta(&self) -> Option<&Value> {
self.meta.as_ref()
}
pub fn history(&self) -> Option<HistoryType> {
self.history.clone()
}
pub fn entry_actions(&self) -> &Vec<Action<C, E>> {
&self.entry
}
pub fn exit_actions(&self) -> &Vec<Action<C, E>> {
&self.exit
}
pub fn transitions(&self) -> &HashMap<String, Vec<Transition<S, C, E>>> {
&self.on
}
pub fn is_final(&self) -> bool {
self.state_type == StateType::Final
}
pub fn is_atomic(&self) -> bool {
self.state_type == StateType::Normal && self.children.is_empty()
}
pub fn is_compound(&self) -> bool {
self.state_type == StateType::Compound
}
pub fn is_parallel(&self) -> bool {
self.state_type == StateType::Parallel
}
pub fn is_history(&self) -> bool {
matches!(self.state_type, StateType::History | StateType::DeepHistory)
}
}
#[derive(Debug, Default, Clone, Serialize)]
#[serde(bound(serialize = "S: Serialize"))]
pub struct StateCollection<S, C = Context, E = Event>
where
S: StateTrait
+ Eq
+ Hash
+ Serialize
+ DeserializeOwned
+ Clone
+ Debug
+ Display
+ Send
+ Sync
+ 'static
+ From<String>,
C: Clone + Default + Send + Sync + Debug + 'static + Serialize + DeserializeOwned,
E: EventTrait + Send + Sync + 'static + Eq + Clone + Debug + Serialize + DeserializeOwned,
{
#[serde(bound(deserialize = "S: StateTrait + Eq + Hash + DeserializeOwned"))]
states: HashMap<String, State<S, C, E>>,
}
impl<S, C, E> StateCollection<S, C, E>
where
S: StateTrait
+ Eq
+ Hash
+ Serialize
+ DeserializeOwned
+ Clone
+ Debug
+ Display
+ Send
+ Sync
+ 'static
+ From<String>,
C: Clone + Default + Send + Sync + Debug + 'static + Serialize + DeserializeOwned,
E: EventTrait + Send + Sync + 'static + Eq + Clone + Debug + Serialize + DeserializeOwned,
{
pub fn new() -> Self {
Self {
states: HashMap::new(),
}
}
pub fn add(&mut self, state: State<S, C, E>) -> &mut Self {
self.states.insert(state.id.to_string(), state);
self
}
pub fn get(&self, id: &S) -> Option<&State<S, C, E>> {
self.states.get(&id.to_string())
}
pub fn get_mut(&mut self, id: &S) -> Option<&mut State<S, C, E>> {
self.states.get_mut(&id.to_string())
}
pub fn contains(&self, id: &S) -> bool {
self.states.contains_key(&id.to_string())
}
pub fn all(&self) -> impl Iterator<Item = &State<S, C, E>> {
self.states.values()
}
pub fn is_empty(&self) -> bool {
self.states.is_empty()
}
}