value_ext/json/
json_value_ext.rs1use crate::AsType;
2use serde::Serialize;
3use serde::de::DeserializeOwned;
4use serde_json::{Map, Value, json};
5use std::collections::VecDeque;
6
7pub trait JsonValueExt {
34 fn x_new_object() -> Value;
35
36 fn x_contains<T: DeserializeOwned>(&self, name_or_pointer: &str) -> bool;
37
38 fn x_get<T: DeserializeOwned>(&self, name_or_pointer: &str) -> Result<T>;
42
43 fn x_get_as<'a, T: AsType<'a>>(&'a self, name_or_pointer: &str) -> Result<T>;
47
48 fn x_get_str(&self, name_or_pointer: &str) -> Result<&str> {
50 self.x_get_as(name_or_pointer)
51 }
52
53 fn x_get_i64(&self, name_or_pointer: &str) -> Result<i64> {
55 self.x_get_as(name_or_pointer)
56 }
57
58 fn x_get_f64(&self, name_or_pointer: &str) -> Result<f64> {
60 self.x_get_as(name_or_pointer)
61 }
62
63 fn x_get_bool(&self, name_or_pointer: &str) -> Result<bool> {
65 self.x_get_as(name_or_pointer)
66 }
67
68 fn x_get_strs(&self, name_or_pointer: &str) -> Result<Vec<&str>> {
70 self.x_get_as(name_or_pointer)
71 }
72
73 fn x_get_i64s(&self, name_or_pointer: &str) -> Result<Vec<i64>> {
75 self.x_get_as(name_or_pointer)
76 }
77
78 fn x_get_f64s(&self, name_or_pointer: &str) -> Result<Vec<f64>> {
80 self.x_get_as(name_or_pointer)
81 }
82
83 fn x_get_bools(&self, name_or_pointer: &str) -> Result<Vec<bool>> {
85 self.x_get_as(name_or_pointer)
86 }
87
88 fn x_get_object(&self, name_or_pointer: &str) -> Result<&serde_json::Map<String, Value>>;
91
92 fn x_take<T: DeserializeOwned>(&mut self, name_or_pointer: &str) -> Result<T>;
95
96 fn x_remove<T: DeserializeOwned>(&mut self, name_or_pointer: &str) -> Result<T>;
99
100 fn x_insert<T: Serialize>(&mut self, name_or_pointer: &str, value: T) -> Result<()>;
104
105 fn x_merge(&mut self, other: Value) -> Result<()>;
110
111 fn x_walk<F>(&mut self, callback: F) -> bool
119 where
120 F: FnMut(&mut Map<String, Value>, &str) -> bool;
121
122 fn x_pretty(&self) -> Result<String>;
124}
125
126impl JsonValueExt for Value {
127 fn x_new_object() -> Value {
128 Value::Object(Map::new())
129 }
130
131 fn x_contains<T: DeserializeOwned>(&self, name_or_pointer: &str) -> bool {
132 if name_or_pointer.starts_with('/') {
133 self.pointer(name_or_pointer).is_some()
134 } else {
135 self.get(name_or_pointer).is_some()
136 }
137 }
138
139 fn x_get<T: DeserializeOwned>(&self, name_or_pointer: &str) -> Result<T> {
140 let value = if name_or_pointer.starts_with('/') {
141 self.pointer(name_or_pointer)
142 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
143 } else {
144 self.get(name_or_pointer)
145 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
146 };
147
148 let value: T =
149 serde_json::from_value(value.clone())
150 .map_err(JsonValueExtError::from)
151 .map_err(|err| match err {
152 JsonValueExtError::ValueNotOfType(not_of_type) => JsonValueExtError::PropertyValueNotOfType {
153 name: name_or_pointer.to_string(),
154 not_of_type,
155 },
156 other => other,
157 })?;
158
159 Ok(value)
160 }
161
162 fn x_get_object(&self, name_or_pointer: &str) -> Result<&serde_json::Map<String, Value>> {
163 let value = if name_or_pointer.starts_with('/') {
164 self.pointer(name_or_pointer)
165 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
166 } else {
167 self.get(name_or_pointer)
168 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
169 };
170
171 value.as_object().ok_or_else(|| JsonValueExtError::PropertyValueNotOfType {
172 name: name_or_pointer.to_string(),
173 not_of_type: "Object",
174 })
175 }
176
177 fn x_get_as<'a, T: AsType<'a>>(&'a self, name_or_pointer: &str) -> Result<T> {
178 let value = if name_or_pointer.starts_with('/') {
179 self.pointer(name_or_pointer)
180 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
181 } else {
182 self.get(name_or_pointer)
183 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
184 };
185
186 T::from_value(value).map_err(|err| match err {
187 JsonValueExtError::ValueNotOfType(not_of_type) => JsonValueExtError::PropertyValueNotOfType {
188 name: name_or_pointer.to_string(),
189 not_of_type,
190 },
191 other => other,
192 })
193 }
194
195 fn x_take<T: DeserializeOwned>(&mut self, name_or_pointer: &str) -> Result<T> {
196 let value = if name_or_pointer.starts_with('/') {
197 self.pointer_mut(name_or_pointer)
198 .map(Value::take)
199 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
200 } else {
201 self.get_mut(name_or_pointer)
202 .map(Value::take)
203 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
204 };
205
206 let value: T = serde_json::from_value(value)?;
207 Ok(value)
208 }
209
210 fn x_remove<T: DeserializeOwned>(&mut self, name_or_pointer: &str) -> Result<T> {
211 if !name_or_pointer.starts_with('/') {
212 match self {
213 Value::Object(map) => {
214 let removed = map
215 .remove(name_or_pointer)
216 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?;
217 let value: T = serde_json::from_value(removed)?;
218 Ok(value)
219 }
220 _ => Err(JsonValueExtError::custom("Value is not an Object; cannot x_remove")),
221 }
222 } else {
223 let parts: Vec<&str> = name_or_pointer.split('/').skip(1).collect();
224 if parts.is_empty() {
225 return Err(JsonValueExtError::custom("Invalid path"));
226 }
227 let mut current = self;
228 for &part in &parts[..parts.len() - 1] {
229 match current {
230 Value::Object(map) => {
231 current = map
232 .get_mut(part)
233 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?;
234 }
235 Value::Array(arr) => {
236 let index: usize = part
237 .parse()
238 .map_err(|_| JsonValueExtError::custom("Invalid array index in pointer"))?;
239 if index < arr.len() {
240 current = &mut arr[index];
241 } else {
242 return Err(JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()));
243 }
244 }
245 _ => return Err(JsonValueExtError::custom("Path does not point to an Object or Array")),
246 }
247 }
248 let last_part = parts
249 .last()
250 .ok_or_else(|| JsonValueExtError::custom("Last element not found"))?;
251 match current {
252 Value::Object(map) => {
253 let removed = map
254 .remove(*last_part)
255 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?;
256 let value: T = serde_json::from_value(removed)?;
257 Ok(value)
258 }
259 Value::Array(arr) => {
260 let index: usize = last_part
261 .parse()
262 .map_err(|_| JsonValueExtError::custom("Invalid array index in pointer"))?;
263 if index < arr.len() {
264 let removed = arr.remove(index);
265 let value: T = serde_json::from_value(removed)?;
266 Ok(value)
267 } else {
268 Err(JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))
269 }
270 }
271 _ => Err(JsonValueExtError::custom("Path does not point to an Object or Array")),
272 }
273 }
274 }
275
276 fn x_insert<T: Serialize>(&mut self, name_or_pointer: &str, value: T) -> Result<()> {
277 let new_value = serde_json::to_value(value)?;
278
279 if !name_or_pointer.starts_with('/') {
280 match self {
281 Value::Object(map) => {
282 map.insert(name_or_pointer.to_string(), new_value);
283 Ok(())
284 }
285 _ => Err(JsonValueExtError::custom("Value is not an Object; cannot x_insert")),
286 }
287 } else {
288 let parts: Vec<&str> = name_or_pointer.split('/').skip(1).collect();
289 let mut current = self;
290
291 for &part in &parts[..parts.len() - 1] {
293 match current {
294 Value::Object(map) => {
295 current = map.entry(part).or_insert_with(|| json!({}));
296 }
297 _ => return Err(JsonValueExtError::custom("Path does not point to an Object")),
298 }
299 }
300
301 if let Some(&last_part) = parts.last() {
303 match current {
304 Value::Object(map) => {
305 map.insert(last_part.to_string(), new_value);
306 Ok(())
307 }
308 _ => Err(JsonValueExtError::custom("Path does not point to an Object")),
309 }
310 } else {
311 Err(JsonValueExtError::custom("Invalid path"))
312 }
313 }
314 }
315
316 fn x_merge(&mut self, other: Value) -> Result<()> {
317 if other.is_null() {
318 return Ok(());
319 }
320
321 let other_map = match other {
322 Value::Object(map) => map,
323 _ => {
324 return Err(JsonValueExtError::custom(
325 "Other value is not an Object; cannot x_merge",
326 ));
327 }
328 };
329
330 match self {
331 Value::Object(map) => {
332 map.extend(other_map);
333 Ok(())
334 }
335 _ => Err(JsonValueExtError::custom("Value is not an Object; cannot x_merge")),
336 }
337 }
338
339 fn x_pretty(&self) -> Result<String> {
340 let content = serde_json::to_string_pretty(self)?;
341 Ok(content)
342 }
343
344 fn x_walk<F>(&mut self, mut callback: F) -> bool
353 where
354 F: FnMut(&mut Map<String, Value>, &str) -> bool,
355 {
356 let mut queue = VecDeque::new();
357 queue.push_back(self);
358
359 while let Some(current) = queue.pop_front() {
360 if let Value::Object(map) = current {
361 for key in map.keys().cloned().collect::<Vec<_>>() {
363 let res = callback(map, &key);
364 if !res {
365 return false;
366 }
367 }
368
369 for value in map.values_mut() {
371 if value.is_object() || value.is_array() {
372 queue.push_back(value);
373 }
374 }
375 } else if let Value::Array(arr) = current {
376 for value in arr.iter_mut() {
378 if value.is_object() || value.is_array() {
379 queue.push_back(value);
380 }
381 }
382 }
383 }
384 true
385 }
386}
387
388type Result<T> = core::result::Result<T, JsonValueExtError>;
390
391#[derive(Debug, derive_more::From)]
392pub enum JsonValueExtError {
393 Custom(String),
394
395 PropertyNotFound(String),
396
397 PropertyValueNotOfType {
398 name: String,
399 not_of_type: &'static str,
400 },
401
402 ValueNotOfType(&'static str),
404
405 #[from]
406 SerdeJson(serde_json::Error),
407}
408
409impl JsonValueExtError {
410 pub(crate) fn custom(val: impl std::fmt::Display) -> Self {
411 Self::Custom(val.to_string())
412 }
413}
414
415impl core::fmt::Display for JsonValueExtError {
418 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
419 write!(fmt, "{self:?}")
420 }
421}
422
423impl std::error::Error for JsonValueExtError {}
424
425