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