use serde::{Deserialize, Serialize};
use crate::error::WyrdError;
use super::ids::JsonPath;
use super::operator::ComparisonOperator;
pub const MAX_CONDITION_DEPTH: u32 = 16;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct EvalCondition {
pub path: JsonPath,
pub operator: ComparisonOperator,
pub expected: serde_json::Value,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub combinator: Option<ConditionCombinator>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub subsequent: Option<Box<EvalCondition>>,
}
impl EvalCondition {
#[must_use]
pub fn depth(&self) -> u32 {
let mut depth = 1_u32;
let mut current = self.subsequent.as_deref();
while let Some(node) = current {
depth = depth.saturating_add(1);
current = node.subsequent.as_deref();
}
depth
}
pub fn validate(&self) -> Result<(), WyrdError> {
let depth = self.depth();
if depth > MAX_CONDITION_DEPTH {
return Err(WyrdError::Validation {
message: format!("eval_condition depth {depth} exceeds max {MAX_CONDITION_DEPTH}"),
details: serde_json::Value::Null,
});
}
let mut current = Some(self);
while let Some(node) = current {
match (node.combinator.is_some(), node.subsequent.is_some()) {
(false, false) | (true, true) => {}
(true, false) => {
return Err(WyrdError::Validation {
message: "eval_condition has combinator without subsequent".to_string(),
details: serde_json::Value::Null,
});
}
(false, true) => {
return Err(WyrdError::Validation {
message: "eval_condition has subsequent without combinator".to_string(),
details: serde_json::Value::Null,
});
}
}
current = node.subsequent.as_deref();
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ConditionCombinator {
And,
Or,
}