behavior_contracts/
codec.rs1use crate::expr::FORBIDDEN_OBJECT_KEY;
9use crate::value::Value;
10use serde_json::Value as J;
11
12#[derive(Debug)]
18pub struct DecodeError {
19 pub msg: String,
20 pub code: Option<&'static str>,
21}
22
23impl DecodeError {
24 fn new(msg: impl Into<String>) -> Self {
25 DecodeError {
26 msg: msg.into(),
27 code: None,
28 }
29 }
30 fn coded(code: &'static str, msg: impl Into<String>) -> Self {
31 DecodeError {
32 msg: msg.into(),
33 code: Some(code),
34 }
35 }
36}
37
38impl std::fmt::Display for DecodeError {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 write!(f, "decode error: {}", self.msg)
41 }
42}
43impl std::error::Error for DecodeError {}
44
45pub fn decode_value(x: &J) -> Result<Value, DecodeError> {
56 match x {
57 J::Null => Ok(Value::Null),
58 J::Bool(b) => Ok(Value::Bool(*b)),
59 J::String(s) => Ok(Value::Str(s.clone())),
60 J::Number(n) => {
61 if let Some(i) = n.as_i64() {
62 if n.is_i64() || n.is_u64() {
65 return Ok(Value::Int(i));
66 }
67 Ok(Value::Int(i))
68 } else if n.is_u64() {
69 Err(DecodeError::new(format!("integer {n} exceeds i64")))
70 } else {
71 let f = n
73 .as_f64()
74 .ok_or_else(|| DecodeError::new(format!("bad number {n}")))?;
75 Ok(Value::Float(f))
76 }
77 }
78 J::Array(a) => {
79 let mut out = Vec::with_capacity(a.len());
80 for e in a {
81 out.push(decode_value(e)?);
82 }
83 Ok(Value::Arr(out))
84 }
85 J::Object(o) => {
86 if o.len() == 1 {
87 if let Some(J::String(s)) = o.get("int") {
88 let i: i64 = s
89 .parse()
90 .map_err(|_| DecodeError::new(format!("int literal '{s}' not i64")))?;
91 return Ok(Value::Int(i));
92 }
93 if let Some(J::Number(n)) = o.get("float") {
94 let f = n
95 .as_f64()
96 .ok_or_else(|| DecodeError::new(format!("bad float {n}")))?;
97 return Ok(Value::Float(f));
98 }
99 if o.contains_key("nan") {
100 return Ok(Value::Float(f64::NAN));
101 }
102 if let Some(J::Number(n)) = o.get("inf") {
103 let sign = n.as_f64().unwrap_or(1.0);
104 return Ok(Value::Float(if sign < 0.0 {
105 f64::NEG_INFINITY
106 } else {
107 f64::INFINITY
108 }));
109 }
110 }
111 let mut out = Vec::with_capacity(o.len());
112 for (k, v) in o {
113 if k == FORBIDDEN_OBJECT_KEY {
116 return Err(DecodeError::coded(
117 "FORBIDDEN_KEY",
118 format!("object key \"{FORBIDDEN_OBJECT_KEY}\" is forbidden (fail-closed)"),
119 ));
120 }
121 out.push((k.clone(), decode_value(v)?));
122 }
123 Ok(Value::Obj(out))
124 }
125 }
126}
127
128pub fn encode_value(v: &Value) -> J {
131 match v {
132 Value::Null => J::Null,
133 Value::Bool(b) => J::Bool(*b),
134 Value::Str(s) => J::String(s.clone()),
135 Value::Int(i) => {
136 const SAFE: i64 = 9_007_199_254_740_991; if *i >= -SAFE && *i <= SAFE {
138 J::Number((*i).into())
139 } else {
140 let mut m = serde_json::Map::new();
141 m.insert("int".into(), J::String(i.to_string()));
142 J::Object(m)
143 }
144 }
145 Value::Float(f) => {
146 if f.fract() == 0.0 && f.is_finite() {
147 let mut m = serde_json::Map::new();
148 m.insert(
149 "float".into(),
150 serde_json::Number::from_f64(*f)
151 .map(J::Number)
152 .unwrap_or(J::Null),
153 );
154 J::Object(m)
155 } else {
156 serde_json::Number::from_f64(*f)
157 .map(J::Number)
158 .unwrap_or(J::Null)
159 }
160 }
161 Value::Arr(a) => J::Array(a.iter().map(encode_value).collect()),
162 Value::Obj(o) => {
163 let mut m = serde_json::Map::new();
164 for (k, val) in o {
165 m.insert(k.clone(), encode_value(val));
166 }
167 J::Object(m)
168 }
169 }
170}