Skip to main content

cumulo_dipa/set/
set_impl_macro.rs

1#[macro_export]
2macro_rules! set_impl {
3    ($map_ty:ty, $module:ident, $($additional_key_bounds:tt)*) => {
4        mod $module {
5            use super::{SetDelta, SetDeltaOwned};
6            use crate::{CreatedDelta, Diffable, Patchable};
7            use std::hash::Hash;
8
9            type SetAssociatedDeltaOwned<'s, 'e, K> =
10                <$map_ty as Diffable<'s, 'e, $map_ty>>::DeltaOwned;
11
12            impl<'s, 'e, K> Diffable<'s, 'e, $map_ty> for $map_ty
13            where
14                K: 's + 'e + Eq + Hash $($additional_key_bounds)*,
15            {
16                type Delta = SetDelta<'s, 'e, K>;
17                type DeltaOwned = SetDeltaOwned<K>;
18
19                fn create_delta_towards(
20                    &'s self,
21                    end_state: &'e $map_ty,
22                ) -> CreatedDelta<Self::Delta> {
23                    let mut did_change = false;
24
25                    if end_state.len() == 0 && self.len() > 0 {
26                        let delta = SetDelta::RemoveAll;
27                        return CreatedDelta {
28                            delta,
29                            did_change: true,
30                        };
31                    }
32
33                    let mut delta = SetDelta::NoChange;
34
35                    let mut fields_to_add = Vec::new();
36                    let mut fields_to_remove = Vec::new();
37
38                    for key in self.iter() {
39                        if !end_state.contains(key) {
40                            did_change = true;
41                            fields_to_remove.push(key);
42                        }
43                    }
44
45                    for key in end_state.iter() {
46                        if !self.contains(key) {
47                            did_change = true;
48                            fields_to_add.push(key);
49                        }
50                    }
51
52                    let many_fields_to_add = fields_to_add.len() > 1;
53                    let many_fields_to_remove = fields_to_remove.len() > 1;
54
55                    let one_field_to_add = fields_to_add.len() == 1;
56                    let one_field_to_remove = fields_to_remove.len() == 1;
57
58                    let encode_using_many_variant =
59                        many_fields_to_add || many_fields_to_remove ;
60
61                    if encode_using_many_variant {
62                        delta = SetDelta::ModifyMany {
63                            added: fields_to_add,
64                            removed: fields_to_remove,
65                        }
66                    } else if one_field_to_add {
67                        delta = SetDelta::AddOneField(fields_to_add[0]);
68                    } else if one_field_to_remove {
69                        delta = SetDelta::RemoveOneField(fields_to_remove[0]);
70                    }
71
72                    CreatedDelta {
73                        delta,
74                        did_change,
75                    }
76                }
77            }
78
79            impl<'s, 'e, K> Patchable<SetAssociatedDeltaOwned<'s, 'e, K>> for $map_ty
80            where
81                K: 's + 'e + Eq + Hash $($additional_key_bounds)*,
82            {
83                fn apply_patch(&mut self, patch: SetAssociatedDeltaOwned<'s, 'e, K>) {
84                    match patch {
85                        SetDeltaOwned::NoChange => {}
86                        SetDeltaOwned::RemoveAll => self.clear(),
87                        SetDeltaOwned::AddOneField(k) => {
88                            self.insert(k);
89                        }
90                        SetDeltaOwned::RemoveOneField(k) => {
91                            self.remove(&k);
92                        }
93                        SetDeltaOwned::ModifyMany {
94                            added,
95                            removed,
96                        } => {
97                            for add in added {
98                                self.insert(add);
99                            }
100
101                            for remove in removed {
102                                self.remove(&remove);
103                            }
104                        }
105                    }
106                }
107            }
108        }
109    };
110}