use crate::value::Value;
#[derive(Debug, Clone)]
pub struct PortabilityError {
pub path: String,
pub message: String,
}
impl std::fmt::Display for PortabilityError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Portability Guard at {}: {}", self.path, self.message)
}
}
impl std::error::Error for PortabilityError {}
pub fn assert_portable(value: &Value) -> Result<(), PortabilityError> {
assert_portable_at(value, "$")
}
fn assert_portable_at(value: &Value, path: &str) -> Result<(), PortabilityError> {
match value {
Value::Float(f) if !f.is_finite() => Err(PortabilityError {
path: path.to_string(),
message: format!("non-finite float {f} cannot be placed in portable IR"),
}),
Value::Arr(a) => {
for (i, v) in a.iter().enumerate() {
assert_portable_at(v, &format!("{path}[{i}]"))?;
}
Ok(())
}
Value::Obj(o) => {
for (k, v) in o {
assert_portable_at(v, &format!("{path}.{k}"))?;
}
Ok(())
}
_ => Ok(()),
}
}