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