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