linera_views/views/collection_view.rs
1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{
5 borrow::Borrow,
6 collections::{btree_map, BTreeMap},
7 io::Write,
8 marker::PhantomData,
9 mem,
10};
11
12use async_lock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
13#[cfg(with_metrics)]
14use linera_base::prometheus_util::MeasureLatency as _;
15use serde::{de::DeserializeOwned, Serialize};
16
17use crate::{
18 batch::Batch,
19 common::{CustomSerialize, HasherOutput, Update},
20 context::{BaseKey, Context},
21 hashable_wrapper::WrappedHashableContainerView,
22 store::{KeyIterable, ReadableKeyValueStore as _},
23 views::{ClonableView, HashableView, Hasher, View, ViewError, MIN_VIEW_TAG},
24};
25
26#[cfg(with_metrics)]
27mod metrics {
28 use std::sync::LazyLock;
29
30 use linera_base::prometheus_util::{exponential_bucket_latencies, register_histogram_vec};
31 use prometheus::HistogramVec;
32
33 /// The runtime of hash computation
34 pub static COLLECTION_VIEW_HASH_RUNTIME: LazyLock<HistogramVec> = LazyLock::new(|| {
35 register_histogram_vec(
36 "collection_view_hash_runtime",
37 "CollectionView hash runtime",
38 &[],
39 exponential_bucket_latencies(5.0),
40 )
41 });
42}
43
44/// A view that supports accessing a collection of views of the same kind, indexed by a
45/// `Vec<u8>`, one subview at a time.
46#[derive(Debug)]
47pub struct ByteCollectionView<C, W> {
48 context: C,
49 delete_storage_first: bool,
50 updates: RwLock<BTreeMap<Vec<u8>, Update<W>>>,
51}
52
53/// A read-only accessor for a particular subview in a [`CollectionView`].
54pub struct ReadGuardedView<'a, W> {
55 guard: RwLockReadGuard<'a, BTreeMap<Vec<u8>, Update<W>>>,
56 short_key: Vec<u8>,
57}
58
59impl<W> std::ops::Deref for ReadGuardedView<'_, W> {
60 type Target = W;
61
62 fn deref(&self) -> &W {
63 let Update::Set(view) = self.guard.get(&self.short_key).unwrap() else {
64 unreachable!();
65 };
66 view
67 }
68}
69
70/// We need to find new base keys in order to implement `CollectionView`.
71/// We do this by appending a value to the base key.
72///
73/// Sub-views in a collection share a common key prefix, like in other view types. However,
74/// just concatenating the shared prefix with sub-view keys makes it impossible to distinguish if a
75/// given key belongs to child sub-view or a grandchild sub-view (consider for example if a
76/// collection is stored inside the collection).
77#[repr(u8)]
78enum KeyTag {
79 /// Prefix for specifying an index and serves to indicate the existence of an entry in the collection.
80 Index = MIN_VIEW_TAG,
81 /// Prefix for specifying as the prefix for the sub-view.
82 Subview,
83}
84
85impl<W: View> View for ByteCollectionView<W::Context, W> {
86 const NUM_INIT_KEYS: usize = 0;
87
88 type Context = W::Context;
89
90 fn context(&self) -> &Self::Context {
91 &self.context
92 }
93
94 fn pre_load(_context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
95 Ok(vec![])
96 }
97
98 fn post_load(context: Self::Context, _values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
99 Ok(Self {
100 context,
101 delete_storage_first: false,
102 updates: RwLock::new(BTreeMap::new()),
103 })
104 }
105
106 async fn load(context: Self::Context) -> Result<Self, ViewError> {
107 Self::post_load(context, &[])
108 }
109
110 fn rollback(&mut self) {
111 self.delete_storage_first = false;
112 self.updates.get_mut().clear();
113 }
114
115 async fn has_pending_changes(&self) -> bool {
116 if self.delete_storage_first {
117 return true;
118 }
119 let updates = self.updates.read().await;
120 !updates.is_empty()
121 }
122
123 fn flush(&mut self, batch: &mut Batch) -> Result<bool, ViewError> {
124 let mut delete_view = false;
125 if self.delete_storage_first {
126 delete_view = true;
127 batch.delete_key_prefix(self.context.base_key().bytes.clone());
128 for (index, update) in mem::take(self.updates.get_mut()) {
129 if let Update::Set(mut view) = update {
130 view.flush(batch)?;
131 self.add_index(batch, &index);
132 delete_view = false;
133 }
134 }
135 } else {
136 for (index, update) in mem::take(self.updates.get_mut()) {
137 match update {
138 Update::Set(mut view) => {
139 view.flush(batch)?;
140 self.add_index(batch, &index);
141 }
142 Update::Removed => {
143 let key_subview = self.get_subview_key(&index);
144 let key_index = self.get_index_key(&index);
145 batch.delete_key(key_index);
146 batch.delete_key_prefix(key_subview);
147 }
148 }
149 }
150 }
151 self.delete_storage_first = false;
152 Ok(delete_view)
153 }
154
155 fn clear(&mut self) {
156 self.delete_storage_first = true;
157 self.updates.get_mut().clear();
158 }
159}
160
161impl<W: ClonableView> ClonableView for ByteCollectionView<W::Context, W> {
162 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
163 let cloned_updates = self
164 .updates
165 .get_mut()
166 .iter_mut()
167 .map(|(key, value)| {
168 let cloned_value = match value {
169 Update::Removed => Update::Removed,
170 Update::Set(view) => Update::Set(view.clone_unchecked()?),
171 };
172 Ok((key.clone(), cloned_value))
173 })
174 .collect::<Result<_, ViewError>>()?;
175
176 Ok(ByteCollectionView {
177 context: self.context.clone(),
178 delete_storage_first: self.delete_storage_first,
179 updates: RwLock::new(cloned_updates),
180 })
181 }
182}
183
184impl<W: View> ByteCollectionView<W::Context, W> {
185 fn get_index_key(&self, index: &[u8]) -> Vec<u8> {
186 self.context
187 .base_key()
188 .base_tag_index(KeyTag::Index as u8, index)
189 }
190
191 fn get_subview_key(&self, index: &[u8]) -> Vec<u8> {
192 self.context
193 .base_key()
194 .base_tag_index(KeyTag::Subview as u8, index)
195 }
196
197 fn add_index(&self, batch: &mut Batch, index: &[u8]) {
198 let key = self.get_index_key(index);
199 batch.put_key_value_bytes(key, vec![]);
200 }
201
202 /// Loads a subview for the data at the given index in the collection. If an entry
203 /// is absent then a default entry is added to the collection. The resulting view
204 /// can be modified.
205 /// ```rust
206 /// # tokio_test::block_on(async {
207 /// # use linera_views::context::MemoryContext;
208 /// # use linera_views::collection_view::ByteCollectionView;
209 /// # use linera_views::register_view::RegisterView;
210 /// # use linera_views::views::View;
211 /// # let context = MemoryContext::new_for_testing(());
212 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
213 /// ByteCollectionView::load(context).await.unwrap();
214 /// let subview = view.load_entry_mut(&[0, 1]).await.unwrap();
215 /// let value = subview.get();
216 /// assert_eq!(*value, String::default());
217 /// # })
218 /// ```
219 pub async fn load_entry_mut(&mut self, short_key: &[u8]) -> Result<&mut W, ViewError> {
220 self.do_load_entry_mut(short_key).await
221 }
222
223 /// Loads a subview for the data at the given index in the collection. If an entry
224 /// is absent then a default entry is added to the collection. The resulting view
225 /// is read-only.
226 /// ```rust
227 /// # tokio_test::block_on(async {
228 /// # use linera_views::context::MemoryContext;
229 /// # use linera_views::collection_view::ByteCollectionView;
230 /// # use linera_views::register_view::RegisterView;
231 /// # use linera_views::views::View;
232 /// # let context = MemoryContext::new_for_testing(());
233 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
234 /// ByteCollectionView::load(context).await.unwrap();
235 /// view.load_entry_mut(&[0, 1]).await.unwrap();
236 /// let subview = view.load_entry_or_insert(&[0, 1]).await.unwrap();
237 /// let value = subview.get();
238 /// assert_eq!(*value, String::default());
239 /// # })
240 /// ```
241 pub async fn load_entry_or_insert(&mut self, short_key: &[u8]) -> Result<&W, ViewError> {
242 Ok(self.do_load_entry_mut(short_key).await?)
243 }
244
245 /// Loads a subview for the data at the given index in the collection. If an entry
246 /// is absent then `None` is returned. The resulting view cannot be modified.
247 /// May fail if one subview is already being visited.
248 /// ```rust
249 /// # tokio_test::block_on(async {
250 /// # use linera_views::context::MemoryContext;
251 /// # use linera_views::collection_view::ByteCollectionView;
252 /// # use linera_views::register_view::RegisterView;
253 /// # use linera_views::views::View;
254 /// # let context = MemoryContext::new_for_testing(());
255 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
256 /// ByteCollectionView::load(context).await.unwrap();
257 /// {
258 /// let _subview = view.load_entry_or_insert(&[0, 1]).await.unwrap();
259 /// }
260 /// {
261 /// let subview = view.try_load_entry(&[0, 1]).await.unwrap().unwrap();
262 /// let value = subview.get();
263 /// assert_eq!(*value, String::default());
264 /// }
265 /// assert!(view.try_load_entry(&[0, 2]).await.unwrap().is_none());
266 /// # })
267 /// ```
268 pub async fn try_load_entry(
269 &self,
270 short_key: &[u8],
271 ) -> Result<Option<ReadGuardedView<W>>, ViewError> {
272 let mut updates = self
273 .updates
274 .try_write()
275 .ok_or(ViewError::CannotAcquireCollectionEntry)?;
276 match updates.entry(short_key.to_vec()) {
277 btree_map::Entry::Occupied(entry) => {
278 let entry = entry.into_mut();
279 match entry {
280 Update::Set(_) => {
281 let guard = RwLockWriteGuard::downgrade(updates);
282 Ok(Some(ReadGuardedView {
283 guard,
284 short_key: short_key.to_vec(),
285 }))
286 }
287 Update::Removed => Ok(None),
288 }
289 }
290 btree_map::Entry::Vacant(entry) => {
291 let key_index = self
292 .context
293 .base_key()
294 .base_tag_index(KeyTag::Index as u8, short_key);
295 if !self.delete_storage_first
296 && self.context.store().contains_key(&key_index).await?
297 {
298 let key = self
299 .context
300 .base_key()
301 .base_tag_index(KeyTag::Subview as u8, short_key);
302 let context = self.context.clone_with_base_key(key);
303 let view = W::load(context).await?;
304 entry.insert(Update::Set(view));
305 let guard = RwLockWriteGuard::downgrade(updates);
306 Ok(Some(ReadGuardedView {
307 guard,
308 short_key: short_key.to_vec(),
309 }))
310 } else {
311 Ok(None)
312 }
313 }
314 }
315 }
316
317 /// Resets an entry to the default value.
318 /// ```rust
319 /// # tokio_test::block_on(async {
320 /// # use linera_views::context::MemoryContext;
321 /// # use linera_views::collection_view::ByteCollectionView;
322 /// # use linera_views::register_view::RegisterView;
323 /// # use linera_views::views::View;
324 /// # let context = MemoryContext::new_for_testing(());
325 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
326 /// ByteCollectionView::load(context).await.unwrap();
327 /// let subview = view.load_entry_mut(&[0, 1]).await.unwrap();
328 /// let value = subview.get_mut();
329 /// *value = String::from("Hello");
330 /// view.reset_entry_to_default(&[0, 1]).unwrap();
331 /// let subview = view.load_entry_mut(&[0, 1]).await.unwrap();
332 /// let value = subview.get_mut();
333 /// assert_eq!(*value, String::default());
334 /// # })
335 /// ```
336 pub fn reset_entry_to_default(&mut self, short_key: &[u8]) -> Result<(), ViewError> {
337 let key = self
338 .context
339 .base_key()
340 .base_tag_index(KeyTag::Subview as u8, short_key);
341 let context = self.context.clone_with_base_key(key);
342 let view = W::new(context)?;
343 self.updates
344 .get_mut()
345 .insert(short_key.to_vec(), Update::Set(view));
346 Ok(())
347 }
348
349 /// Tests if the collection contains a specified key and returns a boolean.
350 /// ```rust
351 /// # tokio_test::block_on(async {
352 /// # use linera_views::context::MemoryContext;
353 /// # use linera_views::collection_view::ByteCollectionView;
354 /// # use linera_views::register_view::RegisterView;
355 /// # use linera_views::views::View;
356 /// # let context = MemoryContext::new_for_testing(());
357 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
358 /// ByteCollectionView::load(context).await.unwrap();
359 /// {
360 /// let _subview = view.load_entry_mut(&[0, 1]).await.unwrap();
361 /// }
362 /// assert!(view.contains_key(&[0, 1]).await.unwrap());
363 /// assert!(!view.contains_key(&[0, 2]).await.unwrap());
364 /// # })
365 /// ```
366 pub async fn contains_key(&self, short_key: &[u8]) -> Result<bool, ViewError> {
367 let updates = self.updates.write().await;
368 Ok(match updates.get(short_key) {
369 Some(entry) => match entry {
370 Update::Set(_view) => true,
371 _entry @ Update::Removed => false,
372 },
373 None => {
374 let key_index = self
375 .context
376 .base_key()
377 .base_tag_index(KeyTag::Index as u8, short_key);
378 !self.delete_storage_first && self.context.store().contains_key(&key_index).await?
379 }
380 })
381 }
382
383 /// Marks the entry as removed. If absent then nothing is done.
384 /// ```rust
385 /// # tokio_test::block_on(async {
386 /// # use linera_views::context::MemoryContext;
387 /// # use linera_views::collection_view::ByteCollectionView;
388 /// # use linera_views::register_view::RegisterView;
389 /// # use linera_views::views::View;
390 /// # let context = MemoryContext::new_for_testing(());
391 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
392 /// ByteCollectionView::load(context).await.unwrap();
393 /// let subview = view.load_entry_mut(&[0, 1]).await.unwrap();
394 /// let value = subview.get_mut();
395 /// assert_eq!(*value, String::default());
396 /// view.remove_entry(vec![0, 1]);
397 /// let keys = view.keys().await.unwrap();
398 /// assert_eq!(keys.len(), 0);
399 /// # })
400 /// ```
401 pub fn remove_entry(&mut self, short_key: Vec<u8>) {
402 if self.delete_storage_first {
403 // Optimization: No need to mark `short_key` for deletion as we are going to remove all the keys at once.
404 self.updates.get_mut().remove(&short_key);
405 } else {
406 self.updates.get_mut().insert(short_key, Update::Removed);
407 }
408 }
409
410 /// Gets the extra data.
411 pub fn extra(&self) -> &<W::Context as Context>::Extra {
412 self.context.extra()
413 }
414
415 async fn do_load_entry_mut(&mut self, short_key: &[u8]) -> Result<&mut W, ViewError> {
416 match self.updates.get_mut().entry(short_key.to_vec()) {
417 btree_map::Entry::Occupied(entry) => {
418 let entry = entry.into_mut();
419 match entry {
420 Update::Set(view) => Ok(view),
421 Update::Removed => {
422 let key = self
423 .context
424 .base_key()
425 .base_tag_index(KeyTag::Subview as u8, short_key);
426 let context = self.context.clone_with_base_key(key);
427 // Obtain a view and set its pending state to the default (e.g. empty) state
428 let view = W::new(context)?;
429 *entry = Update::Set(view);
430 let Update::Set(view) = entry else {
431 unreachable!();
432 };
433 Ok(view)
434 }
435 }
436 }
437 btree_map::Entry::Vacant(entry) => {
438 let key = self
439 .context
440 .base_key()
441 .base_tag_index(KeyTag::Subview as u8, short_key);
442 let context = self.context.clone_with_base_key(key);
443 let view = if self.delete_storage_first {
444 W::new(context)?
445 } else {
446 W::load(context).await?
447 };
448 let Update::Set(view) = entry.insert(Update::Set(view)) else {
449 unreachable!();
450 };
451 Ok(view)
452 }
453 }
454 }
455}
456
457impl<W: View> ByteCollectionView<W::Context, W> {
458 /// Applies a function f on each index (aka key). Keys are visited in the
459 /// lexicographic order. If the function returns false, then the loop
460 /// ends prematurely.
461 /// ```rust
462 /// # tokio_test::block_on(async {
463 /// # use linera_views::context::MemoryContext;
464 /// # use linera_views::collection_view::ByteCollectionView;
465 /// # use linera_views::register_view::RegisterView;
466 /// # use linera_views::views::View;
467 /// # let context = MemoryContext::new_for_testing(());
468 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
469 /// ByteCollectionView::load(context).await.unwrap();
470 /// view.load_entry_mut(&[0, 1]).await.unwrap();
471 /// view.load_entry_mut(&[0, 2]).await.unwrap();
472 /// let mut count = 0;
473 /// view.for_each_key_while(|_key| {
474 /// count += 1;
475 /// Ok(count < 1)
476 /// })
477 /// .await
478 /// .unwrap();
479 /// assert_eq!(count, 1);
480 /// # })
481 /// ```
482 pub async fn for_each_key_while<F>(&self, mut f: F) -> Result<(), ViewError>
483 where
484 F: FnMut(&[u8]) -> Result<bool, ViewError> + Send,
485 {
486 let updates = self.updates.write().await;
487 let mut updates = updates.iter();
488 let mut update = updates.next();
489 if !self.delete_storage_first {
490 let base = self.get_index_key(&[]);
491 for index in self
492 .context
493 .store()
494 .find_keys_by_prefix(&base)
495 .await?
496 .iterator()
497 {
498 let index = index?;
499 loop {
500 match update {
501 Some((key, value)) if key.as_slice() <= index => {
502 if let Update::Set(_) = value {
503 if !f(key)? {
504 return Ok(());
505 }
506 }
507 update = updates.next();
508 if key == index {
509 break;
510 }
511 }
512 _ => {
513 if !f(index)? {
514 return Ok(());
515 }
516 break;
517 }
518 }
519 }
520 }
521 }
522 while let Some((key, value)) = update {
523 if let Update::Set(_) = value {
524 if !f(key)? {
525 return Ok(());
526 }
527 }
528 update = updates.next();
529 }
530 Ok(())
531 }
532
533 /// Applies a function f on each index (aka key). Keys are visited in a
534 /// lexicographic order.
535 /// ```rust
536 /// # tokio_test::block_on(async {
537 /// # use linera_views::context::MemoryContext;
538 /// # use linera_views::collection_view::ByteCollectionView;
539 /// # use linera_views::register_view::RegisterView;
540 /// # use linera_views::views::View;
541 /// # let context = MemoryContext::new_for_testing(());
542 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
543 /// ByteCollectionView::load(context).await.unwrap();
544 /// view.load_entry_mut(&[0, 1]).await.unwrap();
545 /// view.load_entry_mut(&[0, 2]).await.unwrap();
546 /// let mut count = 0;
547 /// view.for_each_key(|_key| {
548 /// count += 1;
549 /// Ok(())
550 /// })
551 /// .await
552 /// .unwrap();
553 /// assert_eq!(count, 2);
554 /// # })
555 /// ```
556 pub async fn for_each_key<F>(&self, mut f: F) -> Result<(), ViewError>
557 where
558 F: FnMut(&[u8]) -> Result<(), ViewError> + Send,
559 {
560 self.for_each_key_while(|key| {
561 f(key)?;
562 Ok(true)
563 })
564 .await
565 }
566
567 /// Returns the list of keys in the collection. The order is lexicographic.
568 /// ```rust
569 /// # tokio_test::block_on(async {
570 /// # use linera_views::context::MemoryContext;
571 /// # use linera_views::collection_view::ByteCollectionView;
572 /// # use linera_views::register_view::RegisterView;
573 /// # use linera_views::views::View;
574 /// # let context = MemoryContext::new_for_testing(());
575 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
576 /// ByteCollectionView::load(context).await.unwrap();
577 /// view.load_entry_mut(&[0, 1]).await.unwrap();
578 /// view.load_entry_mut(&[0, 2]).await.unwrap();
579 /// let keys = view.keys().await.unwrap();
580 /// assert_eq!(keys, vec![vec![0, 1], vec![0, 2]]);
581 /// # })
582 /// ```
583 pub async fn keys(&self) -> Result<Vec<Vec<u8>>, ViewError> {
584 let mut keys = Vec::new();
585 self.for_each_key(|key| {
586 keys.push(key.to_vec());
587 Ok(())
588 })
589 .await?;
590 Ok(keys)
591 }
592
593 /// Returns the number of entries in the collection.
594 /// ```rust
595 /// # tokio_test::block_on(async {
596 /// # use linera_views::context::MemoryContext;
597 /// # use linera_views::collection_view::ByteCollectionView;
598 /// # use linera_views::register_view::RegisterView;
599 /// # use linera_views::views::View;
600 /// # let context = MemoryContext::new_for_testing(());
601 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
602 /// ByteCollectionView::load(context).await.unwrap();
603 /// view.load_entry_mut(&[0, 1]).await.unwrap();
604 /// view.load_entry_mut(&[0, 2]).await.unwrap();
605 /// assert_eq!(view.count().await.unwrap(), 2);
606 /// # })
607 /// ```
608 pub async fn count(&self) -> Result<usize, ViewError> {
609 let mut count = 0;
610 self.for_each_key(|_key| {
611 count += 1;
612 Ok(())
613 })
614 .await?;
615 Ok(count)
616 }
617}
618
619impl<W: HashableView> HashableView for ByteCollectionView<W::Context, W> {
620 type Hasher = sha3::Sha3_256;
621
622 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
623 #[cfg(with_metrics)]
624 let _hash_latency = metrics::COLLECTION_VIEW_HASH_RUNTIME.measure_latency();
625 let mut hasher = sha3::Sha3_256::default();
626 let keys = self.keys().await?;
627 let count = keys.len() as u32;
628 hasher.update_with_bcs_bytes(&count)?;
629 let updates = self.updates.get_mut();
630 for key in keys {
631 hasher.update_with_bytes(&key)?;
632 let hash = match updates.get_mut(&key) {
633 Some(entry) => {
634 let Update::Set(view) = entry else {
635 unreachable!();
636 };
637 view.hash_mut().await?
638 }
639 None => {
640 let key = self
641 .context
642 .base_key()
643 .base_tag_index(KeyTag::Subview as u8, &key);
644 let context = self.context.clone_with_base_key(key);
645 let mut view = W::load(context).await?;
646 view.hash_mut().await?
647 }
648 };
649 hasher.write_all(hash.as_ref())?;
650 }
651 Ok(hasher.finalize())
652 }
653
654 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
655 #[cfg(with_metrics)]
656 let _hash_latency = metrics::COLLECTION_VIEW_HASH_RUNTIME.measure_latency();
657 let mut hasher = sha3::Sha3_256::default();
658 let keys = self.keys().await?;
659 let count = keys.len() as u32;
660 hasher.update_with_bcs_bytes(&count)?;
661 let updates = self.updates.read().await;
662 for key in keys {
663 hasher.update_with_bytes(&key)?;
664 let hash = match updates.get(&key) {
665 Some(entry) => {
666 let Update::Set(view) = entry else {
667 unreachable!();
668 };
669 view.hash().await?
670 }
671 None => {
672 let key = self
673 .context
674 .base_key()
675 .base_tag_index(KeyTag::Subview as u8, &key);
676 let context = self.context.clone_with_base_key(key);
677 let view = W::load(context).await?;
678 view.hash().await?
679 }
680 };
681 hasher.write_all(hash.as_ref())?;
682 }
683 Ok(hasher.finalize())
684 }
685}
686
687/// A view that supports accessing a collection of views of the same kind, indexed by a
688/// key, one subview at a time.
689#[derive(Debug)]
690pub struct CollectionView<C, I, W> {
691 collection: ByteCollectionView<C, W>,
692 _phantom: PhantomData<I>,
693}
694
695impl<W: View, I> View for CollectionView<W::Context, I, W>
696where
697 I: Send + Sync + Serialize + DeserializeOwned,
698{
699 const NUM_INIT_KEYS: usize = ByteCollectionView::<W::Context, W>::NUM_INIT_KEYS;
700
701 type Context = W::Context;
702
703 fn context(&self) -> &Self::Context {
704 self.collection.context()
705 }
706
707 fn pre_load(context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
708 ByteCollectionView::<W::Context, W>::pre_load(context)
709 }
710
711 fn post_load(context: Self::Context, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
712 let collection = ByteCollectionView::post_load(context, values)?;
713 Ok(CollectionView {
714 collection,
715 _phantom: PhantomData,
716 })
717 }
718
719 async fn load(context: Self::Context) -> Result<Self, ViewError> {
720 Self::post_load(context, &[])
721 }
722
723 fn rollback(&mut self) {
724 self.collection.rollback()
725 }
726
727 async fn has_pending_changes(&self) -> bool {
728 self.collection.has_pending_changes().await
729 }
730
731 fn flush(&mut self, batch: &mut Batch) -> Result<bool, ViewError> {
732 self.collection.flush(batch)
733 }
734
735 fn clear(&mut self) {
736 self.collection.clear()
737 }
738}
739
740impl<I, W: ClonableView> ClonableView for CollectionView<W::Context, I, W>
741where
742 I: Send + Sync + Serialize + DeserializeOwned,
743{
744 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
745 Ok(CollectionView {
746 collection: self.collection.clone_unchecked()?,
747 _phantom: PhantomData,
748 })
749 }
750}
751
752impl<I: Serialize, W: View> CollectionView<W::Context, I, W> {
753 /// Loads a subview for the data at the given index in the collection. If an entry
754 /// is absent then a default entry is added to the collection. The resulting view
755 /// can be modified.
756 /// ```rust
757 /// # tokio_test::block_on(async {
758 /// # use linera_views::context::MemoryContext;
759 /// # use linera_views::collection_view::CollectionView;
760 /// # use linera_views::register_view::RegisterView;
761 /// # use linera_views::views::View;
762 /// # let context = MemoryContext::new_for_testing(());
763 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
764 /// CollectionView::load(context).await.unwrap();
765 /// let subview = view.load_entry_mut(&23).await.unwrap();
766 /// let value = subview.get();
767 /// assert_eq!(*value, String::default());
768 /// # })
769 /// ```
770 pub async fn load_entry_mut<Q>(&mut self, index: &Q) -> Result<&mut W, ViewError>
771 where
772 I: Borrow<Q>,
773 Q: Serialize + ?Sized,
774 {
775 let short_key = BaseKey::derive_short_key(index)?;
776 self.collection.load_entry_mut(&short_key).await
777 }
778
779 /// Loads a subview for the data at the given index in the collection. If an entry
780 /// is absent then a default entry is added to the collection. The resulting view
781 /// is read-only.
782 /// ```rust
783 /// # tokio_test::block_on(async {
784 /// # use linera_views::context::MemoryContext;
785 /// # use linera_views::collection_view::CollectionView;
786 /// # use linera_views::register_view::RegisterView;
787 /// # use linera_views::views::View;
788 /// # let context = MemoryContext::new_for_testing(());
789 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
790 /// CollectionView::load(context).await.unwrap();
791 /// view.load_entry_mut(&23).await.unwrap();
792 /// let subview = view.load_entry_or_insert(&23).await.unwrap();
793 /// let value = subview.get();
794 /// assert_eq!(*value, String::default());
795 /// # })
796 /// ```
797 pub async fn load_entry_or_insert<Q>(&mut self, index: &Q) -> Result<&W, ViewError>
798 where
799 I: Borrow<Q>,
800 Q: Serialize + ?Sized,
801 {
802 let short_key = BaseKey::derive_short_key(index)?;
803 self.collection.load_entry_or_insert(&short_key).await
804 }
805
806 /// Loads a subview for the data at the given index in the collection. If an entry
807 /// is absent then `None` is returned. The resulting view cannot be modified.
808 /// May fail if one subview is already being visited.
809 /// ```rust
810 /// # tokio_test::block_on(async {
811 /// # use linera_views::context::MemoryContext;
812 /// # use linera_views::collection_view::CollectionView;
813 /// # use linera_views::register_view::RegisterView;
814 /// # use linera_views::views::View;
815 /// # let context = MemoryContext::new_for_testing(());
816 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
817 /// CollectionView::load(context).await.unwrap();
818 /// {
819 /// let _subview = view.load_entry_or_insert(&23).await.unwrap();
820 /// }
821 /// {
822 /// let subview = view.try_load_entry(&23).await.unwrap().unwrap();
823 /// let value = subview.get();
824 /// assert_eq!(*value, String::default());
825 /// }
826 /// assert!(view.try_load_entry(&24).await.unwrap().is_none());
827 /// # })
828 /// ```
829 pub async fn try_load_entry<Q>(
830 &self,
831 index: &Q,
832 ) -> Result<Option<ReadGuardedView<W>>, ViewError>
833 where
834 I: Borrow<Q>,
835 Q: Serialize + ?Sized,
836 {
837 let short_key = BaseKey::derive_short_key(index)?;
838 self.collection.try_load_entry(&short_key).await
839 }
840
841 /// Resets an entry to the default value.
842 /// ```rust
843 /// # tokio_test::block_on(async {
844 /// # use linera_views::context::MemoryContext;
845 /// # use linera_views::collection_view::CollectionView;
846 /// # use linera_views::register_view::RegisterView;
847 /// # use linera_views::views::View;
848 /// # let context = MemoryContext::new_for_testing(());
849 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
850 /// CollectionView::load(context).await.unwrap();
851 /// let subview = view.load_entry_mut(&23).await.unwrap();
852 /// let value = subview.get_mut();
853 /// *value = String::from("Hello");
854 /// view.reset_entry_to_default(&23).unwrap();
855 /// let subview = view.load_entry_mut(&23).await.unwrap();
856 /// let value = subview.get_mut();
857 /// assert_eq!(*value, String::default());
858 /// # })
859 /// ```
860 pub fn reset_entry_to_default<Q>(&mut self, index: &Q) -> Result<(), ViewError>
861 where
862 I: Borrow<Q>,
863 Q: Serialize + ?Sized,
864 {
865 let short_key = BaseKey::derive_short_key(index)?;
866 self.collection.reset_entry_to_default(&short_key)
867 }
868
869 /// Removes an entry from the `CollectionView`. If absent nothing happens.
870 /// ```rust
871 /// # tokio_test::block_on(async {
872 /// # use linera_views::context::MemoryContext;
873 /// # use linera_views::collection_view::CollectionView;
874 /// # use linera_views::register_view::RegisterView;
875 /// # use linera_views::views::View;
876 /// # let context = MemoryContext::new_for_testing(());
877 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
878 /// CollectionView::load(context).await.unwrap();
879 /// let subview = view.load_entry_mut(&23).await.unwrap();
880 /// let value = subview.get_mut();
881 /// assert_eq!(*value, String::default());
882 /// view.remove_entry(&23);
883 /// let keys = view.indices().await.unwrap();
884 /// assert_eq!(keys.len(), 0);
885 /// # })
886 /// ```
887 pub fn remove_entry<Q>(&mut self, index: &Q) -> Result<(), ViewError>
888 where
889 I: Borrow<Q>,
890 Q: Serialize + ?Sized,
891 {
892 let short_key = BaseKey::derive_short_key(index)?;
893 self.collection.remove_entry(short_key);
894 Ok(())
895 }
896
897 /// Gets the extra data.
898 pub fn extra(&self) -> &<W::Context as Context>::Extra {
899 self.collection.extra()
900 }
901}
902
903impl<I, W: View> CollectionView<W::Context, I, W>
904where
905 I: Sync + Clone + Send + Serialize + DeserializeOwned,
906{
907 /// Returns the list of indices in the collection in the order determined by
908 /// the serialization.
909 /// ```rust
910 /// # tokio_test::block_on(async {
911 /// # use linera_views::context::MemoryContext;
912 /// # use linera_views::collection_view::CollectionView;
913 /// # use linera_views::register_view::RegisterView;
914 /// # use linera_views::views::View;
915 /// # let context = MemoryContext::new_for_testing(());
916 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
917 /// CollectionView::load(context).await.unwrap();
918 /// view.load_entry_mut(&23).await.unwrap();
919 /// view.load_entry_mut(&25).await.unwrap();
920 /// let indices = view.indices().await.unwrap();
921 /// assert_eq!(indices.len(), 2);
922 /// # })
923 /// ```
924 pub async fn indices(&self) -> Result<Vec<I>, ViewError> {
925 let mut indices = Vec::new();
926 self.for_each_index(|index| {
927 indices.push(index);
928 Ok(())
929 })
930 .await?;
931 Ok(indices)
932 }
933
934 /// Returns the number of entries in the collection.
935 /// ```rust
936 /// # tokio_test::block_on(async {
937 /// # use linera_views::context::MemoryContext;
938 /// # use linera_views::collection_view::CollectionView;
939 /// # use linera_views::register_view::RegisterView;
940 /// # use linera_views::views::View;
941 /// # let context = MemoryContext::new_for_testing(());
942 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
943 /// CollectionView::load(context).await.unwrap();
944 /// view.load_entry_mut(&23).await.unwrap();
945 /// view.load_entry_mut(&25).await.unwrap();
946 /// assert_eq!(view.count().await.unwrap(), 2);
947 /// # })
948 /// ```
949 pub async fn count(&self) -> Result<usize, ViewError> {
950 self.collection.count().await
951 }
952}
953
954impl<I: DeserializeOwned, W: View> CollectionView<W::Context, I, W> {
955 /// Applies a function f on each index. Indices are visited in an order
956 /// determined by the serialization. If the function returns false then
957 /// the loop ends prematurely.
958 /// ```rust
959 /// # tokio_test::block_on(async {
960 /// # use linera_views::context::MemoryContext;
961 /// # use linera_views::collection_view::CollectionView;
962 /// # use linera_views::register_view::RegisterView;
963 /// # use linera_views::views::View;
964 /// # let context = MemoryContext::new_for_testing(());
965 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
966 /// CollectionView::load(context).await.unwrap();
967 /// view.load_entry_mut(&23).await.unwrap();
968 /// view.load_entry_mut(&24).await.unwrap();
969 /// let mut count = 0;
970 /// view.for_each_index_while(|_key| {
971 /// count += 1;
972 /// Ok(count < 1)
973 /// })
974 /// .await
975 /// .unwrap();
976 /// assert_eq!(count, 1);
977 /// # })
978 /// ```
979 pub async fn for_each_index_while<F>(&self, mut f: F) -> Result<(), ViewError>
980 where
981 F: FnMut(I) -> Result<bool, ViewError> + Send,
982 {
983 self.collection
984 .for_each_key_while(|key| {
985 let index = BaseKey::deserialize_value(key)?;
986 f(index)
987 })
988 .await?;
989 Ok(())
990 }
991
992 /// Applies a function f on each index. Indices are visited in an order
993 /// determined by the serialization.
994 /// ```rust
995 /// # tokio_test::block_on(async {
996 /// # use linera_views::context::MemoryContext;
997 /// # use linera_views::collection_view::CollectionView;
998 /// # use linera_views::register_view::RegisterView;
999 /// # use linera_views::views::View;
1000 /// # let context = MemoryContext::new_for_testing(());
1001 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1002 /// CollectionView::load(context).await.unwrap();
1003 /// view.load_entry_mut(&23).await.unwrap();
1004 /// view.load_entry_mut(&28).await.unwrap();
1005 /// let mut count = 0;
1006 /// view.for_each_index(|_key| {
1007 /// count += 1;
1008 /// Ok(())
1009 /// })
1010 /// .await
1011 /// .unwrap();
1012 /// assert_eq!(count, 2);
1013 /// # })
1014 /// ```
1015 pub async fn for_each_index<F>(&self, mut f: F) -> Result<(), ViewError>
1016 where
1017 F: FnMut(I) -> Result<(), ViewError> + Send,
1018 {
1019 self.collection
1020 .for_each_key(|key| {
1021 let index = BaseKey::deserialize_value(key)?;
1022 f(index)
1023 })
1024 .await?;
1025 Ok(())
1026 }
1027}
1028
1029impl<I, W: HashableView> HashableView for CollectionView<W::Context, I, W>
1030where
1031 I: Clone + Send + Sync + Serialize + DeserializeOwned,
1032{
1033 type Hasher = sha3::Sha3_256;
1034
1035 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1036 self.collection.hash_mut().await
1037 }
1038
1039 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1040 self.collection.hash().await
1041 }
1042}
1043
1044/// A map view that serializes the indices.
1045#[derive(Debug)]
1046pub struct CustomCollectionView<C, I, W> {
1047 collection: ByteCollectionView<C, W>,
1048 _phantom: PhantomData<I>,
1049}
1050
1051impl<I: Send + Sync, W: View> View for CustomCollectionView<W::Context, I, W> {
1052 const NUM_INIT_KEYS: usize = ByteCollectionView::<W::Context, W>::NUM_INIT_KEYS;
1053
1054 type Context = W::Context;
1055
1056 fn context(&self) -> &Self::Context {
1057 self.collection.context()
1058 }
1059
1060 fn pre_load(context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
1061 ByteCollectionView::<_, W>::pre_load(context)
1062 }
1063
1064 fn post_load(context: Self::Context, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
1065 let collection = ByteCollectionView::post_load(context, values)?;
1066 Ok(CustomCollectionView {
1067 collection,
1068 _phantom: PhantomData,
1069 })
1070 }
1071
1072 async fn load(context: Self::Context) -> Result<Self, ViewError> {
1073 Self::post_load(context, &[])
1074 }
1075
1076 fn rollback(&mut self) {
1077 self.collection.rollback()
1078 }
1079
1080 async fn has_pending_changes(&self) -> bool {
1081 self.collection.has_pending_changes().await
1082 }
1083
1084 fn flush(&mut self, batch: &mut Batch) -> Result<bool, ViewError> {
1085 self.collection.flush(batch)
1086 }
1087
1088 fn clear(&mut self) {
1089 self.collection.clear()
1090 }
1091}
1092
1093impl<I: Send + Sync, W: ClonableView> ClonableView for CustomCollectionView<W::Context, I, W> {
1094 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
1095 Ok(CustomCollectionView {
1096 collection: self.collection.clone_unchecked()?,
1097 _phantom: PhantomData,
1098 })
1099 }
1100}
1101
1102impl<I: CustomSerialize, W: View> CustomCollectionView<W::Context, I, W> {
1103 /// Loads a subview for the data at the given index in the collection. If an entry
1104 /// is absent then a default entry is added to the collection. The resulting view
1105 /// can be modified.
1106 /// ```rust
1107 /// # tokio_test::block_on(async {
1108 /// # use linera_views::context::MemoryContext;
1109 /// # use linera_views::collection_view::CustomCollectionView;
1110 /// # use linera_views::register_view::RegisterView;
1111 /// # use linera_views::views::View;
1112 /// # let context = MemoryContext::new_for_testing(());
1113 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1114 /// CustomCollectionView::load(context).await.unwrap();
1115 /// let subview = view.load_entry_mut(&23).await.unwrap();
1116 /// let value = subview.get();
1117 /// assert_eq!(*value, String::default());
1118 /// # })
1119 /// ```
1120 pub async fn load_entry_mut<Q>(&mut self, index: &Q) -> Result<&mut W, ViewError>
1121 where
1122 I: Borrow<Q>,
1123 Q: CustomSerialize,
1124 {
1125 let short_key = index.to_custom_bytes()?;
1126 self.collection.load_entry_mut(&short_key).await
1127 }
1128
1129 /// Loads a subview for the data at the given index in the collection. If an entry
1130 /// is absent then a default entry is added to the collection. The resulting view
1131 /// is read-only.
1132 /// ```rust
1133 /// # tokio_test::block_on(async {
1134 /// # use linera_views::context::MemoryContext;
1135 /// # use linera_views::collection_view::CustomCollectionView;
1136 /// # use linera_views::register_view::RegisterView;
1137 /// # use linera_views::views::View;
1138 /// # let context = MemoryContext::new_for_testing(());
1139 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1140 /// CustomCollectionView::load(context).await.unwrap();
1141 /// view.load_entry_mut(&23).await.unwrap();
1142 /// let subview = view.load_entry_or_insert(&23).await.unwrap();
1143 /// let value = subview.get();
1144 /// assert_eq!(*value, String::default());
1145 /// # })
1146 /// ```
1147 pub async fn load_entry_or_insert<Q>(&mut self, index: &Q) -> Result<&W, ViewError>
1148 where
1149 I: Borrow<Q>,
1150 Q: CustomSerialize,
1151 {
1152 let short_key = index.to_custom_bytes()?;
1153 self.collection.load_entry_or_insert(&short_key).await
1154 }
1155
1156 /// Loads a subview for the data at the given index in the collection. If an entry
1157 /// is absent then `None` is returned. The resulting view cannot be modified.
1158 /// May fail if one subview is already being visited.
1159 /// ```rust
1160 /// # tokio_test::block_on(async {
1161 /// # use linera_views::context::MemoryContext;
1162 /// # use linera_views::collection_view::CustomCollectionView;
1163 /// # use linera_views::register_view::RegisterView;
1164 /// # use linera_views::views::View;
1165 /// # let context = MemoryContext::new_for_testing(());
1166 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1167 /// CustomCollectionView::load(context).await.unwrap();
1168 /// {
1169 /// let _subview = view.load_entry_or_insert(&23).await.unwrap();
1170 /// }
1171 /// {
1172 /// let subview = view.try_load_entry(&23).await.unwrap().unwrap();
1173 /// let value = subview.get();
1174 /// assert_eq!(*value, String::default());
1175 /// }
1176 /// assert!(view.try_load_entry(&24).await.unwrap().is_none());
1177 /// # })
1178 /// ```
1179 pub async fn try_load_entry<Q>(
1180 &self,
1181 index: &Q,
1182 ) -> Result<Option<ReadGuardedView<W>>, ViewError>
1183 where
1184 I: Borrow<Q>,
1185 Q: CustomSerialize,
1186 {
1187 let short_key = index.to_custom_bytes()?;
1188 self.collection.try_load_entry(&short_key).await
1189 }
1190
1191 /// Marks the entry so that it is removed in the next flush.
1192 /// ```rust
1193 /// # tokio_test::block_on(async {
1194 /// # use linera_views::context::MemoryContext;
1195 /// # use linera_views::collection_view::CustomCollectionView;
1196 /// # use linera_views::register_view::RegisterView;
1197 /// # use linera_views::views::View;
1198 /// # let context = MemoryContext::new_for_testing(());
1199 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1200 /// CustomCollectionView::load(context).await.unwrap();
1201 /// let subview = view.load_entry_mut(&23).await.unwrap();
1202 /// let value = subview.get_mut();
1203 /// *value = String::from("Hello");
1204 /// view.reset_entry_to_default(&23).unwrap();
1205 /// let subview = view.load_entry_mut(&23).await.unwrap();
1206 /// let value = subview.get_mut();
1207 /// assert_eq!(*value, String::default());
1208 /// # })
1209 /// ```
1210 pub fn reset_entry_to_default<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1211 where
1212 I: Borrow<Q>,
1213 Q: CustomSerialize,
1214 {
1215 let short_key = index.to_custom_bytes()?;
1216 self.collection.reset_entry_to_default(&short_key)
1217 }
1218
1219 /// Removes an entry from the `CollectionView`. If absent nothing happens.
1220 /// ```rust
1221 /// # tokio_test::block_on(async {
1222 /// # use linera_views::context::MemoryContext;
1223 /// # use linera_views::collection_view::CustomCollectionView;
1224 /// # use linera_views::register_view::RegisterView;
1225 /// # use linera_views::views::View;
1226 /// # let context = MemoryContext::new_for_testing(());
1227 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1228 /// CustomCollectionView::load(context).await.unwrap();
1229 /// let subview = view.load_entry_mut(&23).await.unwrap();
1230 /// let value = subview.get_mut();
1231 /// assert_eq!(*value, String::default());
1232 /// view.remove_entry(&23);
1233 /// let keys = view.indices().await.unwrap();
1234 /// assert_eq!(keys.len(), 0);
1235 /// # })
1236 /// ```
1237 pub fn remove_entry<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1238 where
1239 I: Borrow<Q>,
1240 Q: CustomSerialize,
1241 {
1242 let short_key = index.to_custom_bytes()?;
1243 self.collection.remove_entry(short_key);
1244 Ok(())
1245 }
1246
1247 /// Gets the extra data.
1248 pub fn extra(&self) -> &<W::Context as Context>::Extra {
1249 self.collection.extra()
1250 }
1251}
1252
1253impl<I: CustomSerialize + Send, W: View> CustomCollectionView<W::Context, I, W> {
1254 /// Returns the list of indices in the collection in the order determined by the custom serialization.
1255 /// ```rust
1256 /// # tokio_test::block_on(async {
1257 /// # use linera_views::context::MemoryContext;
1258 /// # use linera_views::collection_view::CustomCollectionView;
1259 /// # use linera_views::register_view::RegisterView;
1260 /// # use linera_views::views::View;
1261 /// # let context = MemoryContext::new_for_testing(());
1262 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1263 /// CustomCollectionView::load(context).await.unwrap();
1264 /// view.load_entry_mut(&23).await.unwrap();
1265 /// view.load_entry_mut(&25).await.unwrap();
1266 /// let indices = view.indices().await.unwrap();
1267 /// assert_eq!(indices, vec![23, 25]);
1268 /// # })
1269 /// ```
1270 pub async fn indices(&self) -> Result<Vec<I>, ViewError> {
1271 let mut indices = Vec::new();
1272 self.for_each_index(|index| {
1273 indices.push(index);
1274 Ok(())
1275 })
1276 .await?;
1277 Ok(indices)
1278 }
1279
1280 /// Returns the number of entries in the collection.
1281 /// ```rust
1282 /// # tokio_test::block_on(async {
1283 /// # use linera_views::context::MemoryContext;
1284 /// # use linera_views::collection_view::CollectionView;
1285 /// # use linera_views::register_view::RegisterView;
1286 /// # use linera_views::views::View;
1287 /// # let context = MemoryContext::new_for_testing(());
1288 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1289 /// CollectionView::load(context).await.unwrap();
1290 /// view.load_entry_mut(&23).await.unwrap();
1291 /// view.load_entry_mut(&25).await.unwrap();
1292 /// assert_eq!(view.count().await.unwrap(), 2);
1293 /// # })
1294 /// ```
1295 pub async fn count(&self) -> Result<usize, ViewError> {
1296 self.collection.count().await
1297 }
1298}
1299
1300impl<I: CustomSerialize, W: View> CustomCollectionView<W::Context, I, W> {
1301 /// Applies a function f on each index. Indices are visited in an order
1302 /// determined by the custom serialization. If the function f returns false,
1303 /// then the loop ends prematurely.
1304 /// ```rust
1305 /// # tokio_test::block_on(async {
1306 /// # use linera_views::context::MemoryContext;
1307 /// # use linera_views::collection_view::CustomCollectionView;
1308 /// # use linera_views::register_view::RegisterView;
1309 /// # use linera_views::views::View;
1310 /// # let context = MemoryContext::new_for_testing(());
1311 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1312 /// CustomCollectionView::load(context).await.unwrap();
1313 /// view.load_entry_mut(&28).await.unwrap();
1314 /// view.load_entry_mut(&24).await.unwrap();
1315 /// view.load_entry_mut(&23).await.unwrap();
1316 /// let mut part_indices = Vec::new();
1317 /// view.for_each_index_while(|index| {
1318 /// part_indices.push(index);
1319 /// Ok(part_indices.len() < 2)
1320 /// })
1321 /// .await
1322 /// .unwrap();
1323 /// assert_eq!(part_indices, vec![23, 24]);
1324 /// # })
1325 /// ```
1326 pub async fn for_each_index_while<F>(&self, mut f: F) -> Result<(), ViewError>
1327 where
1328 F: FnMut(I) -> Result<bool, ViewError> + Send,
1329 {
1330 self.collection
1331 .for_each_key_while(|key| {
1332 let index = I::from_custom_bytes(key)?;
1333 f(index)
1334 })
1335 .await?;
1336 Ok(())
1337 }
1338
1339 /// Applies a function on each index. Indices are visited in an order
1340 /// determined by the custom serialization.
1341 /// ```rust
1342 /// # tokio_test::block_on(async {
1343 /// # use linera_views::context::MemoryContext;
1344 /// # use linera_views::collection_view::CustomCollectionView;
1345 /// # use linera_views::register_view::RegisterView;
1346 /// # use linera_views::views::View;
1347 /// # let context = MemoryContext::new_for_testing(());
1348 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1349 /// CustomCollectionView::load(context).await.unwrap();
1350 /// view.load_entry_mut(&28).await.unwrap();
1351 /// view.load_entry_mut(&24).await.unwrap();
1352 /// view.load_entry_mut(&23).await.unwrap();
1353 /// let mut indices = Vec::new();
1354 /// view.for_each_index(|index| {
1355 /// indices.push(index);
1356 /// Ok(())
1357 /// })
1358 /// .await
1359 /// .unwrap();
1360 /// assert_eq!(indices, vec![23, 24, 28]);
1361 /// # })
1362 /// ```
1363 pub async fn for_each_index<F>(&self, mut f: F) -> Result<(), ViewError>
1364 where
1365 F: FnMut(I) -> Result<(), ViewError> + Send,
1366 {
1367 self.collection
1368 .for_each_key(|key| {
1369 let index = I::from_custom_bytes(key)?;
1370 f(index)
1371 })
1372 .await?;
1373 Ok(())
1374 }
1375}
1376
1377impl<I, W: HashableView> HashableView for CustomCollectionView<W::Context, I, W>
1378where
1379 Self: View,
1380{
1381 type Hasher = sha3::Sha3_256;
1382
1383 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1384 self.collection.hash_mut().await
1385 }
1386
1387 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1388 self.collection.hash().await
1389 }
1390}
1391
1392/// Type wrapping `ByteCollectionView` while memoizing the hash.
1393pub type HashedByteCollectionView<C, W> =
1394 WrappedHashableContainerView<C, ByteCollectionView<C, W>, HasherOutput>;
1395
1396/// Type wrapping `CollectionView` while memoizing the hash.
1397pub type HashedCollectionView<C, I, W> =
1398 WrappedHashableContainerView<C, CollectionView<C, I, W>, HasherOutput>;
1399
1400/// Type wrapping `CustomCollectionView` while memoizing the hash.
1401pub type HashedCustomCollectionView<C, I, W> =
1402 WrappedHashableContainerView<C, CustomCollectionView<C, I, W>, HasherOutput>;
1403
1404#[cfg(with_graphql)]
1405mod graphql {
1406 use std::borrow::Cow;
1407
1408 use super::{CollectionView, CustomCollectionView, ReadGuardedView};
1409 use crate::{
1410 graphql::{hash_name, mangle, missing_key_error, Entry, MapFilters, MapInput},
1411 views::View,
1412 };
1413
1414 impl<T: async_graphql::OutputType> async_graphql::OutputType for ReadGuardedView<'_, T> {
1415 fn type_name() -> Cow<'static, str> {
1416 T::type_name()
1417 }
1418
1419 fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
1420 T::create_type_info(registry)
1421 }
1422
1423 async fn resolve(
1424 &self,
1425 ctx: &async_graphql::ContextSelectionSet<'_>,
1426 field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
1427 ) -> async_graphql::ServerResult<async_graphql::Value> {
1428 (**self).resolve(ctx, field).await
1429 }
1430 }
1431
1432 impl<C: Send + Sync, K: async_graphql::OutputType, V: async_graphql::OutputType>
1433 async_graphql::TypeName for CollectionView<C, K, V>
1434 {
1435 fn type_name() -> Cow<'static, str> {
1436 format!(
1437 "CollectionView_{}_{}_{:08x}",
1438 mangle(K::type_name()),
1439 mangle(V::type_name()),
1440 hash_name::<(K, V)>(),
1441 )
1442 .into()
1443 }
1444 }
1445
1446 #[async_graphql::Object(cache_control(no_cache), name_type)]
1447 impl<K, V> CollectionView<V::Context, K, V>
1448 where
1449 K: async_graphql::InputType
1450 + async_graphql::OutputType
1451 + serde::ser::Serialize
1452 + serde::de::DeserializeOwned
1453 + std::fmt::Debug
1454 + Clone,
1455 V: View + async_graphql::OutputType,
1456 MapInput<K>: async_graphql::InputType,
1457 MapFilters<K>: async_graphql::InputType,
1458 {
1459 async fn keys(&self) -> Result<Vec<K>, async_graphql::Error> {
1460 Ok(self.indices().await?)
1461 }
1462
1463 async fn entry(
1464 &self,
1465 key: K,
1466 ) -> Result<Entry<K, ReadGuardedView<V>>, async_graphql::Error> {
1467 let value = self
1468 .try_load_entry(&key)
1469 .await?
1470 .ok_or_else(|| missing_key_error(&key))?;
1471 Ok(Entry { value, key })
1472 }
1473
1474 async fn entries(
1475 &self,
1476 input: Option<MapInput<K>>,
1477 ) -> Result<Vec<Entry<K, ReadGuardedView<V>>>, async_graphql::Error> {
1478 let keys = if let Some(keys) = input
1479 .and_then(|input| input.filters)
1480 .and_then(|filters| filters.keys)
1481 {
1482 keys
1483 } else {
1484 self.indices().await?
1485 };
1486
1487 let mut values = vec![];
1488 for key in keys {
1489 let value = self
1490 .try_load_entry(&key)
1491 .await?
1492 .ok_or_else(|| missing_key_error(&key))?;
1493 values.push(Entry { value, key })
1494 }
1495
1496 Ok(values)
1497 }
1498 }
1499
1500 impl<C: Send + Sync, K: async_graphql::InputType, V: async_graphql::OutputType>
1501 async_graphql::TypeName for CustomCollectionView<C, K, V>
1502 {
1503 fn type_name() -> Cow<'static, str> {
1504 format!(
1505 "CustomCollectionView_{}_{}_{:08x}",
1506 mangle(K::type_name()),
1507 mangle(V::type_name()),
1508 hash_name::<(K, V)>(),
1509 )
1510 .into()
1511 }
1512 }
1513
1514 #[async_graphql::Object(cache_control(no_cache), name_type)]
1515 impl<K, V> CustomCollectionView<V::Context, K, V>
1516 where
1517 K: async_graphql::InputType
1518 + async_graphql::OutputType
1519 + crate::common::CustomSerialize
1520 + std::fmt::Debug,
1521 V: View + async_graphql::OutputType,
1522 MapInput<K>: async_graphql::InputType,
1523 MapFilters<K>: async_graphql::InputType,
1524 {
1525 async fn keys(&self) -> Result<Vec<K>, async_graphql::Error> {
1526 Ok(self.indices().await?)
1527 }
1528
1529 async fn entry(
1530 &self,
1531 key: K,
1532 ) -> Result<Entry<K, ReadGuardedView<V>>, async_graphql::Error> {
1533 let value = self
1534 .try_load_entry(&key)
1535 .await?
1536 .ok_or_else(|| missing_key_error(&key))?;
1537 Ok(Entry { value, key })
1538 }
1539
1540 async fn entries(
1541 &self,
1542 input: Option<MapInput<K>>,
1543 ) -> Result<Vec<Entry<K, ReadGuardedView<V>>>, async_graphql::Error> {
1544 let keys = if let Some(keys) = input
1545 .and_then(|input| input.filters)
1546 .and_then(|filters| filters.keys)
1547 {
1548 keys
1549 } else {
1550 self.indices().await?
1551 };
1552
1553 let mut values = vec![];
1554 for key in keys {
1555 let value = self
1556 .try_load_entry(&key)
1557 .await?
1558 .ok_or_else(|| missing_key_error(&key))?;
1559 values.push(Entry { value, key })
1560 }
1561
1562 Ok(values)
1563 }
1564 }
1565}