1use std::{cell::Cell, mem::take};
2
3use compact_str::{CompactString, ToCompactString};
4use serde::{ser::SerializeMap, Deserialize, Serialize};
5
6#[cfg(not(feature = "indexmap"))]
7type Map<T, V> = std::collections::BTreeMap<T, V>;
8
9#[cfg(feature = "indexmap")]
10type Map<T, V> = indexmap::IndexMap<T, V>;
11
12pub enum CategoryRule<'a> {
24 Prefix(&'a str),
26
27 Suffix(&'a str),
29
30 Wrap(&'a str, &'a str),
32}
33
34thread_local! {
35 static CATEGORY_RULE: Cell<CategoryRule<'static>> = Cell::new(Default::default());
36}
37
38pub fn with_category_rule(rule: CategoryRule, f: impl FnOnce() + std::panic::UnwindSafe) {
62 CATEGORY_RULE.with(|x| unsafe {
63 x.replace(std::mem::transmute(rule));
66
67 let err = std::panic::catch_unwind(|| {
68 f();
69 });
70
71 x.replace(Default::default());
72
73 err.unwrap();
75 })
76}
77
78impl<'a> Default for CategoryRule<'a> {
79 fn default() -> Self {
80 Self::Prefix("~")
81 }
82}
83
84impl<'a> CategoryRule<'a> {
85 pub fn is_category(&self, key: &str) -> bool {
86 match self {
87 Self::Prefix(prefix) => key.starts_with(prefix),
88 Self::Suffix(suffix) => key.ends_with(suffix),
89 Self::Wrap(prefix, suffix) => key.starts_with(prefix) && key.ends_with(suffix),
90 }
91 }
92
93 pub fn make_category(&self, key: &str, out_key: &mut CompactString) {
94 out_key.clear();
95
96 match self {
97 CategoryRule::Prefix(tok) => {
98 out_key.push_str(tok);
99 out_key.push_str(key);
100 }
101
102 CategoryRule::Suffix(tok) => {
103 out_key.push_str(key);
104 out_key.push_str(tok);
105 }
106
107 CategoryRule::Wrap(pre, suf) => {
108 out_key.push_str(pre);
109 out_key.push_str(key);
110 out_key.push_str(suf);
111 }
112 }
113 }
114}
115
116#[derive(Default, Clone, Debug, PartialEq)]
133pub struct Archive {
134 pub(crate) paths: Map<CompactString, Archive>,
136
137 pub(crate) values: Map<CompactString, serde_json::Value>,
139}
140
141impl Archive {
142 pub fn iter_values(&self) -> impl Iterator<Item = (&str, &serde_json::Value)> {
143 self.values.iter().map(|(k, v)| (k.as_str(), v))
144 }
145
146 pub fn iter_paths(&self) -> impl Iterator<Item = (&str, &Archive)> {
147 self.paths.iter().map(|(k, v)| (k.as_str(), v))
148 }
149
150 pub fn iter_paths_mut(&mut self) -> impl Iterator<Item = (&str, &mut Archive)> {
151 self.paths.iter_mut().map(|(k, v)| (k.as_str(), v))
152 }
153
154 pub fn iter_values_mut(&mut self) -> impl Iterator<Item = (&str, &mut serde_json::Value)> {
155 self.values.iter_mut().map(|(k, v)| (k.as_str(), v))
156 }
157
158 pub fn get_value(&self, key: &str) -> Option<&serde_json::Value> {
159 self.values.get(key)
160 }
161
162 pub fn get_value_mut(&mut self, key: &str) -> Option<&mut serde_json::Value> {
163 self.values.get_mut(key)
164 }
165
166 pub fn get_path(&self, key: &str) -> Option<&Archive> {
167 self.paths.get(key)
168 }
169
170 pub fn get_path_mut(&mut self, key: &str) -> Option<&mut Archive> {
171 self.paths.get_mut(key)
172 }
173
174 pub fn insert_value(&mut self, key: impl ToCompactString, value: serde_json::Value) {
175 self.values.insert(key.to_compact_string(), value);
176 }
177
178 pub fn insert_path(&mut self, key: impl ToCompactString, value: Archive) {
179 self.paths.insert(key.to_compact_string(), value);
180 }
181
182 pub fn remove_value(&mut self, key: &str) -> Option<serde_json::Value> {
183 self.values.remove(key)
184 }
185
186 pub fn remove_path(&mut self, key: &str) -> Option<Archive> {
187 self.paths.remove(key)
188 }
189
190 pub fn clear_values(&mut self) {
191 self.values.clear();
192 }
193
194 pub fn clear_paths(&mut self) {
195 self.paths.clear();
196 }
197
198 pub fn is_empty_values(&self) -> bool {
199 self.values.is_empty()
200 }
201
202 pub fn is_empty_paths(&self) -> bool {
203 self.paths.is_empty()
204 }
205
206 pub fn len_values(&self) -> usize {
207 self.values.len()
208 }
209
210 pub fn len_paths(&self) -> usize {
211 self.paths.len()
212 }
213}
214
215impl Archive {
216 pub fn find_path<'s, 'a, T: AsRef<str> + 'a>(
228 &'s self,
229 path: impl IntoIterator<Item = T>,
230 ) -> Option<&'s Archive> {
231 let iter = path.into_iter();
232 let mut paths = &self.paths;
233 let mut node = None;
234
235 for key in iter {
236 if let Some(next_node) = paths.get(key.as_ref()) {
237 node = Some(next_node);
238 paths = &next_node.paths;
239 } else {
240 return None;
241 }
242 }
243
244 node
245 }
246
247 pub fn find_or_create_path_mut<'s, 'a>(
258 &'s mut self,
259 path: impl IntoIterator<Item = &'a str>,
260 ) -> &'s mut Archive {
261 path.into_iter().fold(self, |node, key| node.paths.entry(key.into()).or_default())
262 }
263
264 pub fn create_patch(&self, newer: &mut Self) -> Self {
276 let mut patch = Self::default();
277
278 newer.paths.retain(|k, v| {
279 if let Some(base_v) = self.paths.get(k) {
280 let patch_v = base_v.create_patch(v);
281 if !patch_v.is_empty() {
282 patch.paths.insert(k.clone(), patch_v);
283 !v.is_empty()
284 } else {
285 true
286 }
287 } else {
288 patch.paths.insert(k.clone(), take(v));
289 false
290 }
291 });
292
293 newer.values.retain(|k, v| {
294 if let Some(base_v) = self.values.get(k) {
295 if *base_v != *v {
296 patch.values.insert(k.clone(), take(v));
297 false
298 } else {
299 true
300 }
301 } else {
302 patch.values.insert(k.clone(), take(v));
303 false
304 }
305 });
306
307 patch
308 }
309
310 pub fn is_empty(&self) -> bool {
317 self.paths.is_empty() && self.values.is_empty()
318 }
319
320 pub fn merge_from(&mut self, other: Self) {
329 for (k, v) in other.paths {
331 self.paths.entry(k).or_default().merge_from(v);
332 }
333
334 for (k, v) in other.values {
336 self.values.insert(k, v);
337 }
338 }
339
340 #[must_use]
352 pub fn merge(mut self, other: Self) -> Self {
353 self.merge_from(other);
354 self
355 }
356}
357
358impl<'a> Deserialize<'a> for Archive {
359 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
360 where
361 D: serde::Deserializer<'a>,
362 {
363 struct PathNodeVisit {
364 build: Archive,
365 }
366
367 impl<'de> serde::de::Visitor<'de> for PathNodeVisit {
368 type Value = Archive;
369
370 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
371 formatter.write_str("Object consist of Tilde(~) prefixed objects or ")
372 }
373
374 fn visit_map<A>(mut self, mut map: A) -> Result<Self::Value, A::Error>
375 where
376 A: serde::de::MapAccess<'de>,
377 {
378 CATEGORY_RULE.with(|rule| {
379 let rule = rule.take();
380
381 while let Some(mut key) = map.next_key::<CompactString>()? {
382 if !key.is_empty() && rule.is_category(&key) {
383 key.remove(0); let child: Archive = map.next_value()?;
386 self.build.paths.insert(key, child);
387 } else {
388 let value: serde_json::Value = map.next_value()?;
389 self.build.values.insert(key, value);
390 }
391 }
392
393 Ok(self.build)
394 })
395 }
396 }
397
398 deserializer.deserialize_map(PathNodeVisit { build: Default::default() })
399 }
400}
401
402impl Serialize for Archive {
403 fn serialize<S>(&self, se: S) -> Result<S::Ok, S::Error>
404 where
405 S: serde::Serializer,
406 {
407 let mut map = se.serialize_map(Some(self.paths.len() + self.values.len()))?;
408
409 CATEGORY_RULE.with(|rule| {
410 let rule = rule.take();
411 let mut key_b = CompactString::default();
412
413 for (k, v) in &self.paths {
414 rule.make_category(k, &mut key_b);
415 map.serialize_entry(&key_b, v)?;
416 }
417
418 Ok(())
419 })?;
420
421 for (k, v) in &self.values {
422 debug_assert!(
423 !k.starts_with('~'),
424 "Tilde prefixed key '{k}' for field is not allowed!"
425 );
426
427 map.serialize_entry(k, v)?;
428 }
429
430 map.end()
431 }
432}
433
434#[test]
435#[allow(clippy::approx_constant)]
436fn test_archive_basic() {
437 let src = r#"
438 {
439 "~root_path_1": {
440 "~subpath1": {
441 "value1": null,
442 "value2": {},
443 "~sub-subpath": {}
444 },
445 "~subpath2": {}
446 },
447 "~root_path_2": {
448 "value1": null,
449 "value2": 31.4,
450 "value3": "hoho-haha",
451 "value-obj": {
452 "~pathlike": 3.141
453 }
454 }
455 }
456 "#;
457
458 let arch: Archive = serde_json::from_str(src).unwrap();
459 assert!(arch.paths.len() == 2);
460
461 let p1 = arch.paths.get("root_path_1").unwrap();
462 assert!(p1.paths.len() == 2);
463 assert!(p1.values.is_empty());
464
465 let sp1 = p1.paths.get("subpath1").unwrap();
466 assert!(sp1.paths.contains_key("sub-subpath"));
467 assert!(sp1.values.len() == 2);
468 assert!(sp1.values.contains_key("value1"));
469 assert!(sp1.values.contains_key("value2"));
470 assert!(sp1.values.get("value1").unwrap().is_null());
471 assert!(sp1.values.get("value2").unwrap().as_object().unwrap().is_empty());
472
473 let p2 = arch.paths.get("root_path_2").unwrap();
474 assert!(p2.paths.is_empty());
475 assert!(p2.values.len() == 4);
476
477 let newer = r#"
478 {
479 "~root_path_1": {
480 "~subpath1": {
481 "value1": null,
482 "value2": {
483 "hello, world!": 3.141
484 },
485 "~sub-subpath": {}
486 },
487 "~subpath2": {},
488 "~new_path": {
489 "valll": 4.44
490 }
491 },
492 "~root_path_2": {
493 "value1": null,
494 "value2": 31.4,
495 "value3": "hoho-haha",
496 "value-obj": {
497 "~pathlike": 3.141
498 }
499 }
500 }
501 "#;
502 let newer: Archive = serde_json::from_str(newer).unwrap();
503 let mut newer_consume = newer.clone();
504 let patch = Archive::create_patch(&arch, &mut newer_consume);
505
506 let merged = arch.clone().merge(patch.clone());
507 assert_eq!(merged, newer);
508
509 assert!(patch.paths.len() == 1);
510 assert!(patch.paths.contains_key("root_path_1"));
511
512 let val = &patch.find_path(["root_path_1", "subpath1"]).unwrap().values;
513 let val_obj = val.get("value2").unwrap().as_object().unwrap();
514 assert!(val.contains_key("value2"));
515 assert!(val_obj.len() == 1);
516 assert!(val_obj.contains_key("hello, world!"));
517 assert!(val_obj.get("hello, world!") == Some(&serde_json::Value::from(3.141)));
518
519 let val = &patch.find_path(["root_path_1", "new_path"]).unwrap().values;
520 assert!(val.contains_key("valll"));
521 assert!(val.get("valll") == Some(&serde_json::Value::from(4.44)));
522}