use crate::planning::semantics::{DataPath, RulePath};
use serde::{Serialize, Serializer};
pub(crate) fn serialize_rule_path_as_name<S>(
path: &RulePath,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&path.rule)
}
pub(crate) fn serialize_data_path_as_name<S>(
path: &DataPath,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&path.input_key())
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ExplanationNode {
Rule {
#[serde(serialize_with = "serialize_rule_path_as_name")]
name: RulePath,
#[serde(serialize_with = "serialize_option_string")]
result: Option<String>,
body: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
causes: Vec<Cause>,
#[serde(skip_serializing_if = "Vec::is_empty")]
children: Vec<ExplanationNode>,
},
Compose {
expression: String,
operands: Vec<ExplanationNode>,
},
Data {
#[serde(serialize_with = "serialize_data_path_as_name")]
name: DataPath,
display: String,
},
DataUnused {
#[serde(serialize_with = "serialize_data_path_as_name")]
name: DataPath,
},
Conversion {
expression: String,
steps: Vec<SerializedConversionTraceStep>,
operands: Vec<ExplanationNode>,
},
Veto {
#[serde(skip_serializing_if = "Option::is_none")]
message: Option<String>,
},
UnitEquivalence {
text: String,
},
Piecewise {
#[serde(serialize_with = "forbid_piecewise_serialize")]
arms: Vec<PiecewiseArm>,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PiecewiseArm {
pub condition: ExplanationNode,
pub result: ExplanationNode,
pub static_condition: Option<bool>,
pub static_cause_value: Option<bool>,
}
fn forbid_piecewise_serialize<S: Serializer>(
_: &Vec<PiecewiseArm>,
_: S,
) -> Result<S::Ok, S::Error> {
panic!("BUG: Piecewise must be lowered before serialize")
}
fn serialize_option_string<S>(value: &Option<String>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match value {
Some(s) => serializer.serialize_str(s),
None => serializer.serialize_none(),
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Cause {
pub condition: String,
#[serde(serialize_with = "serialize_option_string")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub children: Vec<ExplanationNode>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ConversionTraceRole {
Outcome,
Rule,
Source,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct SerializedConversionTraceStep {
pub(crate) role: ConversionTraceRole,
pub(crate) text: String,
}