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