1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use serde::Deserialize;
use serde::Serialize;
use std::fmt::Debug;
use std::fmt::Formatter;
use crate::Diff;
#[derive(Clone, PartialEq, Deserialize, Serialize)]
#[serde(untagged, into = "Option<T>", from = "Option<T>")]
pub enum DiffOption<T: Diff> {
Some(<T as Diff>::Type),
None,
}
impl<T> Diff for Option<T>
where
T: Diff + Clone + Debug + PartialEq + Default + for<'de> Deserialize<'de> + Serialize,
{
type Type = DiffOption<T>;
fn diff(&self, other: &Self) -> crate::Result<Self::Type> {
match (self, other) {
(Some(x), Some(y)) => Ok(Self::Type::Some(x.diff(y)?)),
(None, Some(y)) => Ok(Self::Type::Some(y.clone().into_diff()?)),
_ => Ok(Self::Type::None),
}
}
fn merge(&self, diff: Self::Type) -> crate::Result<Self> {
match (self, diff) {
(None, DiffOption::None) => Ok(None),
(Some(_), DiffOption::None) => Ok(None),
(None, DiffOption::Some(ref d)) => Ok(Some(<T>::from_diff(d.clone())?)),
(Some(t), DiffOption::Some(ref d)) => Ok(Some(t.merge(d.clone())?)),
}
}
fn from_diff(diff: Self::Type) -> crate::Result<Self> {
match diff {
Self::Type::None => Ok(None),
Self::Type::Some(diff) => Ok(Some(<T>::from_diff(diff)?)),
}
}
fn into_diff(self) -> crate::Result<Self::Type> {
match self {
Self::None => Ok(DiffOption::None),
Self::Some(t) => Ok(DiffOption::Some(t.into_diff()?)),
}
}
}
impl<T: Diff> std::fmt::Debug for DiffOption<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match &self {
Self::Some(d) => write!(f, "DiffOption::Some({:#?})", d),
Self::None => write!(f, "DiffOption::None"),
}
}
}
impl<T: Diff> Default for DiffOption<T> {
fn default() -> Self {
Self::None
}
}
impl<T> From<DiffOption<T>> for Option<T>
where
T: Diff,
{
fn from(other: DiffOption<T>) -> Self {
match other {
DiffOption::Some(s) => Some(Diff::from_diff(s).expect("Unable to convert from diff")),
DiffOption::None => None,
}
}
}
impl<T> From<Option<T>> for DiffOption<T>
where
T: Diff,
{
fn from(opt: Option<T>) -> Self {
match opt {
Some(s) => DiffOption::Some(s.into_diff().expect("Unable to convert to diff")),
None => DiffOption::None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::string::DiffString;
#[test]
fn test_option_diff() {
let a = Some("A".to_owned());
let b = Some("B".to_owned());
let diff = a.diff(&b).unwrap();
assert_eq!(diff, DiffOption::Some(DiffString(Some("B".to_owned()))));
let c = a.merge(diff).unwrap();
assert_eq!(b, c);
}
}