use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::send::Send;
use crate::State;
pub struct Command<S: State> {
pub(crate) update: Option<S>,
pub(crate) goto: Option<CommandGoto>,
pub(crate) interrupt_value: Option<Value>,
pub(crate) resume_value: Option<Value>,
}
impl<S: State> std::fmt::Debug for Command<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Command")
.field("has_update", &self.update.is_some())
.field("goto", &self.goto)
.field("interrupt_value", &self.interrupt_value)
.field("resume_value", &self.resume_value)
.finish()
}
}
impl<S: State> Clone for Command<S> {
fn clone(&self) -> Self {
Self {
update: self.update.clone(),
goto: self.goto.clone(),
interrupt_value: self.interrupt_value.clone(),
resume_value: self.resume_value.clone(),
}
}
}
impl<S: State> Command<S> {
pub fn goto(node: impl Into<String>) -> Self {
Self {
update: None,
goto: Some(CommandGoto::One(node.into())),
interrupt_value: None,
resume_value: None,
}
}
pub fn goto_with_update(node: impl Into<String>, update: S) -> Self {
Self {
update: Some(update),
goto: Some(CommandGoto::One(node.into())),
interrupt_value: None,
resume_value: None,
}
}
pub fn send(targets: Vec<Send>) -> Self {
Self {
update: None,
goto: Some(CommandGoto::Many(targets)),
interrupt_value: None,
resume_value: None,
}
}
pub fn update(state: S) -> Self {
Self {
update: Some(state),
goto: None,
interrupt_value: None,
resume_value: None,
}
}
pub fn resume(value: Value) -> Self {
Self {
update: None,
goto: None,
interrupt_value: None,
resume_value: Some(value),
}
}
pub fn end() -> Self {
Self {
update: None,
goto: Some(CommandGoto::One(crate::END.to_string())),
interrupt_value: None,
resume_value: None,
}
}
}
#[derive(Debug, Clone)]
pub enum CommandGoto {
One(String),
Many(Vec<Send>),
}
#[derive(Clone)]
pub enum NodeOutput<S: State> {
State(S),
Command(Command<S>),
}
impl<S: State + std::fmt::Debug> std::fmt::Debug for NodeOutput<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NodeOutput::State(s) => f.debug_tuple("NodeOutput::State").field(s).finish(),
NodeOutput::Command(c) => f.debug_tuple("NodeOutput::Command").field(c).finish(),
}
}
}
impl<S: State> From<S> for NodeOutput<S> {
fn from(state: S) -> Self {
NodeOutput::State(state)
}
}
#[derive(Debug, Clone)]
pub enum GraphResult<S> {
Complete(S),
Interrupted {
state: S,
interrupt_value: Value,
},
}
impl<S> GraphResult<S> {
pub fn state(&self) -> &S {
match self {
GraphResult::Complete(s) => s,
GraphResult::Interrupted { state, .. } => state,
}
}
pub fn into_state(self) -> S {
match self {
GraphResult::Complete(s) => s,
GraphResult::Interrupted { state, .. } => state,
}
}
pub fn is_complete(&self) -> bool {
matches!(self, GraphResult::Complete(_))
}
pub fn is_interrupted(&self) -> bool {
matches!(self, GraphResult::Interrupted { .. })
}
pub fn interrupt_value(&self) -> Option<&Value> {
match self {
GraphResult::Interrupted {
interrupt_value, ..
} => Some(interrupt_value),
_ => None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Interrupt {
pub value: Value,
}
pub fn interrupt<S: State>(value: Value) -> NodeOutput<S> {
NodeOutput::Command(Command {
update: None,
goto: None,
interrupt_value: Some(value),
resume_value: None,
})
}