icydb_core/traits/
view.rs

1use crate::view::{ListPatch, MapPatch, SetPatch};
2use candid::CandidType;
3use std::{
4    collections::{HashMap, HashSet, hash_map::Entry as HashMapEntry},
5    hash::{BuildHasher, Hash},
6    iter::IntoIterator,
7};
8
9///
10/// View
11/// Recursive for all field/value nodes
12///
13
14pub trait View {
15    type ViewType: Default;
16
17    fn to_view(&self) -> Self::ViewType;
18    fn from_view(view: Self::ViewType) -> Self;
19}
20
21impl View for String {
22    type ViewType = Self;
23
24    fn to_view(&self) -> Self::ViewType {
25        self.clone()
26    }
27
28    fn from_view(view: Self::ViewType) -> Self {
29        view
30    }
31}
32
33// Make Box<T> *not* appear in the view type
34impl<T: View> View for Box<T> {
35    type ViewType = T::ViewType;
36
37    fn to_view(&self) -> Self::ViewType {
38        // Delegate to inner value
39        T::to_view(self.as_ref())
40    }
41
42    fn from_view(view: Self::ViewType) -> Self {
43        // Re-box after reconstructing inner
44        Self::new(T::from_view(view))
45    }
46}
47
48impl<T: View> View for Option<T> {
49    type ViewType = Option<T::ViewType>;
50
51    fn to_view(&self) -> Self::ViewType {
52        self.as_ref().map(View::to_view)
53    }
54
55    fn from_view(view: Self::ViewType) -> Self {
56        view.map(T::from_view)
57    }
58}
59
60impl<T: View> View for Vec<T> {
61    type ViewType = Vec<T::ViewType>;
62
63    fn to_view(&self) -> Self::ViewType {
64        self.iter().map(View::to_view).collect()
65    }
66
67    fn from_view(view: Self::ViewType) -> Self {
68        view.into_iter().map(T::from_view).collect()
69    }
70}
71
72impl<T, S> View for HashSet<T, S>
73where
74    T: View + Eq + Hash + Clone,
75    S: BuildHasher + Default,
76{
77    type ViewType = Vec<T::ViewType>;
78
79    fn to_view(&self) -> Self::ViewType {
80        self.iter().map(View::to_view).collect()
81    }
82
83    fn from_view(view: Self::ViewType) -> Self {
84        view.into_iter().map(T::from_view).collect()
85    }
86}
87
88impl<K, V, S> View for HashMap<K, V, S>
89where
90    K: View + Eq + Hash + Clone,
91    V: View,
92    S: BuildHasher + Default,
93{
94    type ViewType = Vec<(K::ViewType, V::ViewType)>;
95
96    fn to_view(&self) -> Self::ViewType {
97        self.iter()
98            .map(|(k, v)| (k.to_view(), v.to_view()))
99            .collect()
100    }
101
102    fn from_view(view: Self::ViewType) -> Self {
103        view.into_iter()
104            .map(|(k, v)| (K::from_view(k), V::from_view(v)))
105            .collect()
106    }
107}
108
109#[macro_export]
110macro_rules! impl_view {
111    ($($type:ty),*) => {
112        $(
113            impl View for $type {
114                type ViewType = Self;
115
116                fn to_view(&self) -> Self::ViewType {
117                    *self
118                }
119
120                fn from_view(view: Self::ViewType) -> Self {
121                    view
122                }
123            }
124        )*
125    };
126}
127
128impl_view!(bool, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64);
129
130///
131/// CreateView
132///
133
134pub trait CreateView {
135    type CreateViewType: CandidType + Default;
136}
137
138///
139/// UpdateView
140///
141
142pub trait UpdateView {
143    type UpdateViewType: CandidType + Default;
144
145    /// merge the updateview into self
146    fn merge(&mut self, _: Self::UpdateViewType) {}
147}
148
149impl<T> UpdateView for Option<T>
150where
151    T: UpdateView + Default,
152{
153    type UpdateViewType = Option<T::UpdateViewType>;
154
155    fn merge(&mut self, update: Self::UpdateViewType) {
156        match update {
157            None => {
158                // Field was provided (outer Some), inner None means explicit delete
159                *self = None;
160            }
161            Some(inner_update) => {
162                if let Some(inner_value) = self.as_mut() {
163                    inner_value.merge(inner_update);
164                } else {
165                    let mut new_value = T::default();
166                    new_value.merge(inner_update);
167                    *self = Some(new_value);
168                }
169            }
170        }
171    }
172}
173
174impl<T> UpdateView for Vec<T>
175where
176    T: UpdateView + Default,
177{
178    // Payload is T::UpdateViewType, which *is* CandidType
179    type UpdateViewType = Vec<ListPatch<T::UpdateViewType>>;
180
181    fn merge(&mut self, patches: Self::UpdateViewType) {
182        for patch in patches {
183            match patch {
184                ListPatch::Update { index, patch } => {
185                    if let Some(elem) = self.get_mut(index) {
186                        elem.merge(patch);
187                    }
188                }
189                ListPatch::Insert { index, value } => {
190                    let mut elem = T::default();
191                    elem.merge(value);
192                    let idx = index.min(self.len());
193                    self.insert(idx, elem);
194                }
195                ListPatch::Push { value } => {
196                    let mut elem = T::default();
197                    elem.merge(value);
198                    self.push(elem);
199                }
200                ListPatch::Overwrite { values } => {
201                    self.clear();
202                    self.reserve(values.len());
203
204                    for value in values {
205                        let mut elem = T::default();
206                        elem.merge(value);
207                        self.push(elem);
208                    }
209                }
210                ListPatch::Remove { index } => {
211                    if index < self.len() {
212                        self.remove(index);
213                    }
214                }
215                ListPatch::Clear => self.clear(),
216            }
217        }
218    }
219}
220
221impl<T, S> UpdateView for HashSet<T, S>
222where
223    T: UpdateView + Default + Eq + Hash,
224    S: BuildHasher + Default,
225{
226    type UpdateViewType = Vec<SetPatch<T::UpdateViewType>>;
227
228    fn merge(&mut self, patches: Self::UpdateViewType) {
229        for patch in patches {
230            match patch {
231                SetPatch::Insert(value) => {
232                    let mut elem = T::default();
233                    elem.merge(value);
234                    self.insert(elem);
235                }
236                SetPatch::Remove(value) => {
237                    let mut elem = T::default();
238                    elem.merge(value);
239                    self.remove(&elem);
240                }
241                SetPatch::Overwrite { values } => {
242                    self.clear();
243
244                    for value in values {
245                        let mut elem = T::default();
246                        elem.merge(value);
247                        self.insert(elem);
248                    }
249                }
250                SetPatch::Clear => self.clear(),
251            }
252        }
253    }
254}
255
256impl<K, V, S> UpdateView for HashMap<K, V, S>
257where
258    K: UpdateView + Default + Eq + Hash,
259    V: UpdateView + Default,
260    S: BuildHasher + Default,
261{
262    type UpdateViewType = Vec<MapPatch<K::UpdateViewType, V::UpdateViewType>>;
263
264    fn merge(&mut self, patches: Self::UpdateViewType) {
265        for patch in patches {
266            match patch {
267                MapPatch::Upsert { key, value } => {
268                    let mut key_value = K::default();
269                    key_value.merge(key);
270
271                    match self.entry(key_value) {
272                        HashMapEntry::Occupied(mut slot) => {
273                            slot.get_mut().merge(value);
274                        }
275                        HashMapEntry::Vacant(slot) => {
276                            let mut value_value = V::default();
277                            value_value.merge(value);
278                            slot.insert(value_value);
279                        }
280                    }
281                }
282                MapPatch::Remove { key } => {
283                    let mut key_value = K::default();
284                    key_value.merge(key);
285                    self.remove(&key_value);
286                }
287                MapPatch::Overwrite { entries } => {
288                    self.clear();
289                    self.reserve(entries.len());
290
291                    for (key, value) in entries {
292                        let mut key_value = K::default();
293                        key_value.merge(key);
294
295                        let mut value_value = V::default();
296                        value_value.merge(value);
297                        self.insert(key_value, value_value);
298                    }
299                }
300                MapPatch::Clear => self.clear(),
301            }
302        }
303    }
304}
305
306macro_rules! impl_update_view {
307    ($($type:ty),*) => {
308        $(
309            impl UpdateView for $type {
310                type UpdateViewType = Self;
311
312                fn merge(&mut self, update: Self::UpdateViewType) {
313                    *self = update;
314                }
315            }
316        )*
317    };
318}
319
320impl_update_view!(bool, i8, i16, i32, i64, u8, u16, u32, u64, String);
321
322///
323/// FilterView
324///
325
326pub trait FilterView {
327    type FilterViewType: Default + crate::db::primitives::IntoFilterExpr;
328}