Skip to main content

icydb_core/traits/
view.rs

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