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_merge(&mut self, other: Value) -> Result<()>;
81
82 fn x_walk<F>(&mut self, callback: F) -> bool
90 where
91 F: FnMut(&mut Map<String, Value>, &str) -> bool;
92
93 fn x_pretty(&self) -> Result<String>;
95}
96
97impl JsonValueExt for Value {
98 fn x_new_object() -> Value {
99 Value::Object(Map::new())
100 }
101
102 fn x_contains<T: DeserializeOwned>(&self, name_or_pointer: &str) -> bool {
103 if name_or_pointer.starts_with('/') {
104 self.pointer(name_or_pointer).is_some()
105 } else {
106 self.get(name_or_pointer).is_some()
107 }
108 }
109
110 fn x_get<T: DeserializeOwned>(&self, name_or_pointer: &str) -> Result<T> {
111 let value = if name_or_pointer.starts_with('/') {
112 self.pointer(name_or_pointer)
113 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
114 } else {
115 self.get(name_or_pointer)
116 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
117 };
118
119 let value: T =
120 serde_json::from_value(value.clone())
121 .map_err(JsonValueExtError::from)
122 .map_err(|err| match err {
123 JsonValueExtError::ValueNotOfType(not_of_type) => JsonValueExtError::PropertyValueNotOfType {
124 name: name_or_pointer.to_string(),
125 not_of_type,
126 },
127 other => other,
128 })?;
129
130 Ok(value)
131 }
132
133 fn x_get_as<'a, T: AsType<'a>>(&'a self, name_or_pointer: &str) -> Result<T> {
134 let value = if name_or_pointer.starts_with('/') {
135 self.pointer(name_or_pointer)
136 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
137 } else {
138 self.get(name_or_pointer)
139 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
140 };
141
142 T::from_value(value).map_err(|err| match err {
143 JsonValueExtError::ValueNotOfType(not_of_type) => JsonValueExtError::PropertyValueNotOfType {
144 name: name_or_pointer.to_string(),
145 not_of_type,
146 },
147 other => other,
148 })
149 }
150
151 fn x_take<T: DeserializeOwned>(&mut self, name_or_pointer: &str) -> Result<T> {
152 let value = if name_or_pointer.starts_with('/') {
153 self.pointer_mut(name_or_pointer)
154 .map(Value::take)
155 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
156 } else {
157 self.get_mut(name_or_pointer)
158 .map(Value::take)
159 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?
160 };
161
162 let value: T = serde_json::from_value(value)?;
163 Ok(value)
164 }
165
166 fn x_remove<T: DeserializeOwned>(&mut self, name_or_pointer: &str) -> Result<T> {
167 if !name_or_pointer.starts_with('/') {
168 match self {
169 Value::Object(map) => {
170 let removed = map
171 .remove(name_or_pointer)
172 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?;
173 let value: T = serde_json::from_value(removed)?;
174 Ok(value)
175 }
176 _ => Err(JsonValueExtError::custom("Value is not an Object; cannot x_remove")),
177 }
178 } else {
179 let parts: Vec<&str> = name_or_pointer.split('/').skip(1).collect();
180 if parts.is_empty() {
181 return Err(JsonValueExtError::custom("Invalid path"));
182 }
183 let mut current = self;
184 for &part in &parts[..parts.len() - 1] {
185 match current {
186 Value::Object(map) => {
187 current = map
188 .get_mut(part)
189 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?;
190 }
191 Value::Array(arr) => {
192 let index: usize = part
193 .parse()
194 .map_err(|_| JsonValueExtError::custom("Invalid array index in pointer"))?;
195 if index < arr.len() {
196 current = &mut arr[index];
197 } else {
198 return Err(JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()));
199 }
200 }
201 _ => return Err(JsonValueExtError::custom("Path does not point to an Object or Array")),
202 }
203 }
204 let last_part = parts
205 .last()
206 .ok_or_else(|| JsonValueExtError::custom("Last element not found"))?;
207 match current {
208 Value::Object(map) => {
209 let removed = map
210 .remove(*last_part)
211 .ok_or_else(|| JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))?;
212 let value: T = serde_json::from_value(removed)?;
213 Ok(value)
214 }
215 Value::Array(arr) => {
216 let index: usize = last_part
217 .parse()
218 .map_err(|_| JsonValueExtError::custom("Invalid array index in pointer"))?;
219 if index < arr.len() {
220 let removed = arr.remove(index);
221 let value: T = serde_json::from_value(removed)?;
222 Ok(value)
223 } else {
224 Err(JsonValueExtError::PropertyNotFound(name_or_pointer.to_string()))
225 }
226 }
227 _ => Err(JsonValueExtError::custom("Path does not point to an Object or Array")),
228 }
229 }
230 }
231
232 fn x_insert<T: Serialize>(&mut self, name_or_pointer: &str, value: T) -> Result<()> {
233 let new_value = serde_json::to_value(value)?;
234
235 if !name_or_pointer.starts_with('/') {
236 match self {
237 Value::Object(map) => {
238 map.insert(name_or_pointer.to_string(), new_value);
239 Ok(())
240 }
241 _ => Err(JsonValueExtError::custom("Value is not an Object; cannot x_insert")),
242 }
243 } else {
244 let parts: Vec<&str> = name_or_pointer.split('/').skip(1).collect();
245 let mut current = self;
246
247 for &part in &parts[..parts.len() - 1] {
249 match current {
250 Value::Object(map) => {
251 current = map.entry(part).or_insert_with(|| json!({}));
252 }
253 _ => return Err(JsonValueExtError::custom("Path does not point to an Object")),
254 }
255 }
256
257 if let Some(&last_part) = parts.last() {
259 match current {
260 Value::Object(map) => {
261 map.insert(last_part.to_string(), new_value);
262 Ok(())
263 }
264 _ => Err(JsonValueExtError::custom("Path does not point to an Object")),
265 }
266 } else {
267 Err(JsonValueExtError::custom("Invalid path"))
268 }
269 }
270 }
271
272 fn x_merge(&mut self, other: Value) -> Result<()> {
273 if other.is_null() {
274 return Ok(());
275 }
276
277 let other_map = match other {
278 Value::Object(map) => map,
279 _ => return Err(JsonValueExtError::custom("Other value is not an Object; cannot x_merge")),
280 };
281
282 match self {
283 Value::Object(map) => {
284 map.extend(other_map);
285 Ok(())
286 }
287 _ => Err(JsonValueExtError::custom("Value is not an Object; cannot x_merge")),
288 }
289 }
290
291 fn x_pretty(&self) -> Result<String> {
292 let content = serde_json::to_string_pretty(self)?;
293 Ok(content)
294 }
295
296 fn x_walk<F>(&mut self, mut callback: F) -> bool
305 where
306 F: FnMut(&mut Map<String, Value>, &str) -> bool,
307 {
308 let mut queue = VecDeque::new();
309 queue.push_back(self);
310
311 while let Some(current) = queue.pop_front() {
312 if let Value::Object(map) = current {
313 for key in map.keys().cloned().collect::<Vec<_>>() {
315 let res = callback(map, &key);
316 if !res {
317 return false;
318 }
319 }
320
321 for value in map.values_mut() {
323 if value.is_object() || value.is_array() {
324 queue.push_back(value);
325 }
326 }
327 } else if let Value::Array(arr) = current {
328 for value in arr.iter_mut() {
330 if value.is_object() || value.is_array() {
331 queue.push_back(value);
332 }
333 }
334 }
335 }
336 true
337 }
338}
339
340type Result<T> = core::result::Result<T, JsonValueExtError>;
342
343#[derive(Debug, derive_more::From)]
344pub enum JsonValueExtError {
345 Custom(String),
346
347 PropertyNotFound(String),
348
349 PropertyValueNotOfType {
350 name: String,
351 not_of_type: &'static str,
352 },
353
354 ValueNotOfType(&'static str),
356
357 #[from]
358 SerdeJson(serde_json::Error),
359}
360
361impl JsonValueExtError {
362 pub(crate) fn custom(val: impl std::fmt::Display) -> Self {
363 Self::Custom(val.to_string())
364 }
365}
366
367impl core::fmt::Display for JsonValueExtError {
370 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
371 write!(fmt, "{self:?}")
372 }
373}
374
375impl std::error::Error for JsonValueExtError {}
376
377