sim_codec_json/
json_tree.rs1use serde_json::{Map, Number, Value};
4use sim_codec::{DecodeBudget, DecodeLimits};
5use sim_kernel::{CodecId, Error, Result};
6
7#[derive(Clone, Debug, PartialEq, Eq)]
12pub enum JsonTree {
13 Null,
15 Bool(bool),
17 Number(String),
19 String(String),
21 Array(Vec<JsonTree>),
23 Object(Vec<(String, JsonTree)>),
25}
26
27pub fn parse_json(codec: CodecId, source: &str) -> Result<JsonTree> {
29 parse_json_with_limits(codec, source, DecodeLimits::default())
30}
31
32pub fn parse_json_with_limits(
34 codec: CodecId,
35 source: &str,
36 limits: DecodeLimits,
37) -> Result<JsonTree> {
38 let mut budget = DecodeBudget::new(limits);
39 budget.check_input_bytes(codec, source.len())?;
40 let value = serde_json::from_str(source).map_err(|error| json_error(codec, error))?;
41 JsonTree::from_value(codec, value, &mut budget, 0)
42}
43
44pub fn render_json(codec: CodecId, tree: &JsonTree) -> Result<String> {
46 serde_json::to_string(&tree.to_value(codec)?).map_err(|error| json_error(codec, error))
47}
48
49impl JsonTree {
50 pub fn number_from_f64(codec: CodecId, value: f64) -> Result<Self> {
55 Number::from_f64(value)
56 .map(|number| Self::Number(number.to_string()))
57 .ok_or_else(|| json_error(codec, "non-finite number"))
58 }
59
60 pub fn number_as_f64(&self, codec: CodecId) -> Result<f64> {
62 let Self::Number(value) = self else {
63 return Err(json_error(codec, "JSON value is not a number"));
64 };
65 value
66 .parse::<f64>()
67 .map_err(|error| json_error(codec, error))
68 }
69
70 pub(crate) fn from_json_value(value: Value) -> Self {
71 match value {
72 Value::Null => Self::Null,
73 Value::Bool(value) => Self::Bool(value),
74 Value::Number(value) => Self::Number(value.to_string()),
75 Value::String(value) => Self::String(value),
76 Value::Array(values) => {
77 Self::Array(values.into_iter().map(Self::from_json_value).collect())
78 }
79 Value::Object(values) => Self::Object(
80 values
81 .into_iter()
82 .map(|(key, value)| (key, Self::from_json_value(value)))
83 .collect(),
84 ),
85 }
86 }
87
88 pub(crate) fn to_json_value(&self, codec: CodecId) -> Result<Value> {
89 self.to_value(codec)
90 }
91
92 fn from_value(
93 codec: CodecId,
94 value: Value,
95 budget: &mut DecodeBudget,
96 depth: usize,
97 ) -> Result<Self> {
98 budget.enter_node(codec, depth)?;
99 match value {
100 Value::Null => Ok(Self::Null),
101 Value::Bool(value) => Ok(Self::Bool(value)),
102 Value::Number(value) => Ok(Self::Number(value.to_string())),
103 Value::String(value) => {
104 budget.check_string_bytes(codec, value.len())?;
105 Ok(Self::String(value))
106 }
107 Value::Array(values) => {
108 budget.check_collection_len(codec, values.len())?;
109 values
110 .into_iter()
111 .map(|value| Self::from_value(codec, value, budget, depth + 1))
112 .collect::<Result<Vec<_>>>()
113 .map(Self::Array)
114 }
115 Value::Object(values) => {
116 budget.check_collection_len(codec, values.len())?;
117 values
118 .into_iter()
119 .map(|(key, value)| {
120 budget.check_string_bytes(codec, key.len())?;
121 Ok((key, Self::from_value(codec, value, budget, depth + 1)?))
122 })
123 .collect::<Result<Vec<_>>>()
124 .map(Self::Object)
125 }
126 }
127 }
128
129 fn to_value(&self, codec: CodecId) -> Result<Value> {
130 match self {
131 Self::Null => Ok(Value::Null),
132 Self::Bool(value) => Ok(Value::Bool(*value)),
133 Self::Number(value) => value
134 .parse::<Number>()
135 .map(Value::Number)
136 .map_err(|error| json_error(codec, error)),
137 Self::String(value) => Ok(Value::String(value.clone())),
138 Self::Array(values) => values
139 .iter()
140 .map(|value| value.to_value(codec))
141 .collect::<Result<Vec<_>>>()
142 .map(Value::Array),
143 Self::Object(values) => values
144 .iter()
145 .map(|(key, value)| Ok((key.clone(), value.to_value(codec)?)))
146 .collect::<Result<Map<_, _>>>()
147 .map(Value::Object),
148 }
149 }
150}
151
152fn json_error(codec: CodecId, error: impl std::fmt::Display) -> Error {
153 Error::CodecError {
154 codec,
155 message: error.to_string(),
156 }
157}