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::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.context.store().find_keys_by_prefix(&base).await? {
492 loop {
493 match update {
494 Some((key, value)) if key <= &index => {
495 if let Update::Set(_) = value {
496 if !f(key)? {
497 return Ok(());
498 }
499 }
500 update = updates.next();
501 if key == &index {
502 break;
503 }
504 }
505 _ => {
506 if !f(&index)? {
507 return Ok(());
508 }
509 break;
510 }
511 }
512 }
513 }
514 }
515 while let Some((key, value)) = update {
516 if let Update::Set(_) = value {
517 if !f(key)? {
518 return Ok(());
519 }
520 }
521 update = updates.next();
522 }
523 Ok(())
524 }
525
526 /// Applies a function f on each index (aka key). Keys are visited in a
527 /// lexicographic order.
528 /// ```rust
529 /// # tokio_test::block_on(async {
530 /// # use linera_views::context::MemoryContext;
531 /// # use linera_views::collection_view::ByteCollectionView;
532 /// # use linera_views::register_view::RegisterView;
533 /// # use linera_views::views::View;
534 /// # let context = MemoryContext::new_for_testing(());
535 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
536 /// ByteCollectionView::load(context).await.unwrap();
537 /// view.load_entry_mut(&[0, 1]).await.unwrap();
538 /// view.load_entry_mut(&[0, 2]).await.unwrap();
539 /// let mut count = 0;
540 /// view.for_each_key(|_key| {
541 /// count += 1;
542 /// Ok(())
543 /// })
544 /// .await
545 /// .unwrap();
546 /// assert_eq!(count, 2);
547 /// # })
548 /// ```
549 pub async fn for_each_key<F>(&self, mut f: F) -> Result<(), ViewError>
550 where
551 F: FnMut(&[u8]) -> Result<(), ViewError> + Send,
552 {
553 self.for_each_key_while(|key| {
554 f(key)?;
555 Ok(true)
556 })
557 .await
558 }
559
560 /// Returns the list of keys in the collection. The order is lexicographic.
561 /// ```rust
562 /// # tokio_test::block_on(async {
563 /// # use linera_views::context::MemoryContext;
564 /// # use linera_views::collection_view::ByteCollectionView;
565 /// # use linera_views::register_view::RegisterView;
566 /// # use linera_views::views::View;
567 /// # let context = MemoryContext::new_for_testing(());
568 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
569 /// ByteCollectionView::load(context).await.unwrap();
570 /// view.load_entry_mut(&[0, 1]).await.unwrap();
571 /// view.load_entry_mut(&[0, 2]).await.unwrap();
572 /// let keys = view.keys().await.unwrap();
573 /// assert_eq!(keys, vec![vec![0, 1], vec![0, 2]]);
574 /// # })
575 /// ```
576 pub async fn keys(&self) -> Result<Vec<Vec<u8>>, ViewError> {
577 let mut keys = Vec::new();
578 self.for_each_key(|key| {
579 keys.push(key.to_vec());
580 Ok(())
581 })
582 .await?;
583 Ok(keys)
584 }
585
586 /// Returns the number of entries in the collection.
587 /// ```rust
588 /// # tokio_test::block_on(async {
589 /// # use linera_views::context::MemoryContext;
590 /// # use linera_views::collection_view::ByteCollectionView;
591 /// # use linera_views::register_view::RegisterView;
592 /// # use linera_views::views::View;
593 /// # let context = MemoryContext::new_for_testing(());
594 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
595 /// ByteCollectionView::load(context).await.unwrap();
596 /// view.load_entry_mut(&[0, 1]).await.unwrap();
597 /// view.load_entry_mut(&[0, 2]).await.unwrap();
598 /// assert_eq!(view.count().await.unwrap(), 2);
599 /// # })
600 /// ```
601 pub async fn count(&self) -> Result<usize, ViewError> {
602 let mut count = 0;
603 self.for_each_key(|_key| {
604 count += 1;
605 Ok(())
606 })
607 .await?;
608 Ok(count)
609 }
610}
611
612impl<W: HashableView> HashableView for ByteCollectionView<W::Context, W> {
613 type Hasher = sha3::Sha3_256;
614
615 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
616 #[cfg(with_metrics)]
617 let _hash_latency = metrics::COLLECTION_VIEW_HASH_RUNTIME.measure_latency();
618 let mut hasher = sha3::Sha3_256::default();
619 let keys = self.keys().await?;
620 let count = keys.len() as u32;
621 hasher.update_with_bcs_bytes(&count)?;
622 let updates = self.updates.get_mut();
623 for key in keys {
624 hasher.update_with_bytes(&key)?;
625 let hash = match updates.get_mut(&key) {
626 Some(entry) => {
627 let Update::Set(view) = entry else {
628 unreachable!();
629 };
630 view.hash_mut().await?
631 }
632 None => {
633 let key = self
634 .context
635 .base_key()
636 .base_tag_index(KeyTag::Subview as u8, &key);
637 let context = self.context.clone_with_base_key(key);
638 let mut view = W::load(context).await?;
639 view.hash_mut().await?
640 }
641 };
642 hasher.write_all(hash.as_ref())?;
643 }
644 Ok(hasher.finalize())
645 }
646
647 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
648 #[cfg(with_metrics)]
649 let _hash_latency = metrics::COLLECTION_VIEW_HASH_RUNTIME.measure_latency();
650 let mut hasher = sha3::Sha3_256::default();
651 let keys = self.keys().await?;
652 let count = keys.len() as u32;
653 hasher.update_with_bcs_bytes(&count)?;
654 let updates = self.updates.read().await;
655 for key in keys {
656 hasher.update_with_bytes(&key)?;
657 let hash = match updates.get(&key) {
658 Some(entry) => {
659 let Update::Set(view) = entry else {
660 unreachable!();
661 };
662 view.hash().await?
663 }
664 None => {
665 let key = self
666 .context
667 .base_key()
668 .base_tag_index(KeyTag::Subview as u8, &key);
669 let context = self.context.clone_with_base_key(key);
670 let view = W::load(context).await?;
671 view.hash().await?
672 }
673 };
674 hasher.write_all(hash.as_ref())?;
675 }
676 Ok(hasher.finalize())
677 }
678}
679
680/// A view that supports accessing a collection of views of the same kind, indexed by a
681/// key, one subview at a time.
682#[derive(Debug)]
683pub struct CollectionView<C, I, W> {
684 collection: ByteCollectionView<C, W>,
685 _phantom: PhantomData<I>,
686}
687
688impl<W: View, I> View for CollectionView<W::Context, I, W>
689where
690 I: Send + Sync + Serialize + DeserializeOwned,
691{
692 const NUM_INIT_KEYS: usize = ByteCollectionView::<W::Context, W>::NUM_INIT_KEYS;
693
694 type Context = W::Context;
695
696 fn context(&self) -> &Self::Context {
697 self.collection.context()
698 }
699
700 fn pre_load(context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
701 ByteCollectionView::<W::Context, W>::pre_load(context)
702 }
703
704 fn post_load(context: Self::Context, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
705 let collection = ByteCollectionView::post_load(context, values)?;
706 Ok(CollectionView {
707 collection,
708 _phantom: PhantomData,
709 })
710 }
711
712 async fn load(context: Self::Context) -> Result<Self, ViewError> {
713 Self::post_load(context, &[])
714 }
715
716 fn rollback(&mut self) {
717 self.collection.rollback()
718 }
719
720 async fn has_pending_changes(&self) -> bool {
721 self.collection.has_pending_changes().await
722 }
723
724 fn flush(&mut self, batch: &mut Batch) -> Result<bool, ViewError> {
725 self.collection.flush(batch)
726 }
727
728 fn clear(&mut self) {
729 self.collection.clear()
730 }
731}
732
733impl<I, W: ClonableView> ClonableView for CollectionView<W::Context, I, W>
734where
735 I: Send + Sync + Serialize + DeserializeOwned,
736{
737 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
738 Ok(CollectionView {
739 collection: self.collection.clone_unchecked()?,
740 _phantom: PhantomData,
741 })
742 }
743}
744
745impl<I: Serialize, W: View> CollectionView<W::Context, I, W> {
746 /// Loads a subview for the data at the given index in the collection. If an entry
747 /// is absent then a default entry is added to the collection. The resulting view
748 /// can be modified.
749 /// ```rust
750 /// # tokio_test::block_on(async {
751 /// # use linera_views::context::MemoryContext;
752 /// # use linera_views::collection_view::CollectionView;
753 /// # use linera_views::register_view::RegisterView;
754 /// # use linera_views::views::View;
755 /// # let context = MemoryContext::new_for_testing(());
756 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
757 /// CollectionView::load(context).await.unwrap();
758 /// let subview = view.load_entry_mut(&23).await.unwrap();
759 /// let value = subview.get();
760 /// assert_eq!(*value, String::default());
761 /// # })
762 /// ```
763 pub async fn load_entry_mut<Q>(&mut self, index: &Q) -> Result<&mut W, ViewError>
764 where
765 I: Borrow<Q>,
766 Q: Serialize + ?Sized,
767 {
768 let short_key = BaseKey::derive_short_key(index)?;
769 self.collection.load_entry_mut(&short_key).await
770 }
771
772 /// Loads a subview for the data at the given index in the collection. If an entry
773 /// is absent then a default entry is added to the collection. The resulting view
774 /// is read-only.
775 /// ```rust
776 /// # tokio_test::block_on(async {
777 /// # use linera_views::context::MemoryContext;
778 /// # use linera_views::collection_view::CollectionView;
779 /// # use linera_views::register_view::RegisterView;
780 /// # use linera_views::views::View;
781 /// # let context = MemoryContext::new_for_testing(());
782 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
783 /// CollectionView::load(context).await.unwrap();
784 /// view.load_entry_mut(&23).await.unwrap();
785 /// let subview = view.load_entry_or_insert(&23).await.unwrap();
786 /// let value = subview.get();
787 /// assert_eq!(*value, String::default());
788 /// # })
789 /// ```
790 pub async fn load_entry_or_insert<Q>(&mut self, index: &Q) -> Result<&W, ViewError>
791 where
792 I: Borrow<Q>,
793 Q: Serialize + ?Sized,
794 {
795 let short_key = BaseKey::derive_short_key(index)?;
796 self.collection.load_entry_or_insert(&short_key).await
797 }
798
799 /// Loads a subview for the data at the given index in the collection. If an entry
800 /// is absent then `None` is returned. The resulting view cannot be modified.
801 /// May fail if one subview is already being visited.
802 /// ```rust
803 /// # tokio_test::block_on(async {
804 /// # use linera_views::context::MemoryContext;
805 /// # use linera_views::collection_view::CollectionView;
806 /// # use linera_views::register_view::RegisterView;
807 /// # use linera_views::views::View;
808 /// # let context = MemoryContext::new_for_testing(());
809 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
810 /// CollectionView::load(context).await.unwrap();
811 /// {
812 /// let _subview = view.load_entry_or_insert(&23).await.unwrap();
813 /// }
814 /// {
815 /// let subview = view.try_load_entry(&23).await.unwrap().unwrap();
816 /// let value = subview.get();
817 /// assert_eq!(*value, String::default());
818 /// }
819 /// assert!(view.try_load_entry(&24).await.unwrap().is_none());
820 /// # })
821 /// ```
822 pub async fn try_load_entry<Q>(
823 &self,
824 index: &Q,
825 ) -> Result<Option<ReadGuardedView<W>>, ViewError>
826 where
827 I: Borrow<Q>,
828 Q: Serialize + ?Sized,
829 {
830 let short_key = BaseKey::derive_short_key(index)?;
831 self.collection.try_load_entry(&short_key).await
832 }
833
834 /// Resets an entry to the default value.
835 /// ```rust
836 /// # tokio_test::block_on(async {
837 /// # use linera_views::context::MemoryContext;
838 /// # use linera_views::collection_view::CollectionView;
839 /// # use linera_views::register_view::RegisterView;
840 /// # use linera_views::views::View;
841 /// # let context = MemoryContext::new_for_testing(());
842 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
843 /// CollectionView::load(context).await.unwrap();
844 /// let subview = view.load_entry_mut(&23).await.unwrap();
845 /// let value = subview.get_mut();
846 /// *value = String::from("Hello");
847 /// view.reset_entry_to_default(&23).unwrap();
848 /// let subview = view.load_entry_mut(&23).await.unwrap();
849 /// let value = subview.get_mut();
850 /// assert_eq!(*value, String::default());
851 /// # })
852 /// ```
853 pub fn reset_entry_to_default<Q>(&mut self, index: &Q) -> Result<(), ViewError>
854 where
855 I: Borrow<Q>,
856 Q: Serialize + ?Sized,
857 {
858 let short_key = BaseKey::derive_short_key(index)?;
859 self.collection.reset_entry_to_default(&short_key)
860 }
861
862 /// Removes an entry from the `CollectionView`. If absent nothing happens.
863 /// ```rust
864 /// # tokio_test::block_on(async {
865 /// # use linera_views::context::MemoryContext;
866 /// # use linera_views::collection_view::CollectionView;
867 /// # use linera_views::register_view::RegisterView;
868 /// # use linera_views::views::View;
869 /// # let context = MemoryContext::new_for_testing(());
870 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
871 /// CollectionView::load(context).await.unwrap();
872 /// let subview = view.load_entry_mut(&23).await.unwrap();
873 /// let value = subview.get_mut();
874 /// assert_eq!(*value, String::default());
875 /// view.remove_entry(&23);
876 /// let keys = view.indices().await.unwrap();
877 /// assert_eq!(keys.len(), 0);
878 /// # })
879 /// ```
880 pub fn remove_entry<Q>(&mut self, index: &Q) -> Result<(), ViewError>
881 where
882 I: Borrow<Q>,
883 Q: Serialize + ?Sized,
884 {
885 let short_key = BaseKey::derive_short_key(index)?;
886 self.collection.remove_entry(short_key);
887 Ok(())
888 }
889
890 /// Gets the extra data.
891 pub fn extra(&self) -> &<W::Context as Context>::Extra {
892 self.collection.extra()
893 }
894}
895
896impl<I, W: View> CollectionView<W::Context, I, W>
897where
898 I: Sync + Clone + Send + Serialize + DeserializeOwned,
899{
900 /// Returns the list of indices in the collection in the order determined by
901 /// the serialization.
902 /// ```rust
903 /// # tokio_test::block_on(async {
904 /// # use linera_views::context::MemoryContext;
905 /// # use linera_views::collection_view::CollectionView;
906 /// # use linera_views::register_view::RegisterView;
907 /// # use linera_views::views::View;
908 /// # let context = MemoryContext::new_for_testing(());
909 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
910 /// CollectionView::load(context).await.unwrap();
911 /// view.load_entry_mut(&23).await.unwrap();
912 /// view.load_entry_mut(&25).await.unwrap();
913 /// let indices = view.indices().await.unwrap();
914 /// assert_eq!(indices.len(), 2);
915 /// # })
916 /// ```
917 pub async fn indices(&self) -> Result<Vec<I>, ViewError> {
918 let mut indices = Vec::new();
919 self.for_each_index(|index| {
920 indices.push(index);
921 Ok(())
922 })
923 .await?;
924 Ok(indices)
925 }
926
927 /// Returns the number of entries in the collection.
928 /// ```rust
929 /// # tokio_test::block_on(async {
930 /// # use linera_views::context::MemoryContext;
931 /// # use linera_views::collection_view::CollectionView;
932 /// # use linera_views::register_view::RegisterView;
933 /// # use linera_views::views::View;
934 /// # let context = MemoryContext::new_for_testing(());
935 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
936 /// CollectionView::load(context).await.unwrap();
937 /// view.load_entry_mut(&23).await.unwrap();
938 /// view.load_entry_mut(&25).await.unwrap();
939 /// assert_eq!(view.count().await.unwrap(), 2);
940 /// # })
941 /// ```
942 pub async fn count(&self) -> Result<usize, ViewError> {
943 self.collection.count().await
944 }
945}
946
947impl<I: DeserializeOwned, W: View> CollectionView<W::Context, I, W> {
948 /// Applies a function f on each index. Indices are visited in an order
949 /// determined by the serialization. If the function returns false then
950 /// the loop ends prematurely.
951 /// ```rust
952 /// # tokio_test::block_on(async {
953 /// # use linera_views::context::MemoryContext;
954 /// # use linera_views::collection_view::CollectionView;
955 /// # use linera_views::register_view::RegisterView;
956 /// # use linera_views::views::View;
957 /// # let context = MemoryContext::new_for_testing(());
958 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
959 /// CollectionView::load(context).await.unwrap();
960 /// view.load_entry_mut(&23).await.unwrap();
961 /// view.load_entry_mut(&24).await.unwrap();
962 /// let mut count = 0;
963 /// view.for_each_index_while(|_key| {
964 /// count += 1;
965 /// Ok(count < 1)
966 /// })
967 /// .await
968 /// .unwrap();
969 /// assert_eq!(count, 1);
970 /// # })
971 /// ```
972 pub async fn for_each_index_while<F>(&self, mut f: F) -> Result<(), ViewError>
973 where
974 F: FnMut(I) -> Result<bool, ViewError> + Send,
975 {
976 self.collection
977 .for_each_key_while(|key| {
978 let index = BaseKey::deserialize_value(key)?;
979 f(index)
980 })
981 .await?;
982 Ok(())
983 }
984
985 /// Applies a function f on each index. Indices are visited in an order
986 /// determined by the serialization.
987 /// ```rust
988 /// # tokio_test::block_on(async {
989 /// # use linera_views::context::MemoryContext;
990 /// # use linera_views::collection_view::CollectionView;
991 /// # use linera_views::register_view::RegisterView;
992 /// # use linera_views::views::View;
993 /// # let context = MemoryContext::new_for_testing(());
994 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
995 /// CollectionView::load(context).await.unwrap();
996 /// view.load_entry_mut(&23).await.unwrap();
997 /// view.load_entry_mut(&28).await.unwrap();
998 /// let mut count = 0;
999 /// view.for_each_index(|_key| {
1000 /// count += 1;
1001 /// Ok(())
1002 /// })
1003 /// .await
1004 /// .unwrap();
1005 /// assert_eq!(count, 2);
1006 /// # })
1007 /// ```
1008 pub async fn for_each_index<F>(&self, mut f: F) -> Result<(), ViewError>
1009 where
1010 F: FnMut(I) -> Result<(), ViewError> + Send,
1011 {
1012 self.collection
1013 .for_each_key(|key| {
1014 let index = BaseKey::deserialize_value(key)?;
1015 f(index)
1016 })
1017 .await?;
1018 Ok(())
1019 }
1020}
1021
1022impl<I, W: HashableView> HashableView for CollectionView<W::Context, I, W>
1023where
1024 I: Clone + Send + Sync + Serialize + DeserializeOwned,
1025{
1026 type Hasher = sha3::Sha3_256;
1027
1028 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1029 self.collection.hash_mut().await
1030 }
1031
1032 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1033 self.collection.hash().await
1034 }
1035}
1036
1037/// A map view that serializes the indices.
1038#[derive(Debug)]
1039pub struct CustomCollectionView<C, I, W> {
1040 collection: ByteCollectionView<C, W>,
1041 _phantom: PhantomData<I>,
1042}
1043
1044impl<I: Send + Sync, W: View> View for CustomCollectionView<W::Context, I, W> {
1045 const NUM_INIT_KEYS: usize = ByteCollectionView::<W::Context, W>::NUM_INIT_KEYS;
1046
1047 type Context = W::Context;
1048
1049 fn context(&self) -> &Self::Context {
1050 self.collection.context()
1051 }
1052
1053 fn pre_load(context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
1054 ByteCollectionView::<_, W>::pre_load(context)
1055 }
1056
1057 fn post_load(context: Self::Context, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
1058 let collection = ByteCollectionView::post_load(context, values)?;
1059 Ok(CustomCollectionView {
1060 collection,
1061 _phantom: PhantomData,
1062 })
1063 }
1064
1065 async fn load(context: Self::Context) -> Result<Self, ViewError> {
1066 Self::post_load(context, &[])
1067 }
1068
1069 fn rollback(&mut self) {
1070 self.collection.rollback()
1071 }
1072
1073 async fn has_pending_changes(&self) -> bool {
1074 self.collection.has_pending_changes().await
1075 }
1076
1077 fn flush(&mut self, batch: &mut Batch) -> Result<bool, ViewError> {
1078 self.collection.flush(batch)
1079 }
1080
1081 fn clear(&mut self) {
1082 self.collection.clear()
1083 }
1084}
1085
1086impl<I: Send + Sync, W: ClonableView> ClonableView for CustomCollectionView<W::Context, I, W> {
1087 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
1088 Ok(CustomCollectionView {
1089 collection: self.collection.clone_unchecked()?,
1090 _phantom: PhantomData,
1091 })
1092 }
1093}
1094
1095impl<I: CustomSerialize, W: View> CustomCollectionView<W::Context, I, W> {
1096 /// Loads a subview for the data at the given index in the collection. If an entry
1097 /// is absent then a default entry is added to the collection. The resulting view
1098 /// can be modified.
1099 /// ```rust
1100 /// # tokio_test::block_on(async {
1101 /// # use linera_views::context::MemoryContext;
1102 /// # use linera_views::collection_view::CustomCollectionView;
1103 /// # use linera_views::register_view::RegisterView;
1104 /// # use linera_views::views::View;
1105 /// # let context = MemoryContext::new_for_testing(());
1106 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1107 /// CustomCollectionView::load(context).await.unwrap();
1108 /// let subview = view.load_entry_mut(&23).await.unwrap();
1109 /// let value = subview.get();
1110 /// assert_eq!(*value, String::default());
1111 /// # })
1112 /// ```
1113 pub async fn load_entry_mut<Q>(&mut self, index: &Q) -> Result<&mut W, ViewError>
1114 where
1115 I: Borrow<Q>,
1116 Q: CustomSerialize,
1117 {
1118 let short_key = index.to_custom_bytes()?;
1119 self.collection.load_entry_mut(&short_key).await
1120 }
1121
1122 /// Loads a subview for the data at the given index in the collection. If an entry
1123 /// is absent then a default entry is added to the collection. The resulting view
1124 /// is read-only.
1125 /// ```rust
1126 /// # tokio_test::block_on(async {
1127 /// # use linera_views::context::MemoryContext;
1128 /// # use linera_views::collection_view::CustomCollectionView;
1129 /// # use linera_views::register_view::RegisterView;
1130 /// # use linera_views::views::View;
1131 /// # let context = MemoryContext::new_for_testing(());
1132 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1133 /// CustomCollectionView::load(context).await.unwrap();
1134 /// view.load_entry_mut(&23).await.unwrap();
1135 /// let subview = view.load_entry_or_insert(&23).await.unwrap();
1136 /// let value = subview.get();
1137 /// assert_eq!(*value, String::default());
1138 /// # })
1139 /// ```
1140 pub async fn load_entry_or_insert<Q>(&mut self, index: &Q) -> Result<&W, ViewError>
1141 where
1142 I: Borrow<Q>,
1143 Q: CustomSerialize,
1144 {
1145 let short_key = index.to_custom_bytes()?;
1146 self.collection.load_entry_or_insert(&short_key).await
1147 }
1148
1149 /// Loads a subview for the data at the given index in the collection. If an entry
1150 /// is absent then `None` is returned. The resulting view cannot be modified.
1151 /// May fail if one subview is already being visited.
1152 /// ```rust
1153 /// # tokio_test::block_on(async {
1154 /// # use linera_views::context::MemoryContext;
1155 /// # use linera_views::collection_view::CustomCollectionView;
1156 /// # use linera_views::register_view::RegisterView;
1157 /// # use linera_views::views::View;
1158 /// # let context = MemoryContext::new_for_testing(());
1159 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1160 /// CustomCollectionView::load(context).await.unwrap();
1161 /// {
1162 /// let _subview = view.load_entry_or_insert(&23).await.unwrap();
1163 /// }
1164 /// {
1165 /// let subview = view.try_load_entry(&23).await.unwrap().unwrap();
1166 /// let value = subview.get();
1167 /// assert_eq!(*value, String::default());
1168 /// }
1169 /// assert!(view.try_load_entry(&24).await.unwrap().is_none());
1170 /// # })
1171 /// ```
1172 pub async fn try_load_entry<Q>(
1173 &self,
1174 index: &Q,
1175 ) -> Result<Option<ReadGuardedView<W>>, ViewError>
1176 where
1177 I: Borrow<Q>,
1178 Q: CustomSerialize,
1179 {
1180 let short_key = index.to_custom_bytes()?;
1181 self.collection.try_load_entry(&short_key).await
1182 }
1183
1184 /// Marks the entry so that it is removed in the next flush.
1185 /// ```rust
1186 /// # tokio_test::block_on(async {
1187 /// # use linera_views::context::MemoryContext;
1188 /// # use linera_views::collection_view::CustomCollectionView;
1189 /// # use linera_views::register_view::RegisterView;
1190 /// # use linera_views::views::View;
1191 /// # let context = MemoryContext::new_for_testing(());
1192 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1193 /// CustomCollectionView::load(context).await.unwrap();
1194 /// let subview = view.load_entry_mut(&23).await.unwrap();
1195 /// let value = subview.get_mut();
1196 /// *value = String::from("Hello");
1197 /// view.reset_entry_to_default(&23).unwrap();
1198 /// let subview = view.load_entry_mut(&23).await.unwrap();
1199 /// let value = subview.get_mut();
1200 /// assert_eq!(*value, String::default());
1201 /// # })
1202 /// ```
1203 pub fn reset_entry_to_default<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1204 where
1205 I: Borrow<Q>,
1206 Q: CustomSerialize,
1207 {
1208 let short_key = index.to_custom_bytes()?;
1209 self.collection.reset_entry_to_default(&short_key)
1210 }
1211
1212 /// Removes an entry from the `CollectionView`. If absent nothing happens.
1213 /// ```rust
1214 /// # tokio_test::block_on(async {
1215 /// # use linera_views::context::MemoryContext;
1216 /// # use linera_views::collection_view::CustomCollectionView;
1217 /// # use linera_views::register_view::RegisterView;
1218 /// # use linera_views::views::View;
1219 /// # let context = MemoryContext::new_for_testing(());
1220 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1221 /// CustomCollectionView::load(context).await.unwrap();
1222 /// let subview = view.load_entry_mut(&23).await.unwrap();
1223 /// let value = subview.get_mut();
1224 /// assert_eq!(*value, String::default());
1225 /// view.remove_entry(&23);
1226 /// let keys = view.indices().await.unwrap();
1227 /// assert_eq!(keys.len(), 0);
1228 /// # })
1229 /// ```
1230 pub fn remove_entry<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1231 where
1232 I: Borrow<Q>,
1233 Q: CustomSerialize,
1234 {
1235 let short_key = index.to_custom_bytes()?;
1236 self.collection.remove_entry(short_key);
1237 Ok(())
1238 }
1239
1240 /// Gets the extra data.
1241 pub fn extra(&self) -> &<W::Context as Context>::Extra {
1242 self.collection.extra()
1243 }
1244}
1245
1246impl<I: CustomSerialize + Send, W: View> CustomCollectionView<W::Context, I, W> {
1247 /// Returns the list of indices in the collection in the order determined by the custom serialization.
1248 /// ```rust
1249 /// # tokio_test::block_on(async {
1250 /// # use linera_views::context::MemoryContext;
1251 /// # use linera_views::collection_view::CustomCollectionView;
1252 /// # use linera_views::register_view::RegisterView;
1253 /// # use linera_views::views::View;
1254 /// # let context = MemoryContext::new_for_testing(());
1255 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1256 /// CustomCollectionView::load(context).await.unwrap();
1257 /// view.load_entry_mut(&23).await.unwrap();
1258 /// view.load_entry_mut(&25).await.unwrap();
1259 /// let indices = view.indices().await.unwrap();
1260 /// assert_eq!(indices, vec![23, 25]);
1261 /// # })
1262 /// ```
1263 pub async fn indices(&self) -> Result<Vec<I>, ViewError> {
1264 let mut indices = Vec::new();
1265 self.for_each_index(|index| {
1266 indices.push(index);
1267 Ok(())
1268 })
1269 .await?;
1270 Ok(indices)
1271 }
1272
1273 /// Returns the number of entries in the collection.
1274 /// ```rust
1275 /// # tokio_test::block_on(async {
1276 /// # use linera_views::context::MemoryContext;
1277 /// # use linera_views::collection_view::CollectionView;
1278 /// # use linera_views::register_view::RegisterView;
1279 /// # use linera_views::views::View;
1280 /// # let context = MemoryContext::new_for_testing(());
1281 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1282 /// CollectionView::load(context).await.unwrap();
1283 /// view.load_entry_mut(&23).await.unwrap();
1284 /// view.load_entry_mut(&25).await.unwrap();
1285 /// assert_eq!(view.count().await.unwrap(), 2);
1286 /// # })
1287 /// ```
1288 pub async fn count(&self) -> Result<usize, ViewError> {
1289 self.collection.count().await
1290 }
1291}
1292
1293impl<I: CustomSerialize, W: View> CustomCollectionView<W::Context, I, W> {
1294 /// Applies a function f on each index. Indices are visited in an order
1295 /// determined by the custom serialization. If the function f returns false,
1296 /// then the loop ends prematurely.
1297 /// ```rust
1298 /// # tokio_test::block_on(async {
1299 /// # use linera_views::context::MemoryContext;
1300 /// # use linera_views::collection_view::CustomCollectionView;
1301 /// # use linera_views::register_view::RegisterView;
1302 /// # use linera_views::views::View;
1303 /// # let context = MemoryContext::new_for_testing(());
1304 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1305 /// CustomCollectionView::load(context).await.unwrap();
1306 /// view.load_entry_mut(&28).await.unwrap();
1307 /// view.load_entry_mut(&24).await.unwrap();
1308 /// view.load_entry_mut(&23).await.unwrap();
1309 /// let mut part_indices = Vec::new();
1310 /// view.for_each_index_while(|index| {
1311 /// part_indices.push(index);
1312 /// Ok(part_indices.len() < 2)
1313 /// })
1314 /// .await
1315 /// .unwrap();
1316 /// assert_eq!(part_indices, vec![23, 24]);
1317 /// # })
1318 /// ```
1319 pub async fn for_each_index_while<F>(&self, mut f: F) -> Result<(), ViewError>
1320 where
1321 F: FnMut(I) -> Result<bool, ViewError> + Send,
1322 {
1323 self.collection
1324 .for_each_key_while(|key| {
1325 let index = I::from_custom_bytes(key)?;
1326 f(index)
1327 })
1328 .await?;
1329 Ok(())
1330 }
1331
1332 /// Applies a function on each index. Indices are visited in an order
1333 /// determined by the custom serialization.
1334 /// ```rust
1335 /// # tokio_test::block_on(async {
1336 /// # use linera_views::context::MemoryContext;
1337 /// # use linera_views::collection_view::CustomCollectionView;
1338 /// # use linera_views::register_view::RegisterView;
1339 /// # use linera_views::views::View;
1340 /// # let context = MemoryContext::new_for_testing(());
1341 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1342 /// CustomCollectionView::load(context).await.unwrap();
1343 /// view.load_entry_mut(&28).await.unwrap();
1344 /// view.load_entry_mut(&24).await.unwrap();
1345 /// view.load_entry_mut(&23).await.unwrap();
1346 /// let mut indices = Vec::new();
1347 /// view.for_each_index(|index| {
1348 /// indices.push(index);
1349 /// Ok(())
1350 /// })
1351 /// .await
1352 /// .unwrap();
1353 /// assert_eq!(indices, vec![23, 24, 28]);
1354 /// # })
1355 /// ```
1356 pub async fn for_each_index<F>(&self, mut f: F) -> Result<(), ViewError>
1357 where
1358 F: FnMut(I) -> Result<(), ViewError> + Send,
1359 {
1360 self.collection
1361 .for_each_key(|key| {
1362 let index = I::from_custom_bytes(key)?;
1363 f(index)
1364 })
1365 .await?;
1366 Ok(())
1367 }
1368}
1369
1370impl<I, W: HashableView> HashableView for CustomCollectionView<W::Context, I, W>
1371where
1372 Self: View,
1373{
1374 type Hasher = sha3::Sha3_256;
1375
1376 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1377 self.collection.hash_mut().await
1378 }
1379
1380 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1381 self.collection.hash().await
1382 }
1383}
1384
1385/// Type wrapping `ByteCollectionView` while memoizing the hash.
1386pub type HashedByteCollectionView<C, W> =
1387 WrappedHashableContainerView<C, ByteCollectionView<C, W>, HasherOutput>;
1388
1389/// Type wrapping `CollectionView` while memoizing the hash.
1390pub type HashedCollectionView<C, I, W> =
1391 WrappedHashableContainerView<C, CollectionView<C, I, W>, HasherOutput>;
1392
1393/// Type wrapping `CustomCollectionView` while memoizing the hash.
1394pub type HashedCustomCollectionView<C, I, W> =
1395 WrappedHashableContainerView<C, CustomCollectionView<C, I, W>, HasherOutput>;
1396
1397#[cfg(with_graphql)]
1398mod graphql {
1399 use std::borrow::Cow;
1400
1401 use super::{CollectionView, CustomCollectionView, ReadGuardedView};
1402 use crate::{
1403 graphql::{hash_name, mangle, missing_key_error, Entry, MapFilters, MapInput},
1404 views::View,
1405 };
1406
1407 impl<T: async_graphql::OutputType> async_graphql::OutputType for ReadGuardedView<'_, T> {
1408 fn type_name() -> Cow<'static, str> {
1409 T::type_name()
1410 }
1411
1412 fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
1413 T::create_type_info(registry)
1414 }
1415
1416 async fn resolve(
1417 &self,
1418 ctx: &async_graphql::ContextSelectionSet<'_>,
1419 field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
1420 ) -> async_graphql::ServerResult<async_graphql::Value> {
1421 (**self).resolve(ctx, field).await
1422 }
1423 }
1424
1425 impl<C: Send + Sync, K: async_graphql::OutputType, V: async_graphql::OutputType>
1426 async_graphql::TypeName for CollectionView<C, K, V>
1427 {
1428 fn type_name() -> Cow<'static, str> {
1429 format!(
1430 "CollectionView_{}_{}_{:08x}",
1431 mangle(K::type_name()),
1432 mangle(V::type_name()),
1433 hash_name::<(K, V)>(),
1434 )
1435 .into()
1436 }
1437 }
1438
1439 #[async_graphql::Object(cache_control(no_cache), name_type)]
1440 impl<K, V> CollectionView<V::Context, K, V>
1441 where
1442 K: async_graphql::InputType
1443 + async_graphql::OutputType
1444 + serde::ser::Serialize
1445 + serde::de::DeserializeOwned
1446 + std::fmt::Debug
1447 + Clone,
1448 V: View + async_graphql::OutputType,
1449 MapInput<K>: async_graphql::InputType,
1450 MapFilters<K>: async_graphql::InputType,
1451 {
1452 async fn keys(&self) -> Result<Vec<K>, async_graphql::Error> {
1453 Ok(self.indices().await?)
1454 }
1455
1456 async fn entry(
1457 &self,
1458 key: K,
1459 ) -> Result<Entry<K, ReadGuardedView<V>>, async_graphql::Error> {
1460 let value = self
1461 .try_load_entry(&key)
1462 .await?
1463 .ok_or_else(|| missing_key_error(&key))?;
1464 Ok(Entry { value, key })
1465 }
1466
1467 async fn entries(
1468 &self,
1469 input: Option<MapInput<K>>,
1470 ) -> Result<Vec<Entry<K, ReadGuardedView<V>>>, async_graphql::Error> {
1471 let keys = if let Some(keys) = input
1472 .and_then(|input| input.filters)
1473 .and_then(|filters| filters.keys)
1474 {
1475 keys
1476 } else {
1477 self.indices().await?
1478 };
1479
1480 let mut values = vec![];
1481 for key in keys {
1482 let value = self
1483 .try_load_entry(&key)
1484 .await?
1485 .ok_or_else(|| missing_key_error(&key))?;
1486 values.push(Entry { value, key })
1487 }
1488
1489 Ok(values)
1490 }
1491 }
1492
1493 impl<C: Send + Sync, K: async_graphql::InputType, V: async_graphql::OutputType>
1494 async_graphql::TypeName for CustomCollectionView<C, K, V>
1495 {
1496 fn type_name() -> Cow<'static, str> {
1497 format!(
1498 "CustomCollectionView_{}_{}_{:08x}",
1499 mangle(K::type_name()),
1500 mangle(V::type_name()),
1501 hash_name::<(K, V)>(),
1502 )
1503 .into()
1504 }
1505 }
1506
1507 #[async_graphql::Object(cache_control(no_cache), name_type)]
1508 impl<K, V> CustomCollectionView<V::Context, K, V>
1509 where
1510 K: async_graphql::InputType
1511 + async_graphql::OutputType
1512 + crate::common::CustomSerialize
1513 + std::fmt::Debug,
1514 V: View + async_graphql::OutputType,
1515 MapInput<K>: async_graphql::InputType,
1516 MapFilters<K>: async_graphql::InputType,
1517 {
1518 async fn keys(&self) -> Result<Vec<K>, async_graphql::Error> {
1519 Ok(self.indices().await?)
1520 }
1521
1522 async fn entry(
1523 &self,
1524 key: K,
1525 ) -> Result<Entry<K, ReadGuardedView<V>>, async_graphql::Error> {
1526 let value = self
1527 .try_load_entry(&key)
1528 .await?
1529 .ok_or_else(|| missing_key_error(&key))?;
1530 Ok(Entry { value, key })
1531 }
1532
1533 async fn entries(
1534 &self,
1535 input: Option<MapInput<K>>,
1536 ) -> Result<Vec<Entry<K, ReadGuardedView<V>>>, async_graphql::Error> {
1537 let keys = if let Some(keys) = input
1538 .and_then(|input| input.filters)
1539 .and_then(|filters| filters.keys)
1540 {
1541 keys
1542 } else {
1543 self.indices().await?
1544 };
1545
1546 let mut values = vec![];
1547 for key in keys {
1548 let value = self
1549 .try_load_entry(&key)
1550 .await?
1551 .ok_or_else(|| missing_key_error(&key))?;
1552 values.push(Entry { value, key })
1553 }
1554
1555 Ok(values)
1556 }
1557 }
1558}