use std::collections::BTreeMap;
use serde_json::{Map, Value};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Remainder {
unknown: Map<String, Value>,
within: BTreeMap<String, Remainder>,
elements: Vec<Remainder>,
}
impl Remainder {
pub fn between(raw: &Value, understood: &Value) -> Remainder {
let mut remainder = Remainder::default();
match (raw, understood) {
(Value::Object(raw), Value::Object(understood)) => {
for (key, value) in raw {
match understood.get(key) {
None => {
remainder.unknown.insert(key.clone(), value.clone());
}
Some(seen) => {
let nested = Remainder::between(value, seen);
if !nested.is_empty() {
remainder.within.insert(key.clone(), nested);
}
}
}
}
}
(Value::Array(raw), Value::Array(understood)) if raw.len() == understood.len() => {
remainder.elements = raw
.iter()
.zip(understood)
.map(|(value, seen)| Remainder::between(value, seen))
.collect();
}
_ => {}
}
remainder
}
pub fn is_empty(&self) -> bool {
self.unknown.is_empty()
&& self.within.is_empty()
&& self.elements.iter().all(Remainder::is_empty)
}
pub fn restore(&self, into: &mut Value) {
match into {
Value::Object(into) => {
for (key, value) in &self.unknown {
into.entry(key.clone()).or_insert_with(|| value.clone());
}
for (key, nested) in &self.within {
if let Some(existing) = into.get_mut(key) {
nested.restore(existing);
}
}
}
Value::Array(into) => {
for (nested, existing) in self.elements.iter().zip(into.iter_mut()) {
nested.restore(existing);
}
}
_ => {}
}
}
}