1use crate::{CreatedDelta, Diffable, Patchable};
2use serde::de::DeserializeOwned;
3use serde::Serialize;
4use std::fmt::{Debug, Formatter};
5
6impl<'s, 'e, T: Diffable<'s, 'e, T>> Diffable<'s, 'e, Option<T>> for Option<T>
7where
8 T: 'e,
9 <T as Diffable<'s, 'e, T>>::Delta: Serialize,
10 <T as Diffable<'s, 'e, T>>::DeltaOwned: DeserializeOwned,
11{
12 type Delta = OptionDelta<'s, 'e, T>;
13 type DeltaOwned = OptionDeltaOwned<'s, 'e, T>;
14
15 fn create_delta_towards(&'s self, end_state: &'e Option<T>) -> CreatedDelta<Self::Delta> {
16 let diff = match (self, end_state) {
17 (None, None) => OptionDelta::NoChange,
18 (None, Some(new)) => OptionDelta::OuterChange(Some(new)),
19 (Some(_), None) => OptionDelta::OuterChange(None),
20
21 (Some(old), Some(new)) => {
22 let diff = old.create_delta_towards(new);
23
24 if diff.did_change {
25 OptionDelta::InnerChange(diff.delta)
26 } else {
27 OptionDelta::NoChange
28 }
29 }
30 };
31
32 let did_change = match &diff {
33 OptionDelta::NoChange => false,
34 _ => true,
35 };
36
37 CreatedDelta {
38 delta: diff,
39 did_change,
40 }
41 }
42}
43
44impl<'s, 'e, T> Patchable<<Option<T> as Diffable<'s, 'e, Option<T>>>::DeltaOwned> for Option<T>
45where
46 T: 'e,
47 T: Diffable<'s, 'e, T>,
48 T: Patchable<<T as Diffable<'s, 'e, T>>::DeltaOwned>,
49 <T as Diffable<'s, 'e, T>>::Delta: Serialize,
50 <T as Diffable<'s, 'e, T>>::DeltaOwned: DeserializeOwned,
51{
52 fn apply_patch(&mut self, patch: <Option<T> as Diffable<'s, 'e, Option<T>>>::DeltaOwned) {
53 match patch {
54 OptionDeltaOwned::NoChange => {}
55 OptionDeltaOwned::InnerChange(delta) => match self {
56 Some(inner) => inner.apply_patch(delta),
57 _ => panic!("No inner field to change"),
58 },
59 OptionDeltaOwned::OuterChange(outer) => {
60 *self = outer;
61 }
62 }
63 }
64}
65
66#[derive(Serialize)]
67#[allow(missing_docs)]
68pub enum OptionDelta<'s, 'e, T: Diffable<'s, 'e, T>>
69where
70 <T as Diffable<'s, 'e, T>>::Delta: Serialize,
71{
72 NoChange,
73 InnerChange(<T as Diffable<'s, 'e, T>>::Delta),
74 OuterChange(Option<&'e T>),
75}
76
77#[derive(Deserialize)]
78#[allow(missing_docs)]
79pub enum OptionDeltaOwned<'s, 'e, T: Diffable<'s, 'e, T>>
80where
81 <T as Diffable<'s, 'e, T>>::DeltaOwned: DeserializeOwned,
82{
83 NoChange,
84 InnerChange(<T as Diffable<'s, 'e, T>>::DeltaOwned),
85 OuterChange(Option<T>),
86}
87
88impl<'s, 'e, T: Diffable<'s, 'e, T>> Debug for OptionDelta<'s, 'e, T>
90where
91 T: Debug,
92 <T as Diffable<'s, 'e, T>>::Delta: Serialize,
93 <T as Diffable<'s, 'e, T>>::Delta: Debug,
94{
95 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
96 match self {
97 OptionDelta::NoChange => {
98 f.write_str("NoChange")?;
99 }
100 OptionDelta::InnerChange(delta) => {
101 f.debug_tuple("InnerChange").field(delta).finish()?;
102 }
103 OptionDelta::OuterChange(outer) => {
104 f.debug_tuple("Outer").field(outer).finish()?;
105 }
106 };
107
108 Ok(())
109 }
110}
111
112impl<'s, 'e, T: Diffable<'s, 'e, T>> PartialEq for OptionDelta<'s, 'e, T>
114where
115 T: PartialEq,
116 <T as Diffable<'s, 'e, T>>::Delta: Serialize,
117 <T as Diffable<'s, 'e, T>>::Delta: PartialEq,
118{
119 fn eq(&self, other: &Self) -> bool {
120 match (self, other) {
121 (OptionDelta::NoChange, OptionDelta::NoChange) => true,
122 (OptionDelta::InnerChange(left), OptionDelta::InnerChange(right)) => left.eq(right),
123 (OptionDelta::OuterChange(left), OptionDelta::OuterChange(right)) => left.eq(right),
124 _ => false,
125 }
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132 use crate::DipaImplTester;
133
134 #[test]
136 fn dipa_option_impl() {
137 DipaImplTester {
138 label: Some("Option<T>::None no change"),
139 start: &mut Option::<()>::None,
140 end: &None,
141 expected_delta: OptionDelta::NoChange,
142 expected_serialized_patch_size: 1,
143 expected_did_change: false,
144 }
145 .test();
146
147 DipaImplTester {
148 label: Some("Option<T>::Some no change"),
149 start: &mut Some(1u32),
150 end: &Some(1u32),
151 expected_delta: OptionDelta::NoChange,
152 expected_serialized_patch_size: 1,
153 expected_did_change: false,
154 }
155 .test();
156
157 DipaImplTester {
158 label: Some("Option<T>::Some change"),
159 start: &mut Some(1u32),
160 end: &Some(5u32),
161 expected_delta: OptionDelta::InnerChange(Some(5)),
162 expected_serialized_patch_size: 3,
163 expected_did_change: true,
164 }
165 .test();
166
167 DipaImplTester {
168 label: Some("Option<T> Some -> None"),
169 start: &mut Some(1u32),
170 end: &None,
171 expected_delta: OptionDelta::OuterChange(None),
172 expected_serialized_patch_size: 2,
173 expected_did_change: true,
174 }
175 .test();
176
177 DipaImplTester {
178 label: Some("Option<T> None -> Some"),
179 start: &mut None,
180 end: &Some(1u32),
181 expected_delta: OptionDelta::OuterChange(Some(&1u32)),
182 expected_serialized_patch_size: 3,
183 expected_did_change: true,
184 }
185 .test();
186 }
187}