1use crate::view::{ListPatch, MapPatch, SetPatch};
2use candid::CandidType;
3use std::{
4 collections::{
5 BTreeMap, BTreeSet, HashMap, HashSet, btree_map::Entry as BTreeMapEntry,
6 hash_map::Entry as HashMapEntry,
7 },
8 hash::{BuildHasher, Hash},
9 iter::IntoIterator,
10};
11
12pub trait AsView: Sized {
20 type ViewType: Default;
21
22 fn as_view(&self) -> Self::ViewType;
23 fn from_view(view: Self::ViewType) -> Self;
24}
25
26impl AsView for () {
27 type ViewType = Self;
28
29 fn as_view(&self) -> Self::ViewType {}
30
31 fn from_view((): Self::ViewType) -> Self {}
32}
33
34impl AsView for String {
35 type ViewType = Self;
36
37 fn as_view(&self) -> Self::ViewType {
38 self.clone()
39 }
40
41 fn from_view(view: Self::ViewType) -> Self {
42 view
43 }
44}
45
46impl<T: AsView> AsView for Box<T> {
48 type ViewType = T::ViewType;
49
50 fn as_view(&self) -> Self::ViewType {
51 T::as_view(self.as_ref())
53 }
54
55 fn from_view(view: Self::ViewType) -> Self {
56 Self::new(T::from_view(view))
58 }
59}
60
61impl<T: AsView> AsView for Option<T> {
62 type ViewType = Option<T::ViewType>;
63
64 fn as_view(&self) -> Self::ViewType {
65 self.as_ref().map(AsView::as_view)
66 }
67
68 fn from_view(view: Self::ViewType) -> Self {
69 view.map(T::from_view)
70 }
71}
72
73impl<T: AsView> AsView for Vec<T> {
74 type ViewType = Vec<T::ViewType>;
75
76 fn as_view(&self) -> Self::ViewType {
77 self.iter().map(AsView::as_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<T, S> AsView for HashSet<T, S>
86where
87 T: AsView + Eq + Hash + Clone,
88 S: BuildHasher + Default,
89{
90 type ViewType = Vec<T::ViewType>;
91
92 fn as_view(&self) -> Self::ViewType {
93 self.iter().map(AsView::as_view).collect()
94 }
95
96 fn from_view(view: Self::ViewType) -> Self {
97 view.into_iter().map(T::from_view).collect()
98 }
99}
100
101impl<K, V, S> AsView for HashMap<K, V, S>
102where
103 K: AsView + Eq + Hash + Clone,
104 V: AsView,
105 S: BuildHasher + Default,
106{
107 type ViewType = Vec<(K::ViewType, V::ViewType)>;
108
109 fn as_view(&self) -> Self::ViewType {
110 self.iter()
111 .map(|(k, v)| (k.as_view(), v.as_view()))
112 .collect()
113 }
114
115 fn from_view(view: Self::ViewType) -> Self {
116 view.into_iter()
117 .map(|(k, v)| (K::from_view(k), V::from_view(v)))
118 .collect()
119 }
120}
121
122impl<T> AsView for BTreeSet<T>
123where
124 T: AsView + Ord + Clone,
125{
126 type ViewType = Vec<T::ViewType>;
127
128 fn as_view(&self) -> Self::ViewType {
129 self.iter().map(AsView::as_view).collect()
130 }
131
132 fn from_view(view: Self::ViewType) -> Self {
133 view.into_iter().map(T::from_view).collect()
134 }
135}
136
137impl<K, V> AsView for BTreeMap<K, V>
138where
139 K: AsView + Ord + Clone,
140 V: AsView,
141{
142 type ViewType = Vec<(K::ViewType, V::ViewType)>;
143
144 fn as_view(&self) -> Self::ViewType {
145 self.iter()
146 .map(|(k, v)| (k.as_view(), v.as_view()))
147 .collect()
148 }
149
150 fn from_view(view: Self::ViewType) -> Self {
151 view.into_iter()
152 .map(|(k, v)| (K::from_view(k), V::from_view(v)))
153 .collect()
154 }
155}
156
157#[macro_export]
158macro_rules! impl_view {
159 ($($type:ty),*) => {
160 $(
161 impl AsView for $type {
162 type ViewType = Self;
163
164 fn as_view(&self) -> Self::ViewType {
165 *self
166 }
167
168 fn from_view(view: Self::ViewType) -> Self {
169 view
170 }
171 }
172 )*
173 };
174}
175
176impl_view!(bool, i8, i16, i32, i64, u8, u16, u32, u64);
177
178impl AsView for f32 {
179 type ViewType = Self;
180
181 fn as_view(&self) -> Self::ViewType {
182 *self
183 }
184
185 fn from_view(view: Self::ViewType) -> Self {
186 if view.is_finite() {
187 if view == 0.0 { 0.0 } else { view }
188 } else {
189 0.0
190 }
191 }
192}
193
194impl AsView for f64 {
195 type ViewType = Self;
196
197 fn as_view(&self) -> Self::ViewType {
198 *self
199 }
200
201 fn from_view(view: Self::ViewType) -> Self {
202 if view.is_finite() {
203 if view == 0.0 { 0.0 } else { view }
204 } else {
205 0.0
206 }
207 }
208}
209
210pub trait CreateView: AsView {
215 type CreateViewType: CandidType + Default;
220
221 fn from_create_view(view: Self::CreateViewType) -> Self;
222}
223
224pub trait UpdateView: AsView {
229 type UpdateViewType: CandidType + Default;
231
232 fn merge(&mut self, _update: Self::UpdateViewType) {}
234}
235
236impl<T> UpdateView for Option<T>
237where
238 T: UpdateView + Default,
239{
240 type UpdateViewType = Option<T::UpdateViewType>;
241
242 fn merge(&mut self, update: Self::UpdateViewType) {
243 match update {
244 None => {
245 *self = None;
247 }
248 Some(inner_update) => {
249 if let Some(inner_value) = self.as_mut() {
250 inner_value.merge(inner_update);
251 } else {
252 let mut new_value = T::default();
253 new_value.merge(inner_update);
254 *self = Some(new_value);
255 }
256 }
257 }
258 }
259}
260
261impl<T> UpdateView for Vec<T>
262where
263 T: UpdateView + Default,
264{
265 type UpdateViewType = Vec<ListPatch<T::UpdateViewType>>;
267
268 fn merge(&mut self, patches: Self::UpdateViewType) {
269 for patch in patches {
270 match patch {
271 ListPatch::Update { index, patch } => {
272 if let Some(elem) = self.get_mut(index) {
273 elem.merge(patch);
274 }
275 }
276 ListPatch::Insert { index, value } => {
277 let mut elem = T::default();
278 elem.merge(value);
279 let idx = index.min(self.len());
280 self.insert(idx, elem);
281 }
282 ListPatch::Push { value } => {
283 let mut elem = T::default();
284 elem.merge(value);
285 self.push(elem);
286 }
287 ListPatch::Overwrite { values } => {
288 self.clear();
289 self.reserve(values.len());
290
291 for value in values {
292 let mut elem = T::default();
293 elem.merge(value);
294 self.push(elem);
295 }
296 }
297 ListPatch::Remove { index } => {
298 if index < self.len() {
299 self.remove(index);
300 }
301 }
302 ListPatch::Clear => self.clear(),
303 }
304 }
305 }
306}
307
308impl<T, S> UpdateView for HashSet<T, S>
309where
310 T: UpdateView + Clone + Default + Eq + Hash,
311 S: BuildHasher + Default,
312{
313 type UpdateViewType = Vec<SetPatch<T::UpdateViewType>>;
314
315 fn merge(&mut self, patches: Self::UpdateViewType) {
316 for patch in patches {
317 match patch {
318 SetPatch::Insert(value) => {
319 let mut elem = T::default();
320 elem.merge(value);
321 self.insert(elem);
322 }
323 SetPatch::Remove(value) => {
324 let mut elem = T::default();
325 elem.merge(value);
326 self.remove(&elem);
327 }
328 SetPatch::Overwrite { values } => {
329 self.clear();
330
331 for value in values {
332 let mut elem = T::default();
333 elem.merge(value);
334 self.insert(elem);
335 }
336 }
337 SetPatch::Clear => self.clear(),
338 }
339 }
340 }
341}
342
343enum MapPatchOp<K, V> {
345 Insert { key: K, value: V },
346 Remove { key: K },
347 Replace { key: K, value: V },
348 Clear,
349}
350
351impl<K, V, S> UpdateView for HashMap<K, V, S>
352where
353 K: UpdateView + Clone + Default + Eq + Hash,
354 V: UpdateView + Default,
355 S: BuildHasher + Default,
356{
357 type UpdateViewType = Vec<MapPatch<K::UpdateViewType, V::UpdateViewType>>;
358
359 fn merge(&mut self, patches: Self::UpdateViewType) {
360 let mut ops = Vec::with_capacity(patches.len());
362 for patch in patches {
363 match patch {
364 MapPatch::Insert { key, value } => {
365 let mut key_value = K::default();
366 key_value.merge(key);
367 ops.push(MapPatchOp::Insert {
368 key: key_value,
369 value,
370 });
371 }
372 MapPatch::Remove { key } => {
373 let mut key_value = K::default();
374 key_value.merge(key);
375 ops.push(MapPatchOp::Remove { key: key_value });
376 }
377 MapPatch::Replace { key, value } => {
378 let mut key_value = K::default();
379 key_value.merge(key);
380 ops.push(MapPatchOp::Replace {
381 key: key_value,
382 value,
383 });
384 }
385 MapPatch::Clear => ops.push(MapPatchOp::Clear),
386 }
387 }
388
389 let mut saw_clear = false;
391 let mut touched = HashSet::with_capacity(ops.len());
392 for op in &ops {
393 match op {
394 MapPatchOp::Clear => {
395 assert!(
396 !saw_clear,
397 "map patch batch contains duplicate Clear operations"
398 );
399 saw_clear = true;
400 assert!(
401 ops.len() == 1,
402 "map patch batch cannot combine Clear with key operations"
403 );
404 }
405 MapPatchOp::Insert { key, .. }
406 | MapPatchOp::Remove { key }
407 | MapPatchOp::Replace { key, .. } => {
408 assert!(
409 !saw_clear,
410 "map patch batch cannot combine Clear with key operations"
411 );
412 assert!(
413 touched.insert(key.clone()),
414 "map patch batch contains duplicate key operations"
415 );
416 }
417 }
418 }
419 if saw_clear {
420 self.clear();
421 return;
422 }
423
424 for op in ops {
426 match op {
427 MapPatchOp::Insert { key, value } => match self.entry(key) {
428 HashMapEntry::Occupied(mut slot) => {
429 slot.get_mut().merge(value);
430 }
431 HashMapEntry::Vacant(slot) => {
432 let mut value_value = V::default();
433 value_value.merge(value);
434 slot.insert(value_value);
435 }
436 },
437 MapPatchOp::Remove { key } => {
438 assert!(
439 self.remove(&key).is_some(),
440 "map patch remove target missing"
441 );
442 }
443 MapPatchOp::Replace { key, value } => match self.entry(key) {
444 HashMapEntry::Occupied(mut slot) => {
445 slot.get_mut().merge(value);
446 }
447 HashMapEntry::Vacant(_) => {
448 panic!("map patch replace target missing");
449 }
450 },
451 MapPatchOp::Clear => {
452 unreachable!("map patch clear shape is handled before apply");
453 }
454 }
455 }
456 }
457}
458
459impl<T> UpdateView for BTreeSet<T>
460where
461 T: UpdateView + Clone + Default + Ord,
462{
463 type UpdateViewType = Vec<SetPatch<T::UpdateViewType>>;
464
465 fn merge(&mut self, patches: Self::UpdateViewType) {
466 for patch in patches {
467 match patch {
468 SetPatch::Insert(value) => {
469 let mut elem = T::default();
470 elem.merge(value);
471 self.insert(elem);
472 }
473 SetPatch::Remove(value) => {
474 let mut elem = T::default();
475 elem.merge(value);
476 self.remove(&elem);
477 }
478 SetPatch::Overwrite { values } => {
479 self.clear();
480
481 for value in values {
482 let mut elem = T::default();
483 elem.merge(value);
484 self.insert(elem);
485 }
486 }
487 SetPatch::Clear => self.clear(),
488 }
489 }
490 }
491}
492
493impl<K, V> UpdateView for BTreeMap<K, V>
494where
495 K: UpdateView + Clone + Default + Ord,
496 V: UpdateView + Default,
497{
498 type UpdateViewType = Vec<MapPatch<K::UpdateViewType, V::UpdateViewType>>;
499
500 fn merge(&mut self, patches: Self::UpdateViewType) {
501 let mut ops = Vec::with_capacity(patches.len());
503 for patch in patches {
504 match patch {
505 MapPatch::Insert { key, value } => {
506 let mut key_value = K::default();
507 key_value.merge(key);
508 ops.push(MapPatchOp::Insert {
509 key: key_value,
510 value,
511 });
512 }
513 MapPatch::Remove { key } => {
514 let mut key_value = K::default();
515 key_value.merge(key);
516 ops.push(MapPatchOp::Remove { key: key_value });
517 }
518 MapPatch::Replace { key, value } => {
519 let mut key_value = K::default();
520 key_value.merge(key);
521 ops.push(MapPatchOp::Replace {
522 key: key_value,
523 value,
524 });
525 }
526 MapPatch::Clear => ops.push(MapPatchOp::Clear),
527 }
528 }
529
530 let mut saw_clear = false;
532 let mut touched = BTreeSet::new();
533 for op in &ops {
534 match op {
535 MapPatchOp::Clear => {
536 assert!(
537 !saw_clear,
538 "map patch batch contains duplicate Clear operations"
539 );
540 saw_clear = true;
541 assert!(
542 ops.len() == 1,
543 "map patch batch cannot combine Clear with key operations"
544 );
545 }
546 MapPatchOp::Insert { key, .. }
547 | MapPatchOp::Remove { key }
548 | MapPatchOp::Replace { key, .. } => {
549 assert!(
550 !saw_clear,
551 "map patch batch cannot combine Clear with key operations"
552 );
553 assert!(
554 touched.insert(key.clone()),
555 "map patch batch contains duplicate key operations"
556 );
557 }
558 }
559 }
560 if saw_clear {
561 self.clear();
562 return;
563 }
564
565 for op in ops {
567 match op {
568 MapPatchOp::Insert { key, value } => match self.entry(key) {
569 BTreeMapEntry::Occupied(mut slot) => {
570 slot.get_mut().merge(value);
571 }
572 BTreeMapEntry::Vacant(slot) => {
573 let mut value_value = V::default();
574 value_value.merge(value);
575 slot.insert(value_value);
576 }
577 },
578 MapPatchOp::Remove { key } => {
579 assert!(
580 self.remove(&key).is_some(),
581 "map patch remove target missing"
582 );
583 }
584 MapPatchOp::Replace { key, value } => match self.entry(key) {
585 BTreeMapEntry::Occupied(mut slot) => {
586 slot.get_mut().merge(value);
587 }
588 BTreeMapEntry::Vacant(_) => {
589 panic!("map patch replace target missing");
590 }
591 },
592 MapPatchOp::Clear => {
593 unreachable!("map patch clear shape is handled before apply");
594 }
595 }
596 }
597 }
598}
599
600macro_rules! impl_update_view {
601 ($($type:ty),*) => {
602 $(
603 impl UpdateView for $type {
604 type UpdateViewType = Self;
605
606 fn merge(&mut self, update: Self::UpdateViewType) {
607 *self = update;
608 }
609 }
610 )*
611 };
612}
613
614impl_update_view!(bool, i8, i16, i32, i64, u8, u16, u32, u64, String);