value_ext/json/
json_value_ext.rs1use crate::AsType;
2use serde::de::DeserializeOwned;
3use serde::Serialize;
4use serde_json::{json, Map, Value};
5use std::collections::VecDeque;
6
7pub trait JsonValueExt {
29 fn x_new_object() -> Value;
30
31 fn x_contains<T: DeserializeOwned>(&self, name_or_pointer: &str) -> bool;
32
33 fn x_get<T: DeserializeOwned>(&self, name_or_pointer: &str) -> Result<T>;
37
38 fn x_get_as<'a, T: AsType<'a>>(&'a self, name_or_pointer: &str) -> Result<T>;
42
43 fn x_get_str(&self, name_or_pointer: &str) -> Result<&str> {
45 self.x_get_as(name_or_pointer)
46 }
47
48 fn x_get_i64(&self, name_or_pointer: &str) -> Result<i64> {
50 self.x_get_as(name_or_pointer)
51 }
52
53 fn x_get_f64(&self, name_or_pointer: &str) -> Result<f64> {
55 self.x_get_as(name_or_pointer)
56 }
57
58 fn x_get_bool(&self, name_or_pointer: &str) -> Result<bool> {
60 self.x_get_as(name_or_pointer)
61 }
62
63 fn x_take<T: DeserializeOwned>(&mut self, name_or_pointer: &str) -> Result<T>;
66
67 fn x_remove<T: DeserializeOwned>(&mut self, name_or_pointer: &str) -> Result<T>;
70
71 fn x_insert<T: Serialize>(&mut self, name_or_pointer: &str, value: T) -> Result<()>;
75
76 fn x_walk<F>(&mut self, callback: F) -> bool
84 where
85 F: FnMut(&mut Map<String, Value>, &str) -> bool;
86
87 fn x_pretty(&self) -> Result<String>;
89}
90
91impl JsonValueExt for Value {
92 fn x_new_object() -> Value {
93 Value::Object(Map::new())
94 }
95
96 fn x_contains<T: DeserializeOwned>(&self, name_or_pointer: &str) -> bool {
97 if name_or_pointer.starts_with('/') {
98 self.pointer(name_or_pointer).is_some()
99 } else {
100 self.get(name_or_pointer).is_some()
101 }
102 }
103
104 fn x_get<T: DeserializeOwned>(&self, name_or_pointer: &str) -> Result<T> {
105 let value = if name_or_pointer.starts_with('/') {
106 self.pointer(name_or_pointer)
107 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
108 } else {
109 self.get(name_or_pointer)
110 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
111 };
112
113 let value: T =
114 serde_json::from_value(value.clone())
115 .map_err(JsonValueExtError::from)
116 .map_err(|err| match err {
117 JsonValueExtError::ValueNotOfType(not_of_type) => JsonValueExtError::PropertyValueNotOfType {
118 name: name_or_pointer.to_string(),
119 not_of_type,
120 },
121 other => other,
122 })?;
123
124 Ok(value)
125 }
126
127 fn x_get_as<'a, T: AsType<'a>>(&'a self, name_or_pointer: &str) -> Result<T> {
128 let value = if name_or_pointer.starts_with('/') {
129 self.pointer(name_or_pointer)
130 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
131 } else {
132 self.get(name_or_pointer)
133 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
134 };
135
136 T::from_value(value).map_err(|err| match err {
137 JsonValueExtError::ValueNotOfType(not_of_type) => JsonValueExtError::PropertyValueNotOfType {
138 name: name_or_pointer.to_string(),
139 not_of_type,
140 },
141 other => other,
142 })
143 }
144
145 fn x_take<T: DeserializeOwned>(&mut self, name_or_pointer: &str) -> Result<T> {
146 let value = if name_or_pointer.starts_with('/') {
147 self.pointer_mut(name_or_pointer)
148 .map(Value::take)
149 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
150 } else {
151 self.get_mut(name_or_pointer)
152 .map(Value::take)
153 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
154 };
155
156 let value: T = serde_json::from_value(value)?;
157 Ok(value)
158 }
159
160 fn x_remove<T: DeserializeOwned>(&mut self, name_or_pointer: &str) -> Result<T> {
161 if !name_or_pointer.starts_with('/') {
162 match self {
163 Value::Object(map) => {
164 let removed = map
165 .remove(name_or_pointer)
166 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?;
167 let value: T = serde_json::from_value(removed)?;
168 Ok(value)
169 }
170 _ => Err(JsonValueExtError::custom("Value is not an Object; cannot x_remove")),
171 }
172 } else {
173 let parts: Vec<&str> = name_or_pointer.split('/').skip(1).collect();
174 if parts.is_empty() {
175 return Err(JsonValueExtError::custom("Invalid path"));
176 }
177 let mut current = self;
178 for &part in &parts[..parts.len() - 1] {
179 match current {
180 Value::Object(map) => {
181 current = map
182 .get_mut(part)
183 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?;
184 }
185 Value::Array(arr) => {
186 let index: usize = part
187 .parse()
188 .map_err(|_| JsonValueExtError::custom("Invalid array index in pointer"))?;
189 if index < arr.len() {
190 current = &mut arr[index];
191 } else {
192 return Err(JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()));
193 }
194 }
195 _ => return Err(JsonValueExtError::custom("Path does not point to an Object or Array")),
196 }
197 }
198 let last_part = parts
199 .last()
200 .ok_or_else(|| JsonValueExtError::custom("Last element not found"))?;
201 match current {
202 Value::Object(map) => {
203 let removed = map
204 .remove(*last_part)
205 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?;
206 let value: T = serde_json::from_value(removed)?;
207 Ok(value)
208 }
209 Value::Array(arr) => {
210 let index: usize = last_part
211 .parse()
212 .map_err(|_| JsonValueExtError::custom("Invalid array index in pointer"))?;
213 if index < arr.len() {
214 let removed = arr.remove(index);
215 let value: T = serde_json::from_value(removed)?;
216 Ok(value)
217 } else {
218 Err(JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))
219 }
220 }
221 _ => Err(JsonValueExtError::custom("Path does not point to an Object or Array")),
222 }
223 }
224 }
225
226 fn x_insert<T: Serialize>(&mut self, name_or_pointer: &str, value: T) -> Result<()> {
227 let new_value = serde_json::to_value(value)?;
228
229 if !name_or_pointer.starts_with('/') {
230 match self {
231 Value::Object(map) => {
232 map.insert(name_or_pointer.to_string(), new_value);
233 Ok(())
234 }
235 _ => Err(JsonValueExtError::custom("Value is not an Object; cannot x_insert")),
236 }
237 } else {
238 let parts: Vec<&str> = name_or_pointer.split('/').skip(1).collect();
239 let mut current = self;
240
241 for &part in &parts[..parts.len() - 1] {
243 match current {
244 Value::Object(map) => {
245 current = map.entry(part).or_insert_with(|| json!({}));
246 }
247 _ => return Err(JsonValueExtError::custom("Path does not point to an Object")),
248 }
249 }
250
251 if let Some(&last_part) = parts.last() {
253 match current {
254 Value::Object(map) => {
255 map.insert(last_part.to_string(), new_value);
256 Ok(())
257 }
258 _ => Err(JsonValueExtError::custom("Path does not point to an Object")),
259 }
260 } else {
261 Err(JsonValueExtError::custom("Invalid path"))
262 }
263 }
264 }
265
266 fn x_pretty(&self) -> Result<String> {
267 let content = serde_json::to_string_pretty(self)?;
268 Ok(content)
269 }
270
271 fn x_walk<F>(&mut self, mut callback: F) -> bool
280 where
281 F: FnMut(&mut Map<String, Value>, &str) -> bool,
282 {
283 let mut queue = VecDeque::new();
284 queue.push_back(self);
285
286 while let Some(current) = queue.pop_front() {
287 if let Value::Object(map) = current {
288 for key in map.keys().cloned().collect::<Vec<_>>() {
290 let res = callback(map, &key);
291 if !res {
292 return false;
293 }
294 }
295
296 for value in map.values_mut() {
298 if value.is_object() || value.is_array() {
299 queue.push_back(value);
300 }
301 }
302 } else if let Value::Array(arr) = current {
303 for value in arr.iter_mut() {
305 if value.is_object() || value.is_array() {
306 queue.push_back(value);
307 }
308 }
309 }
310 }
311 true
312 }
313}
314
315type Result<T> = core::result::Result<T, JsonValueExtError>;
317
318#[derive(Debug, derive_more::From)]
319pub enum JsonValueExtError {
320 Custom(String),
321
322 PropertyNotFound(String),
323
324 PropertyValueNotOfType {
325 name: String,
326 not_of_type: &'static str,
327 },
328
329 ValueNotOfType(&'static str),
331
332 #[from]
333 SerdeJson(serde_json::Error),
334}
335
336impl JsonValueExtError {
337 pub(crate) fn custom(val: impl std::fmt::Display) -> Self {
338 Self::Custom(val.to_string())
339 }
340}
341
342impl core::fmt::Display for JsonValueExtError {
345 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
346 write!(fmt, "{self:?}")
347 }
348}
349
350impl std::error::Error for JsonValueExtError {}
351
352