1use crate::{
2 patch::{
3 ListPatch, MapPatch, MergePatchError, SetPatch,
4 merge::{
5 merge_atomic, merge_btree_map, merge_btree_set, merge_hash_map, merge_hash_set,
6 merge_option, merge_vec,
7 },
8 },
9 traits::Atomic,
10};
11use candid::CandidType;
12use std::{
13 collections::{BTreeMap, BTreeSet, HashMap, HashSet},
14 hash::{BuildHasher, Hash},
15};
16
17pub trait AsView: Sized {
25 type ViewType: Default;
26
27 fn as_view(&self) -> Self::ViewType;
28 fn from_view(view: Self::ViewType) -> Self;
29}
30
31impl AsView for () {
32 type ViewType = Self;
33
34 fn as_view(&self) -> Self::ViewType {}
35 fn from_view((): Self::ViewType) -> Self {}
36}
37
38impl AsView for String {
39 type ViewType = Self;
40
41 fn as_view(&self) -> Self::ViewType {
42 self.clone()
43 }
44
45 fn from_view(view: Self::ViewType) -> Self {
46 view
47 }
48}
49
50impl<T: AsView> AsView for Box<T> {
52 type ViewType = T::ViewType;
53
54 fn as_view(&self) -> Self::ViewType {
55 T::as_view(self.as_ref())
57 }
58
59 fn from_view(view: Self::ViewType) -> Self {
60 Self::new(T::from_view(view))
62 }
63}
64
65impl<T: AsView> AsView for Option<T> {
66 type ViewType = Option<T::ViewType>;
67
68 fn as_view(&self) -> Self::ViewType {
69 self.as_ref().map(AsView::as_view)
70 }
71
72 fn from_view(view: Self::ViewType) -> Self {
73 view.map(T::from_view)
74 }
75}
76
77impl<T: AsView> AsView for Vec<T> {
78 type ViewType = Vec<T::ViewType>;
79
80 fn as_view(&self) -> Self::ViewType {
81 self.iter().map(AsView::as_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<T, S> AsView for HashSet<T, S>
90where
91 T: AsView + Eq + Hash + Clone,
92 S: BuildHasher + Default,
93{
94 type ViewType = Vec<T::ViewType>;
95
96 fn as_view(&self) -> Self::ViewType {
97 self.iter().map(AsView::as_view).collect()
98 }
99
100 fn from_view(view: Self::ViewType) -> Self {
101 view.into_iter().map(T::from_view).collect()
102 }
103}
104
105impl<K, V, S> AsView for HashMap<K, V, S>
106where
107 K: AsView + Eq + Hash + Clone,
108 V: AsView,
109 S: BuildHasher + Default,
110{
111 type ViewType = Vec<(K::ViewType, V::ViewType)>;
112
113 fn as_view(&self) -> Self::ViewType {
114 self.iter()
115 .map(|(k, v)| (k.as_view(), v.as_view()))
116 .collect()
117 }
118
119 fn from_view(view: Self::ViewType) -> Self {
120 view.into_iter()
121 .map(|(k, v)| (K::from_view(k), V::from_view(v)))
122 .collect()
123 }
124}
125
126impl<T> AsView for BTreeSet<T>
127where
128 T: AsView + Ord + Clone,
129{
130 type ViewType = Vec<T::ViewType>;
131
132 fn as_view(&self) -> Self::ViewType {
133 self.iter().map(AsView::as_view).collect()
134 }
135
136 fn from_view(view: Self::ViewType) -> Self {
137 view.into_iter().map(T::from_view).collect()
138 }
139}
140
141impl<K, V> AsView for BTreeMap<K, V>
142where
143 K: AsView + Ord + Clone,
144 V: AsView,
145{
146 type ViewType = Vec<(K::ViewType, V::ViewType)>;
147
148 fn as_view(&self) -> Self::ViewType {
149 self.iter()
150 .map(|(k, v)| (k.as_view(), v.as_view()))
151 .collect()
152 }
153
154 fn from_view(view: Self::ViewType) -> Self {
155 view.into_iter()
156 .map(|(k, v)| (K::from_view(k), V::from_view(v)))
157 .collect()
158 }
159}
160
161#[macro_export]
162macro_rules! impl_view {
163 ($($type:ty),*) => {
164 $(
165 impl AsView for $type {
166 type ViewType = Self;
167
168 fn as_view(&self) -> Self::ViewType {
169 *self
170 }
171
172 fn from_view(view: Self::ViewType) -> Self {
173 view
174 }
175 }
176 )*
177 };
178}
179
180impl_view!(bool, i8, i16, i32, i64, u8, u16, u32, u64);
181
182impl AsView for f32 {
183 type ViewType = Self;
184
185 fn as_view(&self) -> Self::ViewType {
186 *self
187 }
188
189 fn from_view(view: Self::ViewType) -> Self {
190 if view.is_finite() {
191 if view == 0.0 { 0.0 } else { view }
192 } else {
193 0.0
194 }
195 }
196}
197
198impl AsView for f64 {
199 type ViewType = Self;
200
201 fn as_view(&self) -> Self::ViewType {
202 *self
203 }
204
205 fn from_view(view: Self::ViewType) -> Self {
206 if view.is_finite() {
207 if view == 0.0 { 0.0 } else { view }
208 } else {
209 0.0
210 }
211 }
212}
213
214pub trait CreateView: AsView {
219 type CreateViewType: CandidType + Default;
224
225 fn from_create_view(view: Self::CreateViewType) -> Self;
226}
227
228pub trait UpdateView: AsView {
233 type UpdateViewType: CandidType + Default;
235 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError>;
236}
237
238impl<T> UpdateView for T
239where
240 T: Atomic + AsView + CandidType + Default,
241{
242 type UpdateViewType = Self;
243
244 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
245 merge_atomic(self, patch);
246
247 Ok(())
248 }
249}
250
251impl<T> UpdateView for Option<T>
252where
253 T: UpdateView + Default,
254{
255 type UpdateViewType = Option<T::UpdateViewType>;
256
257 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
258 merge_option(self, patch)
259 }
260}
261
262impl<T> UpdateView for Vec<T>
263where
264 T: UpdateView + Default,
265{
266 type UpdateViewType = Vec<ListPatch<T::UpdateViewType>>;
267
268 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
269 merge_vec(self, patch)
270 }
271}
272
273impl<T, S> UpdateView for HashSet<T, S>
274where
275 T: UpdateView + Clone + Default + Eq + Hash,
276 S: BuildHasher + Default,
277{
278 type UpdateViewType = Vec<SetPatch<T::UpdateViewType>>;
279
280 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
281 merge_hash_set(self, patch)
282 }
283}
284
285impl<K, V, S> UpdateView for HashMap<K, V, S>
286where
287 K: UpdateView + Clone + Default + Eq + Hash,
288 V: UpdateView + Default,
289 S: BuildHasher + Default,
290{
291 type UpdateViewType = Vec<MapPatch<K::UpdateViewType, V::UpdateViewType>>;
292
293 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
294 merge_hash_map(self, patch)
295 }
296}
297
298impl<T> UpdateView for BTreeSet<T>
299where
300 T: UpdateView + Clone + Default + Ord,
301{
302 type UpdateViewType = Vec<SetPatch<T::UpdateViewType>>;
303
304 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
305 merge_btree_set(self, patch)
306 }
307}
308
309impl<K, V> UpdateView for BTreeMap<K, V>
310where
311 K: UpdateView + Clone + Default + Ord,
312 V: UpdateView + Default,
313{
314 type UpdateViewType = Vec<MapPatch<K::UpdateViewType, V::UpdateViewType>>;
315
316 fn merge(&mut self, patch: Self::UpdateViewType) -> Result<(), MergePatchError> {
317 merge_btree_map(self, patch)
318 }
319}