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        if let Some(inner_update) = update {
157            if let Some(inner_value) = self {
158                inner_value.merge(inner_update);
159            } else {
160                let mut new_value = T::default();
161                new_value.merge(inner_update);
162                *self = Some(new_value);
163            }
164        }
165    }
166}
167
168impl<T> UpdateView for Vec<T>
169where
170    T: UpdateView + Default,
171{
172    // Payload is T::UpdateViewType, which *is* CandidType
173    type UpdateViewType = Vec<ListPatch<T::UpdateViewType>>;
174
175    fn merge(&mut self, patches: Self::UpdateViewType) {
176        for patch in patches {
177            match patch {
178                ListPatch::Update { index, patch } => {
179                    if let Some(elem) = self.get_mut(index) {
180                        elem.merge(patch);
181                    }
182                }
183                ListPatch::Insert { index, value } => {
184                    let mut elem = T::default();
185                    elem.merge(value);
186                    let idx = index.min(self.len());
187                    self.insert(idx, elem);
188                }
189                ListPatch::Push { value } => {
190                    let mut elem = T::default();
191                    elem.merge(value);
192                    self.push(elem);
193                }
194                ListPatch::Overwrite { values } => {
195                    self.clear();
196                    self.reserve(values.len());
197
198                    for value in values {
199                        let mut elem = T::default();
200                        elem.merge(value);
201                        self.push(elem);
202                    }
203                }
204                ListPatch::Remove { index } => {
205                    if index < self.len() {
206                        self.remove(index);
207                    }
208                }
209                ListPatch::Clear => self.clear(),
210            }
211        }
212    }
213}
214
215impl<T, S> UpdateView for HashSet<T, S>
216where
217    T: UpdateView + Default + Eq + Hash,
218    S: BuildHasher + Default,
219{
220    type UpdateViewType = Vec<SetPatch<T::UpdateViewType>>;
221
222    fn merge(&mut self, patches: Self::UpdateViewType) {
223        for patch in patches {
224            match patch {
225                SetPatch::Insert(value) => {
226                    let mut elem = T::default();
227                    elem.merge(value);
228                    self.insert(elem);
229                }
230                SetPatch::Remove(value) => {
231                    let mut elem = T::default();
232                    elem.merge(value);
233                    self.remove(&elem);
234                }
235                SetPatch::Overwrite { values } => {
236                    self.clear();
237
238                    for value in values {
239                        let mut elem = T::default();
240                        elem.merge(value);
241                        self.insert(elem);
242                    }
243                }
244                SetPatch::Clear => self.clear(),
245            }
246        }
247    }
248}
249
250impl<K, V, S> UpdateView for HashMap<K, V, S>
251where
252    K: UpdateView + Default + Eq + Hash,
253    V: UpdateView + Default,
254    S: BuildHasher + Default,
255{
256    type UpdateViewType = Vec<MapPatch<K::UpdateViewType, V::UpdateViewType>>;
257
258    fn merge(&mut self, patches: Self::UpdateViewType) {
259        for patch in patches {
260            match patch {
261                MapPatch::Upsert { key, value } => {
262                    let mut key_value = K::default();
263                    key_value.merge(key);
264
265                    match self.entry(key_value) {
266                        HashMapEntry::Occupied(mut slot) => {
267                            slot.get_mut().merge(value);
268                        }
269                        HashMapEntry::Vacant(slot) => {
270                            let mut value_value = V::default();
271                            value_value.merge(value);
272                            slot.insert(value_value);
273                        }
274                    }
275                }
276                MapPatch::Remove { key } => {
277                    let mut key_value = K::default();
278                    key_value.merge(key);
279                    self.remove(&key_value);
280                }
281                MapPatch::Overwrite { entries } => {
282                    self.clear();
283                    self.reserve(entries.len());
284
285                    for (key, value) in entries {
286                        let mut key_value = K::default();
287                        key_value.merge(key);
288
289                        let mut value_value = V::default();
290                        value_value.merge(value);
291                        self.insert(key_value, value_value);
292                    }
293                }
294                MapPatch::Clear => self.clear(),
295            }
296        }
297    }
298}
299
300macro_rules! impl_update_view {
301    ($($type:ty),*) => {
302        $(
303            impl UpdateView for $type {
304                type UpdateViewType = Self;
305
306                fn merge(&mut self, update: Self::UpdateViewType) {
307                    *self = update;
308                }
309            }
310        )*
311    };
312}
313
314impl_update_view!(bool, i8, i16, i32, i64, u8, u16, u32, u64, String);
315
316///
317/// FilterView
318///
319
320pub trait FilterView {
321    type FilterViewType: Default + crate::db::primitives::IntoFilterExpr;
322}