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