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 if let Some(inner_update) = update {
157 if let Some(inner_value) = self {
158 inner_value.merge(inner_update);
159 } else {
160 let mut new_value = T::default();
161 new_value.merge(inner_update);
162 *self = Some(new_value);
163 }
164 }
165 }
166}
167
168impl<T> UpdateView for Vec<T>
169where
170 T: UpdateView + Default,
171{
172 type UpdateViewType = Vec<ListPatch<T::UpdateViewType>>;
174
175 fn merge(&mut self, patches: Self::UpdateViewType) {
176 for patch in patches {
177 match patch {
178 ListPatch::Update { index, patch } => {
179 if let Some(elem) = self.get_mut(index) {
180 elem.merge(patch);
181 }
182 }
183 ListPatch::Insert { index, value } => {
184 let mut elem = T::default();
185 elem.merge(value);
186 let idx = index.min(self.len());
187 self.insert(idx, elem);
188 }
189 ListPatch::Push { value } => {
190 let mut elem = T::default();
191 elem.merge(value);
192 self.push(elem);
193 }
194 ListPatch::Overwrite { values } => {
195 self.clear();
196 self.reserve(values.len());
197
198 for value in values {
199 let mut elem = T::default();
200 elem.merge(value);
201 self.push(elem);
202 }
203 }
204 ListPatch::Remove { index } => {
205 if index < self.len() {
206 self.remove(index);
207 }
208 }
209 ListPatch::Clear => self.clear(),
210 }
211 }
212 }
213}
214
215impl<T, S> UpdateView for HashSet<T, S>
216where
217 T: UpdateView + Default + Eq + Hash,
218 S: BuildHasher + Default,
219{
220 type UpdateViewType = Vec<SetPatch<T::UpdateViewType>>;
221
222 fn merge(&mut self, patches: Self::UpdateViewType) {
223 for patch in patches {
224 match patch {
225 SetPatch::Insert(value) => {
226 let mut elem = T::default();
227 elem.merge(value);
228 self.insert(elem);
229 }
230 SetPatch::Remove(value) => {
231 let mut elem = T::default();
232 elem.merge(value);
233 self.remove(&elem);
234 }
235 SetPatch::Overwrite { values } => {
236 self.clear();
237
238 for value in values {
239 let mut elem = T::default();
240 elem.merge(value);
241 self.insert(elem);
242 }
243 }
244 SetPatch::Clear => self.clear(),
245 }
246 }
247 }
248}
249
250impl<K, V, S> UpdateView for HashMap<K, V, S>
251where
252 K: UpdateView + Default + Eq + Hash,
253 V: UpdateView + Default,
254 S: BuildHasher + Default,
255{
256 type UpdateViewType = Vec<MapPatch<K::UpdateViewType, V::UpdateViewType>>;
257
258 fn merge(&mut self, patches: Self::UpdateViewType) {
259 for patch in patches {
260 match patch {
261 MapPatch::Upsert { key, value } => {
262 let mut key_value = K::default();
263 key_value.merge(key);
264
265 match self.entry(key_value) {
266 HashMapEntry::Occupied(mut slot) => {
267 slot.get_mut().merge(value);
268 }
269 HashMapEntry::Vacant(slot) => {
270 let mut value_value = V::default();
271 value_value.merge(value);
272 slot.insert(value_value);
273 }
274 }
275 }
276 MapPatch::Remove { key } => {
277 let mut key_value = K::default();
278 key_value.merge(key);
279 self.remove(&key_value);
280 }
281 MapPatch::Overwrite { entries } => {
282 self.clear();
283 self.reserve(entries.len());
284
285 for (key, value) in entries {
286 let mut key_value = K::default();
287 key_value.merge(key);
288
289 let mut value_value = V::default();
290 value_value.merge(value);
291 self.insert(key_value, value_value);
292 }
293 }
294 MapPatch::Clear => self.clear(),
295 }
296 }
297 }
298}
299
300macro_rules! impl_update_view {
301 ($($type:ty),*) => {
302 $(
303 impl UpdateView for $type {
304 type UpdateViewType = Self;
305
306 fn merge(&mut self, update: Self::UpdateViewType) {
307 *self = update;
308 }
309 }
310 )*
311 };
312}
313
314impl_update_view!(bool, i8, i16, i32, i64, u8, u16, u32, u64, String);
315
316pub trait FilterView {
321 type FilterViewType: Default + crate::db::primitives::IntoFilterExpr;
322}