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