1#[macro_export]
2macro_rules! impl_structured_driver {
3 (
4 driver = $driver:ident,
5 name = $name:literal,
6 extensions = [$($ext:literal),+ $(,)?],
7 value_ty = $value:ty,
8
9 obj_pat = |$obj_map:ident| $obj_arm:pat,
10 arr_pat = |$arr_vec:ident| $arr_arm:pat,
11
12 new_map = $new_map:expr,
13 wrap_map = |$wrap_m:ident| $wrap_map_expr:expr,
14 wrap_arr = |$wrap_v:ident| $wrap_arr_expr:expr,
15
16 key_set = |$ks_map:ident| $ks_expr:expr,
17 map_get = |$mg_map:ident, $mg_key:ident| $mg_expr:expr,
18 map_insert = |$mi_map:ident, $mi_key:ident, $mi_val:ident| $mi_expr:expr,
19
20 val_str = |$vs_val:ident| $vs_expr:expr,
21 child_path = |$cp_parent:ident, $cp_key:ident| $cp_expr:expr,
22
23 parse_val = |$pv_src:ident| $pv_expr:expr,
24 serialize_val = |$sv_val:ident| $sv_expr:expr,
25
26 arrow = $arrow:literal,
27 ) => {
28 #[allow(clippy::collapsible_match)]
29 impl $driver {
30 pub fn new() -> Self {
31 Self
32 }
33
34 fn diff_values(old: &$value, new: &$value, path: &str) -> Vec<SemanticChange> {
35 let mut changes = Vec::new();
36
37 if matches!(old, $obj_arm) && matches!(new, $obj_arm) {
38 let __old_map = match old { $obj_arm => $obj_map, _ => unreachable!() };
39 let __new_map = match new { $obj_arm => $obj_map, _ => unreachable!() };
40
41 let __old_keys: std::collections::HashSet<_> = { let $ks_map = __old_map; $ks_expr };
42 let __new_keys: std::collections::HashSet<_> = { let $ks_map = __new_map; $ks_expr };
43
44 for __k in &__old_keys {
45 if !__new_keys.contains(__k) {
46 let __cp = { let $cp_parent = path; let $cp_key = __k; $cp_expr };
47 let __val = { let $mg_map = __old_map; let $mg_key = __k; $mg_expr }.unwrap();
48 changes.push(SemanticChange::Removed {
49 path: __cp,
50 old_value: { let $vs_val = __val; $vs_expr },
51 });
52 }
53 }
54
55 for __k in &__new_keys {
56 if !__old_keys.contains(__k) {
57 let __cp = { let $cp_parent = path; let $cp_key = __k; $cp_expr };
58 let __val = { let $mg_map = __new_map; let $mg_key = __k; $mg_expr }.unwrap();
59 changes.push(SemanticChange::Added {
60 path: __cp,
61 value: { let $vs_val = __val; $vs_expr },
62 });
63 }
64 }
65
66 for __k in &__old_keys {
67 if __new_keys.contains(__k) {
68 let __cp = { let $cp_parent = path; let $cp_key = __k; $cp_expr };
69 let __old_val = { let $mg_map = __old_map; let $mg_key = __k; $mg_expr }.unwrap();
70 let __new_val = { let $mg_map = __new_map; let $mg_key = __k; $mg_expr }.unwrap();
71 changes.extend(Self::diff_values(__old_val, __new_val, &__cp));
72 }
73 }
74 } else if matches!(old, $arr_arm) && matches!(new, $arr_arm) {
75 let __old_arr = match old { $arr_arm => $arr_vec, _ => unreachable!() };
76 let __new_arr = match new { $arr_arm => $arr_vec, _ => unreachable!() };
77
78 let __max_len = __old_arr.len().max(__new_arr.len());
79
80 for __i in 0..__max_len {
81 let __cp = format!("{path}/{__i}");
82 match (__old_arr.get(__i), __new_arr.get(__i)) {
83 (None, Some(__nv)) => {
84 changes.push(SemanticChange::Added {
85 path: __cp,
86 value: { let $vs_val = __nv; $vs_expr },
87 });
88 }
89 (Some(__ov), None) => {
90 changes.push(SemanticChange::Removed {
91 path: __cp,
92 old_value: { let $vs_val = __ov; $vs_expr },
93 });
94 }
95 (Some(__ov), Some(__nv)) => {
96 changes.extend(Self::diff_values(__ov, __nv, &__cp));
97 }
98 (None, None) => {}
99 }
100 }
101 } else if old != new {
102 changes.push(SemanticChange::Modified {
103 path: path.to_string(),
104 old_value: { let $vs_val = old; $vs_expr },
105 new_value: { let $vs_val = new; $vs_expr },
106 });
107 }
108
109 changes
110 }
111
112 fn merge_values(
113 base: &$value,
114 ours: &$value,
115 theirs: &$value,
116 ) -> Result<Option<$value>, DriverError> {
117 if matches!(base, $obj_arm)
118 && matches!(ours, $obj_arm)
119 && matches!(theirs, $obj_arm)
120 {
121 let __base_map = match base { $obj_arm => $obj_map, _ => unreachable!() };
122 let __ours_map = match ours { $obj_arm => $obj_map, _ => unreachable!() };
123 let __theirs_map =
124 match theirs { $obj_arm => $obj_map, _ => unreachable!() };
125
126 let __base_keys: std::collections::HashSet<_> = { let $ks_map = __base_map; $ks_expr };
127 let __ours_keys: std::collections::HashSet<_> = { let $ks_map = __ours_map; $ks_expr };
128 let __theirs_keys: std::collections::HashSet<_> = { let $ks_map = __theirs_map; $ks_expr };
129
130 let __all_keys: std::collections::HashSet<_> = __base_keys
131 .iter()
132 .chain(__ours_keys.iter())
133 .chain(__theirs_keys.iter())
134 .copied()
135 .collect();
136
137 let mut __merged = $new_map;
138
139 for __k in &__all_keys {
140 let __in_base = __base_keys.contains(__k);
141 let __in_ours = __ours_keys.contains(__k);
142 let __in_theirs = __theirs_keys.contains(__k);
143
144 match (__in_base, __in_ours, __in_theirs) {
145 (true, true, false) => {
146 let __v = { let $mg_map = __ours_map; let $mg_key = __k; $mg_expr }.unwrap();
147 { let $mi_map = &mut __merged; let $mi_key = __k; let $mi_val = __v.clone(); $mi_expr };
148 }
149 (true, false, true) => {
150 let __v = { let $mg_map = __theirs_map; let $mg_key = __k; $mg_expr }.unwrap();
151 { let $mi_map = &mut __merged; let $mi_key = __k; let $mi_val = __v.clone(); $mi_expr };
152 }
153 (true, true, true) => {
154 let __bv = { let $mg_map = __base_map; let $mg_key = __k; $mg_expr }.unwrap();
155 let __ov = { let $mg_map = __ours_map; let $mg_key = __k; $mg_expr }.unwrap();
156 let __tv = { let $mg_map = __theirs_map; let $mg_key = __k; $mg_expr }.unwrap();
157
158 if __ov == __tv {
159 { let $mi_map = &mut __merged; let $mi_key = __k; let $mi_val = __ov.clone(); $mi_expr };
160 } else if __ov == __bv {
161 { let $mi_map = &mut __merged; let $mi_key = __k; let $mi_val = __tv.clone(); $mi_expr };
162 } else if __tv == __bv {
163 { let $mi_map = &mut __merged; let $mi_key = __k; let $mi_val = __ov.clone(); $mi_expr };
164 } else if let Some(__m) =
165 Self::merge_values(__bv, __ov, __tv)?
166 {
167 { let $mi_map = &mut __merged; let $mi_key = __k; let $mi_val = __m; $mi_expr };
168 } else {
169 return Ok(None);
170 }
171 }
172 (false, true, true) => {
173 let __ov = { let $mg_map = __ours_map; let $mg_key = __k; $mg_expr }.unwrap();
174 let __tv = { let $mg_map = __theirs_map; let $mg_key = __k; $mg_expr }.unwrap();
175 if __ov == __tv {
176 { let $mi_map = &mut __merged; let $mi_key = __k; let $mi_val = __ov.clone(); $mi_expr };
177 } else {
178 return Ok(None);
179 }
180 }
181 (false, true, false) => {
182 let __v = { let $mg_map = __ours_map; let $mg_key = __k; $mg_expr }.unwrap();
183 { let $mi_map = &mut __merged; let $mi_key = __k; let $mi_val = __v.clone(); $mi_expr };
184 }
185 (false, false, true) => {
186 let __v = { let $mg_map = __theirs_map; let $mg_key = __k; $mg_expr }.unwrap();
187 { let $mi_map = &mut __merged; let $mi_key = __k; let $mi_val = __v.clone(); $mi_expr };
188 }
189 (true, false, false) | (false, false, false) => {}
190 }
191 }
192
193 Ok(Some({ let $wrap_m = __merged; $wrap_map_expr }))
194 } else if matches!(base, $arr_arm)
195 && matches!(ours, $arr_arm)
196 && matches!(theirs, $arr_arm)
197 {
198 let __base_arr = match base { $arr_arm => $arr_vec, _ => unreachable!() };
199 let __ours_arr = match ours { $arr_arm => $arr_vec, _ => unreachable!() };
200 let __theirs_arr =
201 match theirs { $arr_arm => $arr_vec, _ => unreachable!() };
202
203 let __max_len =
204 __base_arr.len().max(__ours_arr.len()).max(__theirs_arr.len());
205 let mut __merged_vec = Vec::new();
206
207 for __i in 0..__max_len {
208 let __bv = __base_arr.get(__i);
209 let __ov = __ours_arr.get(__i);
210 let __tv = __theirs_arr.get(__i);
211
212 match (__bv, __ov, __tv) {
213 (None, Some(__o), None) => __merged_vec.push(__o.clone()),
214 (None, None, Some(__t)) => __merged_vec.push(__t.clone()),
215 (None, Some(__o), Some(__t)) => {
216 if __o == __t {
217 __merged_vec.push(__o.clone());
218 } else {
219 return Ok(None);
220 }
221 }
222 (None, None, _) => {}
223 (Some(_), Some(__o), None) => __merged_vec.push(__o.clone()),
224 (Some(_), None, Some(__t)) => __merged_vec.push(__t.clone()),
225 (Some(_), None, None) => {}
226 (Some(__b), Some(__o), Some(__t)) => {
227 if __o == __t {
228 __merged_vec.push(__o.clone());
229 } else if __o == __b {
230 __merged_vec.push(__t.clone());
231 } else if __t == __b {
232 __merged_vec.push(__o.clone());
233 } else if let Some(__m) = Self::merge_values(__b, __o, __t)? {
234 __merged_vec.push(__m);
235 } else {
236 return Ok(None);
237 }
238 }
239 }
240 }
241
242 Ok(Some({ let $wrap_v = __merged_vec; $wrap_arr_expr }))
243 } else {
244 if ours == theirs {
245 Ok(Some(ours.clone()))
246 } else if ours == base {
247 Ok(Some(theirs.clone()))
248 } else if theirs == base {
249 Ok(Some(ours.clone()))
250 } else {
251 Ok(None)
252 }
253 }
254 }
255
256 fn format_change(change: &SemanticChange) -> String {
257 match change {
258 SemanticChange::Added { path, value } => {
259 format!(" ADDED {path}: {value}")
260 }
261 SemanticChange::Removed { path, old_value } => {
262 format!(" REMOVED {path}: {old_value}")
263 }
264 SemanticChange::Modified {
265 path,
266 old_value,
267 new_value,
268 } => {
269 format!(" MODIFIED {path}: {old_value} $arrow {new_value}")
270 }
271 SemanticChange::Moved {
272 old_path,
273 new_path,
274 value,
275 } => {
276 format!(" MOVED {old_path} $arrow {new_path}: {value}")
277 }
278 }
279 }
280 }
281
282 impl Default for $driver {
283 fn default() -> Self {
284 Self::new()
285 }
286 }
287
288 impl SutureDriver for $driver {
289 fn name(&self) -> &str {
290 $name
291 }
292
293 fn supported_extensions(&self) -> &[&str] {
294 &[$($ext),+]
295 }
296
297 fn diff(
298 &self,
299 base_content: Option<&str>,
300 new_content: &str,
301 ) -> Result<Vec<SemanticChange>, DriverError> {
302 let __new_val: $value = { let $pv_src = new_content; $pv_expr }?;
303
304 match base_content {
305 None => {
306 let mut __changes = Vec::new();
307 collect_all_paths(&__new_val, "/".to_string(), &mut __changes);
308 Ok(__changes)
309 }
310 Some(__base) => {
311 let __old_val: $value = { let $pv_src = __base; $pv_expr }?;
312 Ok(Self::diff_values(&__old_val, &__new_val, "/"))
313 }
314 }
315 }
316
317 fn format_diff(
318 &self,
319 base_content: Option<&str>,
320 new_content: &str,
321 ) -> Result<String, DriverError> {
322 let __changes = self.diff(base_content, new_content)?;
323
324 if __changes.is_empty() {
325 return Ok("no changes".to_string());
326 }
327
328 let __lines: Vec<String> = __changes.iter().map(Self::format_change).collect();
329 Ok(__lines.join("\n"))
330 }
331
332 fn merge(
333 &self,
334 base: &str,
335 ours: &str,
336 theirs: &str,
337 ) -> Result<Option<String>, DriverError> {
338 let __base_val: $value = { let $pv_src = base; $pv_expr }?;
339 let __ours_val: $value = { let $pv_src = ours; $pv_expr }?;
340 let __theirs_val: $value = { let $pv_src = theirs; $pv_expr }?;
341
342 match Self::merge_values(&__base_val, &__ours_val, &__theirs_val)? {
343 Some(__merged) => Ok(Some({ let $sv_val = &__merged; $sv_expr }?)),
344 None => Ok(None),
345 }
346 }
347 }
348
349 #[allow(clippy::collapsible_match)]
350 fn collect_all_paths(
351 __val: &$value,
352 __path: String,
353 __out: &mut Vec<SemanticChange>,
354 ) {
355 match __val {
356 $obj_arm => {
357 for (__k, __child) in $obj_map {
358 let __cp = { let $cp_parent = &__path; let $cp_key = __k; $cp_expr };
359 collect_all_paths(__child, __cp, __out);
360 }
361 }
362 $arr_arm => {
363 for (__i, __child) in $arr_vec.iter().enumerate() {
364 let __cp = format!("{__path}/{__i}");
365 collect_all_paths(__child, __cp, __out);
366 }
367 }
368 __other => {
369 __out.push(SemanticChange::Added {
370 path: __path,
371 value: { let $vs_val = __other; $vs_expr },
372 });
373 }
374 }
375 }
376 };
377}