Skip to main content

cumulo_dipa/map/
map_impl_macro.rs

1#[macro_export]
2macro_rules! map_impl {
3    ($map_ty:ty, $module:ident, $($additional_key_bounds:tt)*) => {
4        mod $module {
5            use super::{MapDelta, MapDeltaOwned};
6            use crate::{CreatedDelta, Diffable, Patchable};
7            use serde::{Serialize, de::DeserializeOwned};
8            use std::hash::Hash;
9
10            type MapAssociatedDeltaOwned<'s, 'e, K, V> =
11                <$map_ty as Diffable<'s, 'e, $map_ty>>::DeltaOwned;
12
13            impl<'s, 'e, K, V> Diffable<'s, 'e, $map_ty> for $map_ty
14            where
15                K: 's + 'e + Eq + Hash $($additional_key_bounds)*,
16                V: 'e + Diffable<'s, 'e, V>,
17                <V as Diffable<'s,'e,V>>::Delta: Serialize,
18                <V as Diffable<'s,'e,V>>::DeltaOwned: DeserializeOwned
19            {
20                type Delta = MapDelta<'s, 'e, K, V>;
21                type DeltaOwned = MapDeltaOwned<'s, 'e, K, V>;
22
23                fn create_delta_towards(
24                    &'s self,
25                    end_state: &'e $map_ty,
26                ) -> CreatedDelta<Self::Delta> {
27                    let mut did_change = false;
28
29                    if end_state.len() == 0 && self.len() > 0 {
30                        let delta = MapDelta::RemoveAll;
31                        return CreatedDelta {
32                            delta,
33                            did_change: true
34                        };
35                    }
36
37                    let mut delta = MapDelta::NoChange;
38
39                    let mut fields_to_add = Vec::new();
40                    let mut fields_to_remove = Vec::new();
41                    let mut fields_changed = Vec::new();
42
43                    for (key, start) in self.iter() {
44                        match end_state.get(key) {
45                            None => {
46                                did_change = true;
47                                fields_to_remove.push(key);
48                            }
49                            Some(end) => {
50                                let CreatedDelta {delta, did_change: changed} = start.create_delta_towards(end);
51
52                                if changed {
53                                    did_change = true;
54                                    fields_changed.push((key, delta));
55                                }
56                            }
57                        }
58                    }
59
60                    for (key, val) in end_state.iter() {
61                        if !self.contains_key(key) {
62                            did_change = true;
63                            fields_to_add.push((key, val));
64                        }
65                    }
66
67                    let many_fields_to_add = fields_to_add.len() > 1;
68                    let many_fields_to_remove = fields_to_remove.len() > 1;
69                    let many_fields_changed = fields_changed.len() > 1;
70
71                    let one_field_to_add = fields_to_add.len() == 1;
72                    let one_field_to_remove = fields_to_remove.len() == 1;
73                    let one_field_changed = fields_changed.len() == 1;
74
75                    let encode_using_many_variant =
76                        many_fields_to_add || many_fields_to_remove || many_fields_changed;
77
78                    if encode_using_many_variant {
79                        delta = MapDelta::ModifyMany {
80                            added: fields_to_add,
81                            removed: fields_to_remove,
82                            changed: fields_changed,
83                        }
84                    } else if one_field_to_add {
85                        delta = MapDelta::AddOneField(fields_to_add[0].0, fields_to_add[0].1);
86                    } else if one_field_to_remove {
87                        delta = MapDelta::RemoveOneField(fields_to_remove[0]);
88                    } else if one_field_changed {
89                        let change = fields_changed.remove(0);
90                        delta = MapDelta::ChangeOneField(change.0, change.1);
91                    }
92
93                    CreatedDelta {
94                        delta,
95                        did_change
96                    }
97                }
98            }
99
100            impl<'s, 'e, K, V> Patchable<MapAssociatedDeltaOwned<'s, 'e, K, V>> for $map_ty
101            where
102                K: 's + 'e + Eq + Hash $($additional_key_bounds)*,
103                V: 'e + Diffable<'s, 'e, V>,
104                V: Patchable<<V as Diffable<'s, 'e, V>>::DeltaOwned>,
105                <V as Diffable<'s,'e,V>>::Delta: Serialize,
106                <V as Diffable<'s,'e,V>>::DeltaOwned: DeserializeOwned
107            {
108                fn apply_patch(&mut self, patch: MapAssociatedDeltaOwned<'s, 'e, K, V>) {
109                    match patch {
110                        MapDeltaOwned::NoChange => {}
111                        MapDeltaOwned::RemoveAll => self.clear(),
112                        MapDeltaOwned::AddOneField(k, v) => {
113                            self.insert(k, v);
114                        }
115                        MapDeltaOwned::RemoveOneField(k) => {
116                            self.remove(&k);
117                        }
118                        MapDeltaOwned::ChangeOneField(k, delta) => {
119                            self.get_mut(&k).unwrap().apply_patch(delta);
120                        }
121                        MapDeltaOwned::ModifyMany {
122                            added,
123                            removed,
124                            changed,
125                        } => {
126                            for add in added {
127                                self.insert(add.0, add.1);
128                            }
129
130                            for remove in removed {
131                                self.remove(&remove);
132                            }
133
134                            for change in changed {
135                                self.get_mut(&change.0).unwrap().apply_patch(change.1);
136                            }
137                        }
138                    }
139                }
140            }
141        }
142    };
143}