Skip to main content

suture_driver/
structured_merge.rs

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}