behavior_contracts/
guard.rs1use crate::value::Value;
10
11#[derive(Debug, Clone)]
12pub struct PortabilityError {
13 pub path: String,
14 pub message: String,
15}
16
17impl std::fmt::Display for PortabilityError {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 write!(f, "Portability Guard at {}: {}", self.path, self.message)
20 }
21}
22impl std::error::Error for PortabilityError {}
23
24pub fn assert_portable(value: &Value) -> Result<(), PortabilityError> {
27 assert_portable_at(value, "$")
28}
29
30fn assert_portable_at(value: &Value, path: &str) -> Result<(), PortabilityError> {
31 match value {
32 Value::Float(f) if !f.is_finite() => Err(PortabilityError {
33 path: path.to_string(),
34 message: format!("non-finite float {f} cannot be placed in portable IR"),
35 }),
36 Value::Arr(a) => {
37 for (i, v) in a.iter().enumerate() {
38 assert_portable_at(v, &format!("{path}[{i}]"))?;
39 }
40 Ok(())
41 }
42 Value::Obj(o) => {
43 for (k, v) in o {
44 assert_portable_at(v, &format!("{path}.{k}"))?;
45 }
46 Ok(())
47 }
48 _ => Ok(()),
49 }
50}