1use crate::{
2 patch::{ListPatch, MapPatch, MergePatchError, SetPatch, merge},
3 traits::Atomic,
4};
5use candid::CandidType;
6use std::{
7 collections::{BTreeMap, BTreeSet, HashMap, HashSet},
8 hash::{BuildHasher, Hash},
9};
10
11pub 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
44impl<T: AsView> AsView for Box<T> {
46 type ViewType = T::ViewType;
47
48 fn as_view(&self) -> Self::ViewType {
49 T::as_view(self.as_ref())
51 }
52
53 fn from_view(view: Self::ViewType) -> Self {
54 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
208pub trait CreateView: AsView {
213 type CreateViewType: CandidType + Default;
218
219 fn from_create_view(view: Self::CreateViewType) -> Self;
220}
221
222pub trait UpdateView: AsView {
227 type UpdateViewType: CandidType + Default;
229 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError>;
230}
231
232impl<T> UpdateView for T
233where
234 T: Atomic + AsView + CandidType + Default,
235{
236 type UpdateViewType = Self;
237
238 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
239 merge::merge_atomic(self, patch)
240 }
241}
242
243impl<T> UpdateView for Option<T>
244where
245 T: UpdateView + Default,
246{
247 type UpdateViewType = Option<T::UpdateViewType>;
248
249 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
250 merge::merge_option(self, patch)
251 }
252}
253
254impl<T> UpdateView for Vec<T>
255where
256 T: UpdateView + Default,
257{
258 type UpdateViewType = Vec<ListPatch<T::UpdateViewType>>;
259
260 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
261 merge::merge_vec(self, patch)
262 }
263}
264
265impl<T, S> UpdateView for HashSet<T, S>
266where
267 T: UpdateView + Clone + Default + Eq + Hash,
268 S: BuildHasher + Default,
269{
270 type UpdateViewType = Vec<SetPatch<T::UpdateViewType>>;
271
272 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
273 merge::merge_hash_set(self, patch)
274 }
275}
276
277impl<K, V, S> UpdateView for HashMap<K, V, S>
278where
279 K: UpdateView + Clone + Default + Eq + Hash,
280 V: UpdateView + Default,
281 S: BuildHasher + Default,
282{
283 type UpdateViewType = Vec<MapPatch<K::UpdateViewType, V::UpdateViewType>>;
284
285 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
286 merge::merge_hash_map(self, patch)
287 }
288}
289
290impl<T> UpdateView for BTreeSet<T>
291where
292 T: UpdateView + Clone + Default + Ord,
293{
294 type UpdateViewType = Vec<SetPatch<T::UpdateViewType>>;
295
296 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
297 merge::merge_btree_set(self, patch)
298 }
299}
300
301impl<K, V> UpdateView for BTreeMap<K, V>
302where
303 K: UpdateView + Clone + Default + Ord,
304 V: UpdateView + Default,
305{
306 type UpdateViewType = Vec<MapPatch<K::UpdateViewType, V::UpdateViewType>>;
307
308 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
309 merge::merge_btree_map(self, patch)
310 }
311}