use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
use crate::ir::Chart;
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Value {
#[default]
Undefined,
Null,
Bool(bool),
Number(f64),
String(String),
Array(Vec<Value>),
Object(Vec<(String, Value)>),
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EvalError {
pub message: String,
}
impl EvalError {
pub fn new(message: impl Into<String>) -> Self {
EvalError {
message: message.into(),
}
}
}
impl core::fmt::Display for EvalError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(&self.message)
}
}
impl core::error::Error for EvalError {}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum EventType {
Platform,
Internal,
#[default]
External,
}
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Event {
pub name: String,
pub type_: EventType,
pub sendid: Option<String>,
pub origin: Option<String>,
pub origintype: Option<String>,
#[cfg_attr(feature = "serde", serde(default))]
pub originverified: bool,
pub invokeid: Option<String>,
pub data: Value,
}
impl Event {
pub fn named(name: impl Into<String>, type_: EventType) -> Self {
Event {
name: name.into(),
type_,
..Event::default()
}
}
pub fn with_verified_origin(mut self, sender: impl Into<String>) -> Self {
self.origin = Some(sender.into());
self.originverified = true;
self
}
}
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SessionInfo {
pub sessionid: String,
pub name: Option<String>,
pub ioprocessors: Value,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Environment {
pub now_ms: i64,
pub seed: u64,
}
pub trait StateQuery {
fn in_state(&self, id: &str) -> bool;
fn active_states(&self) -> Option<Vec<String>> {
None
}
}
pub trait Datamodel {
fn name(&self) -> &str;
fn init_session(&mut self, info: &SessionInfo) -> Result<(), EvalError>;
fn set_environment(&mut self, env: &Environment);
fn declare(&mut self, id: &str) -> Result<(), EvalError>;
fn set_event(&mut self, event: &Event);
fn check_event(&self, _event: &Event) -> Result<(), EvalError> {
Ok(())
}
fn eval_cond(&mut self, expr: &str, states: &dyn StateQuery) -> Result<bool, EvalError>;
fn eval_value(&mut self, expr: &str, states: &dyn StateQuery) -> Result<Value, EvalError>;
fn eval_content(&mut self, content: &str) -> Result<Value, EvalError>;
fn assign_expr(
&mut self,
location: &str,
expr: &str,
states: &dyn StateQuery,
) -> Result<(), EvalError>;
fn assign_value(&mut self, location: &str, value: Value) -> Result<(), EvalError>;
fn bind_var(&mut self, name: &str, value: Value) -> Result<(), EvalError>;
fn is_location(&mut self, location: &str) -> bool;
fn exec_script(&mut self, script: &str, states: &dyn StateQuery) -> Result<(), EvalError>;
fn foreach_items(
&mut self,
array: &str,
states: &dyn StateQuery,
) -> Result<Vec<Value>, EvalError>;
fn snapshot(&self) -> Value;
fn restore(&mut self, snapshot: &Value) -> Result<(), EvalError>;
}
pub trait DatamodelRegistry {
fn create(&self, name: &str) -> Option<Box<dyn Datamodel>>;
fn create_for(&self, chart: &Chart) -> Option<Result<Box<dyn Datamodel>, Vec<String>>> {
self.create(&chart.datamodel).map(Ok)
}
fn check(&self, _chart: &Chart) -> Result<(), Vec<String>> {
Ok(())
}
}
pub fn admit(dm: &dyn Datamodel, event: Event) -> Event {
match dm.check_event(&event) {
Ok(()) => event,
Err(e) => Event {
name: String::from("error.execution"),
type_: EventType::Platform,
sendid: event.sendid,
data: Value::Object(Vec::from([
(
String::from("kind"),
Value::String(String::from("execution")),
),
(String::from("message"), Value::String(e.message)),
])),
..Event::default()
},
}
}