identity_diff/
value.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use serde::Deserialize;
5use serde::Serialize;
6use serde_json::Value;
7
8use crate::Diff;
9
10/// The Diff Type for `serde_json::Value`.
11#[derive(Clone, Default, Eq, Serialize, Deserialize, PartialEq, Debug)]
12#[serde(transparent)]
13pub struct DiffValue(#[serde(skip_serializing_if = "Option::is_none")] pub Option<Value>);
14
15/// The Diff implementation for `serde_json::Value`.
16impl Diff for Value {
17  /// The Diff Type for `serde_json::Value`.
18  type Type = DiffValue;
19
20  /// Compares two `serde_json::Value` types; `self`, `diff` and outputs a `DiffValue` type.
21  fn diff(&self, other: &Self) -> crate::Result<Self::Type> {
22    if self == other {
23      Ok(DiffValue(None))
24    } else {
25      other.clone().into_diff()
26    }
27  }
28
29  /// Merges a `DiffValue`; `diff` with `self`; a `serde_json::Value` to create a new `serde_json::Value`.
30  fn merge(&self, diff: Self::Type) -> crate::Result<Self> {
31    if diff.0.is_none() {
32      Ok(self.clone())
33    } else {
34      Self::from_diff(diff)
35    }
36  }
37
38  /// Converts from a `diff` of type `DiffValue` to a `serde_json::Value`.
39  fn from_diff(diff: Self::Type) -> crate::Result<Self> {
40    match diff.0 {
41      Some(s) => Ok(s),
42      None => Err(crate::Error::ConversionError(
43        "Error converting from serde_json::Value".into(),
44      )),
45    }
46  }
47
48  /// converts a `serde_json::Value` to a `DiffValue`.
49  fn into_diff(self) -> crate::Result<Self::Type> {
50    Ok(DiffValue(Some(self)))
51  }
52}
53
54#[cfg(test)]
55mod test {
56  use super::*;
57  use serde_json::json;
58
59  #[test]
60  fn test_json_value() {
61    let v = Value::Null;
62
63    let v2 = Value::Bool(true);
64
65    let diff = v.diff(&v2).unwrap();
66
67    let res = v.merge(diff).unwrap();
68
69    let expected = Value::Bool(true);
70
71    assert_eq!(expected, res);
72
73    let v = json!("A string");
74
75    let v2 = json!("A string");
76
77    let diff = v.diff(&v2).unwrap();
78
79    let res = v.merge(diff).unwrap();
80
81    assert_eq!(res, v2);
82
83    let v3 = json!("Another string");
84
85    let diff = v.diff(&v3).unwrap();
86
87    let res = v.merge(diff).unwrap();
88
89    assert_eq!(v3, res);
90  }
91}