Skip to main content

icydb_core/traits/
view.rs

1use crate::{
2    patch::{list::ListPatch, map::MapPatch, set::SetPatch},
3    traits::Atomic,
4};
5use candid::CandidType;
6use std::{
7    collections::{BTreeMap, BTreeSet, HashMap, HashSet},
8    hash::{BuildHasher, Hash},
9};
10
11///
12/// AsView
13///
14/// Recursive for all field/value nodes
15/// `from_view` is infallible; view values are treated as canonical.
16///
17
18pub trait AsView: Sized {
19    type ViewType: Default;
20
21    fn as_view(&self) -> Self::ViewType;
22    fn from_view(view: Self::ViewType) -> Self;
23}
24
25impl AsView for () {
26    type ViewType = Self;
27
28    fn as_view(&self) -> Self::ViewType {}
29    fn from_view((): Self::ViewType) -> Self {}
30}
31
32impl AsView for String {
33    type ViewType = Self;
34
35    fn as_view(&self) -> Self::ViewType {
36        self.clone()
37    }
38
39    fn from_view(view: Self::ViewType) -> Self {
40        view
41    }
42}
43
44// Make Box<T> *not* appear in the view type
45impl<T: AsView> AsView for Box<T> {
46    type ViewType = T::ViewType;
47
48    fn as_view(&self) -> Self::ViewType {
49        // Delegate to inner value
50        T::as_view(self.as_ref())
51    }
52
53    fn from_view(view: Self::ViewType) -> Self {
54        // Re-box after reconstructing inner
55        Self::new(T::from_view(view))
56    }
57}
58
59impl<T: AsView> AsView for Option<T> {
60    type ViewType = Option<T::ViewType>;
61
62    fn as_view(&self) -> Self::ViewType {
63        self.as_ref().map(AsView::as_view)
64    }
65
66    fn from_view(view: Self::ViewType) -> Self {
67        view.map(T::from_view)
68    }
69}
70
71impl<T: AsView> AsView for Vec<T> {
72    type ViewType = Vec<T::ViewType>;
73
74    fn as_view(&self) -> Self::ViewType {
75        self.iter().map(AsView::as_view).collect()
76    }
77
78    fn from_view(view: Self::ViewType) -> Self {
79        view.into_iter().map(T::from_view).collect()
80    }
81}
82
83impl<T, S> AsView for HashSet<T, S>
84where
85    T: AsView + Eq + Hash + Clone,
86    S: BuildHasher + Default,
87{
88    type ViewType = Vec<T::ViewType>;
89
90    fn as_view(&self) -> Self::ViewType {
91        self.iter().map(AsView::as_view).collect()
92    }
93
94    fn from_view(view: Self::ViewType) -> Self {
95        view.into_iter().map(T::from_view).collect()
96    }
97}
98
99impl<K, V, S> AsView for HashMap<K, V, S>
100where
101    K: AsView + Eq + Hash + Clone,
102    V: AsView,
103    S: BuildHasher + Default,
104{
105    type ViewType = Vec<(K::ViewType, V::ViewType)>;
106
107    fn as_view(&self) -> Self::ViewType {
108        self.iter()
109            .map(|(k, v)| (k.as_view(), v.as_view()))
110            .collect()
111    }
112
113    fn from_view(view: Self::ViewType) -> Self {
114        view.into_iter()
115            .map(|(k, v)| (K::from_view(k), V::from_view(v)))
116            .collect()
117    }
118}
119
120impl<T> AsView for BTreeSet<T>
121where
122    T: AsView + Ord + Clone,
123{
124    type ViewType = Vec<T::ViewType>;
125
126    fn as_view(&self) -> Self::ViewType {
127        self.iter().map(AsView::as_view).collect()
128    }
129
130    fn from_view(view: Self::ViewType) -> Self {
131        view.into_iter().map(T::from_view).collect()
132    }
133}
134
135impl<K, V> AsView for BTreeMap<K, V>
136where
137    K: AsView + Ord + Clone,
138    V: AsView,
139{
140    type ViewType = Vec<(K::ViewType, V::ViewType)>;
141
142    fn as_view(&self) -> Self::ViewType {
143        self.iter()
144            .map(|(k, v)| (k.as_view(), v.as_view()))
145            .collect()
146    }
147
148    fn from_view(view: Self::ViewType) -> Self {
149        view.into_iter()
150            .map(|(k, v)| (K::from_view(k), V::from_view(v)))
151            .collect()
152    }
153}
154
155#[macro_export]
156macro_rules! impl_view {
157    ($($type:ty),*) => {
158        $(
159            impl AsView for $type {
160                type ViewType = Self;
161
162                fn as_view(&self) -> Self::ViewType {
163                    *self
164                }
165
166                fn from_view(view: Self::ViewType) -> Self {
167                    view
168                }
169            }
170        )*
171    };
172}
173
174impl_view!(bool, i8, i16, i32, i64, u8, u16, u32, u64);
175
176impl AsView for f32 {
177    type ViewType = Self;
178
179    fn as_view(&self) -> Self::ViewType {
180        *self
181    }
182
183    fn from_view(view: Self::ViewType) -> Self {
184        if view.is_finite() {
185            if view == 0.0 { 0.0 } else { view }
186        } else {
187            0.0
188        }
189    }
190}
191
192impl AsView for f64 {
193    type ViewType = Self;
194
195    fn as_view(&self) -> Self::ViewType {
196        *self
197    }
198
199    fn from_view(view: Self::ViewType) -> Self {
200        if view.is_finite() {
201            if view == 0.0 { 0.0 } else { view }
202        } else {
203            0.0
204        }
205    }
206}
207
208///
209/// CreateView
210///
211
212pub trait CreateView: AsView {
213    /// Payload accepted when creating this value.
214    ///
215    /// This is often equal to ViewType, but may differ
216    /// (e.g. Option<T>, defaults, omissions).
217    type CreateViewType: CandidType + Default;
218
219    fn from_create_view(view: Self::CreateViewType) -> Self;
220}
221
222///
223/// UpdateView
224///
225
226pub trait UpdateView: AsView {
227    /// A view payload that may be applied to `Self`.
228    type UpdateViewType: CandidType + Default;
229}
230
231impl<T> UpdateView for T
232where
233    T: Atomic + AsView + CandidType + Default,
234{
235    type UpdateViewType = Self;
236}
237
238impl<T> UpdateView for Option<T>
239where
240    T: UpdateView,
241{
242    type UpdateViewType = Option<T::UpdateViewType>;
243}
244
245impl<T> UpdateView for Vec<T>
246where
247    T: UpdateView,
248{
249    type UpdateViewType = Vec<ListPatch<T::UpdateViewType>>;
250}
251
252impl<T, S> UpdateView for HashSet<T, S>
253where
254    T: UpdateView + Clone + Eq + Hash,
255    S: BuildHasher + Default,
256{
257    type UpdateViewType = Vec<SetPatch<T::UpdateViewType>>;
258}
259
260impl<K, V, S> UpdateView for HashMap<K, V, S>
261where
262    K: UpdateView + Clone + Eq + Hash,
263    V: UpdateView,
264    S: BuildHasher + Default,
265{
266    type UpdateViewType = Vec<MapPatch<K::UpdateViewType, V::UpdateViewType>>;
267}
268
269impl<T> UpdateView for BTreeSet<T>
270where
271    T: UpdateView + Clone + Ord,
272{
273    type UpdateViewType = Vec<SetPatch<T::UpdateViewType>>;
274}
275
276impl<K, V> UpdateView for BTreeMap<K, V>
277where
278    K: UpdateView + Clone + Ord,
279    V: UpdateView,
280{
281    type UpdateViewType = Vec<MapPatch<K::UpdateViewType, V::UpdateViewType>>;
282}