identity_diff/
object.rs

1// Copyright 2020-2022 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use serde_json::Value;
5use std::collections::BTreeMap;
6use std::collections::HashMap;
7
8use crate::error::Result;
9use crate::hashmap::DiffHashMap;
10use crate::traits::Diff;
11
12pub type DiffObject = DiffHashMap<String, Value>;
13
14type ObjectSrc = BTreeMap<String, Value>;
15type ObjectDst = HashMap<String, Value>;
16
17impl Diff for ObjectSrc {
18  type Type = DiffObject;
19
20  fn diff(&self, other: &Self) -> Result<Self::Type> {
21    let a: ObjectDst = self.clone().into_iter().collect();
22    let b: ObjectDst = other.clone().into_iter().collect();
23
24    a.diff(&b)
25  }
26
27  fn merge(&self, diff: Self::Type) -> Result<Self> {
28    let this: ObjectDst = self.clone().into_iter().collect();
29    let this: ObjectDst = this.merge(diff)?;
30
31    Ok(this.into_iter().collect())
32  }
33
34  fn from_diff(diff: Self::Type) -> Result<Self> {
35    Ok(ObjectDst::from_diff(diff)?.into_iter().collect())
36  }
37
38  fn into_diff(self) -> Result<Self::Type> {
39    self.into_iter().collect::<ObjectDst>().into_diff()
40  }
41}
42
43#[cfg(test)]
44mod tests {
45  use super::*;
46  use crate::hashmap::InnerValue;
47  use serde_json::json;
48
49  #[test]
50  fn test_diff_empty() {
51    // Ensure diff is none.
52    let a: ObjectSrc = ObjectSrc::default();
53    let b: ObjectSrc = ObjectSrc::default();
54    let diff: DiffObject = Diff::diff(&a, &b).unwrap();
55    assert!(diff.0.is_none());
56    let merge: ObjectSrc = a.merge(diff.clone()).unwrap();
57    assert_eq!(merge, a);
58
59    // Test serde round-trip.
60    let serialized: String = serde_json::to_string(&diff).unwrap();
61    let deserialized: DiffObject = serde_json::from_str(&serialized).unwrap();
62    assert_eq!(diff, deserialized)
63  }
64
65  #[test]
66  fn test_diff() {
67    let mut a: ObjectSrc = ObjectSrc::new();
68    a.insert("foo".into(), 12.into());
69    a.insert("bar".into(), 34.into());
70    a.insert("baz".into(), 56.into());
71    a.insert("qux".into(), 78.into());
72
73    let mut b: ObjectSrc = ObjectSrc::new();
74    b.insert("foo".into(), 56.into());
75    b.insert("thud".into(), 9.into());
76    b.insert("bar".into(), 34.into());
77    b.insert("qux".into(), 78.into());
78
79    let diff: DiffObject = Diff::diff(&a, &b).unwrap();
80    let expected: DiffObject = DiffHashMap(Some(vec![
81      InnerValue::Change {
82        key: "foo".into(),
83        value: json!(56).into_diff().unwrap(),
84      },
85      InnerValue::Add {
86        key: "thud".into(),
87        value: json!(9).into_diff().unwrap(),
88      },
89      InnerValue::Remove { key: "baz".into() },
90    ]));
91    assert_eq!(expected, diff);
92
93    let merge: ObjectSrc = a.merge(diff.clone()).unwrap();
94    assert_eq!(merge, b);
95
96    // Test serde round-trip.
97    let serialized: String = serde_json::to_string(&diff).unwrap();
98    let deserialized: DiffObject = serde_json::from_str(&serialized).unwrap();
99    assert_eq!(diff, deserialized)
100  }
101}