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 ops::Deref,
11};
12
13use allocative::{Allocative, Key, Visitor};
14use async_lock::{RwLock, RwLockReadGuard};
15#[cfg(with_metrics)]
16use linera_base::prometheus_util::MeasureLatency as _;
17use serde::{de::DeserializeOwned, Serialize};
18
19use crate::{
20 batch::Batch,
21 common::{CustomSerialize, HasherOutput, SliceExt as _, Update},
22 context::{BaseKey, Context},
23 hashable_wrapper::WrappedHashableContainerView,
24 historical_hash_wrapper::HistoricallyHashableView,
25 store::ReadableKeyValueStore as _,
26 views::{ClonableView, HashableView, Hasher, View, ViewError, MIN_VIEW_TAG},
27};
28
29#[cfg(with_metrics)]
30mod metrics {
31 use std::sync::LazyLock;
32
33 use linera_base::prometheus_util::{exponential_bucket_latencies, register_histogram_vec};
34 use prometheus::HistogramVec;
35
36 /// The runtime of hash computation
37 pub static COLLECTION_VIEW_HASH_RUNTIME: LazyLock<HistogramVec> = LazyLock::new(|| {
38 register_histogram_vec(
39 "collection_view_hash_runtime",
40 "CollectionView hash runtime",
41 &[],
42 exponential_bucket_latencies(5.0),
43 )
44 });
45}
46
47/// A view that supports accessing a collection of views of the same kind, indexed by a
48/// `Vec<u8>`, one subview at a time.
49#[derive(Debug)]
50pub struct ByteCollectionView<C, W> {
51 /// The view context.
52 context: C,
53 /// Whether to clear storage before applying updates.
54 delete_storage_first: bool,
55 /// Entries that may have staged changes.
56 updates: RwLock<BTreeMap<Vec<u8>, Update<W>>>,
57}
58
59impl<C, W: Allocative> Allocative for ByteCollectionView<C, W> {
60 fn visit<'a, 'b: 'a>(&self, visitor: &'a mut Visitor<'b>) {
61 let name = Key::new("ByteCollectionView");
62 let size = mem::size_of::<Self>();
63 let mut visitor = visitor.enter(name, size);
64 if let Some(updates) = self.updates.try_read() {
65 updates.deref().visit(&mut visitor);
66 }
67 visitor.exit();
68 }
69}
70
71/// A read-only accessor for a particular subview in a [`CollectionView`].
72pub enum ReadGuardedView<'a, W> {
73 /// The view is loaded in the updates
74 Loaded {
75 /// The guard for the updates.
76 updates: RwLockReadGuard<'a, BTreeMap<Vec<u8>, Update<W>>>,
77 /// The key in question.
78 short_key: Vec<u8>,
79 },
80 /// The view is not loaded in the updates
81 NotLoaded {
82 /// The guard for the updates. It is needed so that it prevents
83 /// opening the view as write separately.
84 _updates: RwLockReadGuard<'a, BTreeMap<Vec<u8>, Update<W>>>,
85 /// The view obtained from the storage
86 view: W,
87 },
88}
89
90impl<W> std::ops::Deref for ReadGuardedView<'_, W> {
91 type Target = W;
92
93 fn deref(&self) -> &W {
94 match self {
95 ReadGuardedView::Loaded { updates, short_key } => {
96 let Update::Set(view) = updates.get(short_key).unwrap() else {
97 unreachable!();
98 };
99 view
100 }
101 ReadGuardedView::NotLoaded { _updates, view } => view,
102 }
103 }
104}
105
106/// We need to find new base keys in order to implement `CollectionView`.
107/// We do this by appending a value to the base key.
108///
109/// Sub-views in a collection share a common key prefix, like in other view types. However,
110/// just concatenating the shared prefix with sub-view keys makes it impossible to distinguish if a
111/// given key belongs to child sub-view or a grandchild sub-view (consider for example if a
112/// collection is stored inside the collection).
113#[repr(u8)]
114enum KeyTag {
115 /// Prefix for specifying an index and serves to indicate the existence of an entry in the collection.
116 Index = MIN_VIEW_TAG,
117 /// Prefix for specifying as the prefix for the sub-view.
118 Subview,
119}
120
121impl<W: View> View for ByteCollectionView<W::Context, W> {
122 const NUM_INIT_KEYS: usize = 0;
123
124 type Context = W::Context;
125
126 fn context(&self) -> &Self::Context {
127 &self.context
128 }
129
130 fn pre_load(_context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
131 Ok(vec![])
132 }
133
134 fn post_load(context: Self::Context, _values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
135 Ok(Self {
136 context,
137 delete_storage_first: false,
138 updates: RwLock::new(BTreeMap::new()),
139 })
140 }
141
142 fn rollback(&mut self) {
143 self.delete_storage_first = false;
144 self.updates.get_mut().clear();
145 }
146
147 async fn has_pending_changes(&self) -> bool {
148 if self.delete_storage_first {
149 return true;
150 }
151 let updates = self.updates.read().await;
152 !updates.is_empty()
153 }
154
155 fn pre_save(&self, batch: &mut Batch) -> Result<bool, ViewError> {
156 let mut delete_view = false;
157 let updates = self
158 .updates
159 .try_read()
160 .ok_or_else(|| ViewError::TryLockError(vec![]))?;
161 if self.delete_storage_first {
162 delete_view = true;
163 batch.delete_key_prefix(self.context.base_key().bytes.clone());
164 for (index, update) in updates.iter() {
165 if let Update::Set(view) = update {
166 view.pre_save(batch)?;
167 self.add_index(batch, index);
168 delete_view = false;
169 }
170 }
171 } else {
172 for (index, update) in updates.iter() {
173 match update {
174 Update::Set(view) => {
175 view.pre_save(batch)?;
176 self.add_index(batch, index);
177 }
178 Update::Removed => {
179 let key_subview = self.get_subview_key(index);
180 let key_index = self.get_index_key(index);
181 batch.delete_key(key_index);
182 batch.delete_key_prefix(key_subview);
183 }
184 }
185 }
186 }
187 Ok(delete_view)
188 }
189
190 fn post_save(&mut self) {
191 for (_, update) in self.updates.get_mut().iter_mut() {
192 if let Update::Set(view) = update {
193 view.post_save();
194 }
195 }
196 self.delete_storage_first = false;
197 self.updates.get_mut().clear();
198 }
199
200 fn clear(&mut self) {
201 self.delete_storage_first = true;
202 self.updates.get_mut().clear();
203 }
204}
205
206impl<W: ClonableView> ClonableView for ByteCollectionView<W::Context, W> {
207 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
208 let cloned_updates = self
209 .updates
210 .get_mut()
211 .iter_mut()
212 .map(|(key, value)| {
213 let cloned_value: Result<_, ViewError> = match value {
214 Update::Removed => Ok(Update::Removed),
215 Update::Set(view) => Ok(Update::Set(view.clone_unchecked()?)),
216 };
217 cloned_value.map(|v| (key.clone(), v))
218 })
219 .collect::<Result<_, ViewError>>()?;
220
221 Ok(ByteCollectionView {
222 context: self.context.clone(),
223 delete_storage_first: self.delete_storage_first,
224 updates: RwLock::new(cloned_updates),
225 })
226 }
227}
228
229impl<W: View> ByteCollectionView<W::Context, W> {
230 fn get_index_key(&self, index: &[u8]) -> Vec<u8> {
231 self.context
232 .base_key()
233 .base_tag_index(KeyTag::Index as u8, index)
234 }
235
236 fn get_subview_key(&self, index: &[u8]) -> Vec<u8> {
237 self.context
238 .base_key()
239 .base_tag_index(KeyTag::Subview as u8, index)
240 }
241
242 fn add_index(&self, batch: &mut Batch, index: &[u8]) {
243 let key = self.get_index_key(index);
244 batch.put_key_value_bytes(key, vec![]);
245 }
246
247 /// Loads a subview for the data at the given index in the collection. If an entry
248 /// is absent then a default entry is added to the collection. The resulting view
249 /// can be modified.
250 /// ```rust
251 /// # tokio_test::block_on(async {
252 /// # use linera_views::context::MemoryContext;
253 /// # use linera_views::collection_view::ByteCollectionView;
254 /// # use linera_views::register_view::RegisterView;
255 /// # use linera_views::views::View;
256 /// # let context = MemoryContext::new_for_testing(());
257 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
258 /// ByteCollectionView::load(context).await.unwrap();
259 /// let subview = view.load_entry_mut(&[0, 1]).await.unwrap();
260 /// let value = subview.get();
261 /// assert_eq!(*value, String::default());
262 /// # })
263 /// ```
264 pub async fn load_entry_mut(&mut self, short_key: &[u8]) -> Result<&mut W, ViewError> {
265 match self.updates.get_mut().entry(short_key.to_vec()) {
266 btree_map::Entry::Occupied(entry) => {
267 let entry = entry.into_mut();
268 match entry {
269 Update::Set(view) => Ok(view),
270 Update::Removed => {
271 let key = self
272 .context
273 .base_key()
274 .base_tag_index(KeyTag::Subview as u8, short_key);
275 let context = self.context.clone_with_base_key(key);
276 // Obtain a view and set its pending state to the default (e.g. empty) state
277 let view = W::new(context)?;
278 *entry = Update::Set(view);
279 let Update::Set(view) = entry else {
280 unreachable!();
281 };
282 Ok(view)
283 }
284 }
285 }
286 btree_map::Entry::Vacant(entry) => {
287 let key = self
288 .context
289 .base_key()
290 .base_tag_index(KeyTag::Subview as u8, short_key);
291 let context = self.context.clone_with_base_key(key);
292 let view = if self.delete_storage_first {
293 W::new(context)?
294 } else {
295 W::load(context).await?
296 };
297 let Update::Set(view) = entry.insert(Update::Set(view)) else {
298 unreachable!();
299 };
300 Ok(view)
301 }
302 }
303 }
304
305 /// Loads a subview for the data at the given index in the collection. If an entry
306 /// is absent then `None` is returned. The resulting view cannot be modified.
307 /// May fail if one subview is already being visited.
308 /// ```rust
309 /// # tokio_test::block_on(async {
310 /// # use linera_views::context::MemoryContext;
311 /// # use linera_views::collection_view::ByteCollectionView;
312 /// # use linera_views::register_view::RegisterView;
313 /// # use linera_views::views::View;
314 /// # let context = MemoryContext::new_for_testing(());
315 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
316 /// ByteCollectionView::load(context).await.unwrap();
317 /// {
318 /// let _subview = view.load_entry_mut(&[0, 1]).await.unwrap();
319 /// }
320 /// {
321 /// let subview = view.try_load_entry(&[0, 1]).await.unwrap().unwrap();
322 /// let value = subview.get();
323 /// assert_eq!(*value, String::default());
324 /// }
325 /// assert!(view.try_load_entry(&[0, 2]).await.unwrap().is_none());
326 /// # })
327 /// ```
328 pub async fn try_load_entry(
329 &self,
330 short_key: &[u8],
331 ) -> Result<Option<ReadGuardedView<W>>, ViewError> {
332 let updates = self.updates.read().await;
333 match updates.get(short_key) {
334 Some(update) => match update {
335 Update::Removed => Ok(None),
336 Update::Set(_) => Ok(Some(ReadGuardedView::Loaded {
337 updates,
338 short_key: short_key.to_vec(),
339 })),
340 },
341 None => {
342 let key_index = self
343 .context
344 .base_key()
345 .base_tag_index(KeyTag::Index as u8, short_key);
346 if !self.delete_storage_first
347 && self.context.store().contains_key(&key_index).await?
348 {
349 let key = self
350 .context
351 .base_key()
352 .base_tag_index(KeyTag::Subview as u8, short_key);
353 let context = self.context.clone_with_base_key(key);
354 let view = W::load(context).await?;
355 Ok(Some(ReadGuardedView::NotLoaded {
356 _updates: updates,
357 view,
358 }))
359 } else {
360 Ok(None)
361 }
362 }
363 }
364 }
365
366 /// Load multiple entries for reading at once.
367 /// The entries in `short_keys` have to be all distinct.
368 /// ```rust
369 /// # tokio_test::block_on(async {
370 /// # use linera_views::context::MemoryContext;
371 /// # use linera_views::collection_view::ByteCollectionView;
372 /// # use linera_views::register_view::RegisterView;
373 /// # use linera_views::views::View;
374 /// # let context = MemoryContext::new_for_testing(());
375 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
376 /// ByteCollectionView::load(context).await.unwrap();
377 /// {
378 /// let _subview = view.load_entry_mut(&[0, 1]).await.unwrap();
379 /// }
380 /// let short_keys = vec![vec![0, 1], vec![2, 3]];
381 /// let subviews = view.try_load_entries(short_keys).await.unwrap();
382 /// let value0 = subviews[0].as_ref().unwrap().get();
383 /// assert_eq!(*value0, String::default());
384 /// # })
385 /// ```
386 pub async fn try_load_entries(
387 &self,
388 short_keys: Vec<Vec<u8>>,
389 ) -> Result<Vec<Option<ReadGuardedView<W>>>, ViewError> {
390 let mut results = Vec::with_capacity(short_keys.len());
391 let mut keys_to_check = Vec::new();
392 let mut keys_to_check_metadata = Vec::new();
393 let updates = self.updates.read().await;
394
395 for (position, short_key) in short_keys.into_iter().enumerate() {
396 match updates.get(&short_key) {
397 Some(update) => match update {
398 Update::Removed => {
399 results.push(None);
400 }
401 Update::Set(_) => {
402 let updates = self.updates.read().await;
403 results.push(Some(ReadGuardedView::Loaded {
404 updates,
405 short_key: short_key.clone(),
406 }));
407 }
408 },
409 None => {
410 results.push(None); // Placeholder, may be updated later
411 if !self.delete_storage_first {
412 let key = self
413 .context
414 .base_key()
415 .base_tag_index(KeyTag::Subview as u8, &short_key);
416 let subview_context = self.context.clone_with_base_key(key);
417 let key = self
418 .context
419 .base_key()
420 .base_tag_index(KeyTag::Index as u8, &short_key);
421 keys_to_check.push(key);
422 keys_to_check_metadata.push((position, subview_context));
423 }
424 }
425 }
426 }
427
428 let found_keys = self.context.store().contains_keys(&keys_to_check).await?;
429 let entries_to_load = keys_to_check_metadata
430 .into_iter()
431 .zip(found_keys)
432 .filter_map(|(metadata, found)| found.then_some(metadata))
433 .collect::<Vec<_>>();
434
435 let mut keys_to_load = Vec::with_capacity(entries_to_load.len() * W::NUM_INIT_KEYS);
436 for (_, context) in &entries_to_load {
437 keys_to_load.extend(W::pre_load(context)?);
438 }
439 let values = self
440 .context
441 .store()
442 .read_multi_values_bytes(&keys_to_load)
443 .await?;
444
445 for (loaded_values, (position, context)) in values
446 .chunks_exact_or_repeat(W::NUM_INIT_KEYS)
447 .zip(entries_to_load)
448 {
449 let view = W::post_load(context, loaded_values)?;
450 let updates = self.updates.read().await;
451 results[position] = Some(ReadGuardedView::NotLoaded {
452 _updates: updates,
453 view,
454 });
455 }
456
457 Ok(results)
458 }
459
460 /// Loads multiple entries for reading at once with their keys.
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 /// {
471 /// let subview = view.load_entry_mut(&vec![0, 1]).await.unwrap();
472 /// subview.set("Bonjour".into());
473 /// }
474 /// let short_keys = vec![vec![0, 1], vec![0, 2]];
475 /// let pairs = view.try_load_entries_pairs(short_keys).await.unwrap();
476 /// assert_eq!(pairs[0].0, vec![0, 1]);
477 /// assert_eq!(pairs[1].0, vec![0, 2]);
478 /// let value0 = pairs[0].1.as_ref().unwrap().get();
479 /// assert_eq!(*value0, "Bonjour".to_string());
480 /// assert!(pairs[1].1.is_none());
481 /// # })
482 /// ```
483 pub async fn try_load_entries_pairs(
484 &self,
485 short_keys: Vec<Vec<u8>>,
486 ) -> Result<Vec<(Vec<u8>, Option<ReadGuardedView<W>>)>, ViewError> {
487 let values = self.try_load_entries(short_keys.clone()).await?;
488 Ok(short_keys.into_iter().zip(values).collect())
489 }
490
491 /// Load all entries for reading at once.
492 /// ```rust
493 /// # tokio_test::block_on(async {
494 /// # use linera_views::context::MemoryContext;
495 /// # use linera_views::collection_view::ByteCollectionView;
496 /// # use linera_views::register_view::RegisterView;
497 /// # use linera_views::views::View;
498 /// # let context = MemoryContext::new_for_testing(());
499 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
500 /// ByteCollectionView::load(context).await.unwrap();
501 /// {
502 /// let _subview = view.load_entry_mut(&[0, 1]).await.unwrap();
503 /// }
504 /// let subviews = view.try_load_all_entries().await.unwrap();
505 /// assert_eq!(subviews.len(), 1);
506 /// # })
507 /// ```
508 pub async fn try_load_all_entries(
509 &self,
510 ) -> Result<Vec<(Vec<u8>, ReadGuardedView<W>)>, ViewError> {
511 let updates = self.updates.read().await; // Acquire the read lock to prevent writes.
512 let short_keys = self.keys().await?;
513 let mut results = Vec::with_capacity(short_keys.len());
514
515 let mut keys_to_load = Vec::new();
516 let mut keys_to_load_metadata = Vec::new();
517 for (position, short_key) in short_keys.iter().enumerate() {
518 match updates.get(short_key) {
519 Some(update) => {
520 let Update::Set(_) = update else {
521 unreachable!();
522 };
523 let updates = self.updates.read().await;
524 let view = ReadGuardedView::Loaded {
525 updates,
526 short_key: short_key.clone(),
527 };
528 results.push((short_key.clone(), Some(view)));
529 }
530 None => {
531 // If a key is not in `updates`, then it is in storage.
532 // The key exists since otherwise it would not be in `short_keys`.
533 // Therefore we have `self.delete_storage_first = false`.
534 assert!(!self.delete_storage_first);
535 results.push((short_key.clone(), None));
536 let key = self
537 .context
538 .base_key()
539 .base_tag_index(KeyTag::Subview as u8, short_key);
540 let subview_context = self.context.clone_with_base_key(key);
541 keys_to_load.extend(W::pre_load(&subview_context)?);
542 keys_to_load_metadata.push((position, subview_context, short_key.clone()));
543 }
544 }
545 }
546
547 let values = self
548 .context
549 .store()
550 .read_multi_values_bytes(&keys_to_load)
551 .await?;
552
553 for (loaded_values, (position, context, short_key)) in values
554 .chunks_exact_or_repeat(W::NUM_INIT_KEYS)
555 .zip(keys_to_load_metadata)
556 {
557 let view = W::post_load(context, loaded_values)?;
558 let updates = self.updates.read().await;
559 let guarded_view = ReadGuardedView::NotLoaded {
560 _updates: updates,
561 view,
562 };
563 results[position] = (short_key, Some(guarded_view));
564 }
565
566 Ok(results
567 .into_iter()
568 .map(|(short_key, view)| (short_key, view.unwrap()))
569 .collect::<Vec<_>>())
570 }
571
572 /// Resets an entry to the default value.
573 /// ```rust
574 /// # tokio_test::block_on(async {
575 /// # use linera_views::context::MemoryContext;
576 /// # use linera_views::collection_view::ByteCollectionView;
577 /// # use linera_views::register_view::RegisterView;
578 /// # use linera_views::views::View;
579 /// # let context = MemoryContext::new_for_testing(());
580 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
581 /// ByteCollectionView::load(context).await.unwrap();
582 /// let subview = view.load_entry_mut(&[0, 1]).await.unwrap();
583 /// let value = subview.get_mut();
584 /// *value = String::from("Hello");
585 /// view.reset_entry_to_default(&[0, 1]).unwrap();
586 /// let subview = view.load_entry_mut(&[0, 1]).await.unwrap();
587 /// let value = subview.get_mut();
588 /// assert_eq!(*value, String::default());
589 /// # })
590 /// ```
591 pub fn reset_entry_to_default(&mut self, short_key: &[u8]) -> Result<(), ViewError> {
592 let key = self
593 .context
594 .base_key()
595 .base_tag_index(KeyTag::Subview as u8, short_key);
596 let context = self.context.clone_with_base_key(key);
597 let view = W::new(context)?;
598 self.updates
599 .get_mut()
600 .insert(short_key.to_vec(), Update::Set(view));
601 Ok(())
602 }
603
604 /// Tests if the collection contains a specified key and returns a boolean.
605 /// ```rust
606 /// # tokio_test::block_on(async {
607 /// # use linera_views::context::MemoryContext;
608 /// # use linera_views::collection_view::ByteCollectionView;
609 /// # use linera_views::register_view::RegisterView;
610 /// # use linera_views::views::View;
611 /// # let context = MemoryContext::new_for_testing(());
612 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
613 /// ByteCollectionView::load(context).await.unwrap();
614 /// {
615 /// let _subview = view.load_entry_mut(&[0, 1]).await.unwrap();
616 /// }
617 /// assert!(view.contains_key(&[0, 1]).await.unwrap());
618 /// assert!(!view.contains_key(&[0, 2]).await.unwrap());
619 /// # })
620 /// ```
621 pub async fn contains_key(&self, short_key: &[u8]) -> Result<bool, ViewError> {
622 let updates = self.updates.read().await;
623 Ok(match updates.get(short_key) {
624 Some(entry) => match entry {
625 Update::Set(_view) => true,
626 _entry @ Update::Removed => false,
627 },
628 None => {
629 let key_index = self
630 .context
631 .base_key()
632 .base_tag_index(KeyTag::Index as u8, short_key);
633 !self.delete_storage_first && self.context.store().contains_key(&key_index).await?
634 }
635 })
636 }
637
638 /// Marks the entry as removed. If absent then nothing is done.
639 /// ```rust
640 /// # tokio_test::block_on(async {
641 /// # use linera_views::context::MemoryContext;
642 /// # use linera_views::collection_view::ByteCollectionView;
643 /// # use linera_views::register_view::RegisterView;
644 /// # use linera_views::views::View;
645 /// # let context = MemoryContext::new_for_testing(());
646 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
647 /// ByteCollectionView::load(context).await.unwrap();
648 /// let subview = view.load_entry_mut(&[0, 1]).await.unwrap();
649 /// let value = subview.get_mut();
650 /// assert_eq!(*value, String::default());
651 /// view.remove_entry(vec![0, 1]);
652 /// let keys = view.keys().await.unwrap();
653 /// assert_eq!(keys.len(), 0);
654 /// # })
655 /// ```
656 pub fn remove_entry(&mut self, short_key: Vec<u8>) {
657 if self.delete_storage_first {
658 // Optimization: No need to mark `short_key` for deletion as we are going to remove all the keys at once.
659 self.updates.get_mut().remove(&short_key);
660 } else {
661 self.updates.get_mut().insert(short_key, Update::Removed);
662 }
663 }
664
665 /// Gets the extra data.
666 pub fn extra(&self) -> &<W::Context as Context>::Extra {
667 self.context.extra()
668 }
669}
670
671impl<W: View> ByteCollectionView<W::Context, W> {
672 /// Applies a function f on each index (aka key). Keys are visited in the
673 /// lexicographic order. If the function returns false, then the loop
674 /// ends prematurely.
675 /// ```rust
676 /// # tokio_test::block_on(async {
677 /// # use linera_views::context::MemoryContext;
678 /// # use linera_views::collection_view::ByteCollectionView;
679 /// # use linera_views::register_view::RegisterView;
680 /// # use linera_views::views::View;
681 /// # let context = MemoryContext::new_for_testing(());
682 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
683 /// ByteCollectionView::load(context).await.unwrap();
684 /// view.load_entry_mut(&[0, 1]).await.unwrap();
685 /// view.load_entry_mut(&[0, 2]).await.unwrap();
686 /// let mut count = 0;
687 /// view.for_each_key_while(|_key| {
688 /// count += 1;
689 /// Ok(count < 1)
690 /// })
691 /// .await
692 /// .unwrap();
693 /// assert_eq!(count, 1);
694 /// # })
695 /// ```
696 pub async fn for_each_key_while<F>(&self, mut f: F) -> Result<(), ViewError>
697 where
698 F: FnMut(&[u8]) -> Result<bool, ViewError> + Send,
699 {
700 let updates = self.updates.read().await;
701 let mut updates = updates.iter();
702 let mut update = updates.next();
703 if !self.delete_storage_first {
704 let base = self.get_index_key(&[]);
705 for index in self.context.store().find_keys_by_prefix(&base).await? {
706 loop {
707 match update {
708 Some((key, value)) if key <= &index => {
709 if let Update::Set(_) = value {
710 if !f(key)? {
711 return Ok(());
712 }
713 }
714 update = updates.next();
715 if key == &index {
716 break;
717 }
718 }
719 _ => {
720 if !f(&index)? {
721 return Ok(());
722 }
723 break;
724 }
725 }
726 }
727 }
728 }
729 while let Some((key, value)) = update {
730 if let Update::Set(_) = value {
731 if !f(key)? {
732 return Ok(());
733 }
734 }
735 update = updates.next();
736 }
737 Ok(())
738 }
739
740 /// Applies a function f on each index (aka key). Keys are visited in a
741 /// lexicographic order.
742 /// ```rust
743 /// # tokio_test::block_on(async {
744 /// # use linera_views::context::MemoryContext;
745 /// # use linera_views::collection_view::ByteCollectionView;
746 /// # use linera_views::register_view::RegisterView;
747 /// # use linera_views::views::View;
748 /// # let context = MemoryContext::new_for_testing(());
749 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
750 /// ByteCollectionView::load(context).await.unwrap();
751 /// view.load_entry_mut(&[0, 1]).await.unwrap();
752 /// view.load_entry_mut(&[0, 2]).await.unwrap();
753 /// let mut count = 0;
754 /// view.for_each_key(|_key| {
755 /// count += 1;
756 /// Ok(())
757 /// })
758 /// .await
759 /// .unwrap();
760 /// assert_eq!(count, 2);
761 /// # })
762 /// ```
763 pub async fn for_each_key<F>(&self, mut f: F) -> Result<(), ViewError>
764 where
765 F: FnMut(&[u8]) -> Result<(), ViewError> + Send,
766 {
767 self.for_each_key_while(|key| {
768 f(key)?;
769 Ok(true)
770 })
771 .await
772 }
773
774 /// Returns the list of keys in the collection. The order is lexicographic.
775 /// ```rust
776 /// # tokio_test::block_on(async {
777 /// # use linera_views::context::MemoryContext;
778 /// # use linera_views::collection_view::ByteCollectionView;
779 /// # use linera_views::register_view::RegisterView;
780 /// # use linera_views::views::View;
781 /// # let context = MemoryContext::new_for_testing(());
782 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
783 /// ByteCollectionView::load(context).await.unwrap();
784 /// view.load_entry_mut(&[0, 1]).await.unwrap();
785 /// view.load_entry_mut(&[0, 2]).await.unwrap();
786 /// let keys = view.keys().await.unwrap();
787 /// assert_eq!(keys, vec![vec![0, 1], vec![0, 2]]);
788 /// # })
789 /// ```
790 pub async fn keys(&self) -> Result<Vec<Vec<u8>>, ViewError> {
791 let mut keys = Vec::new();
792 self.for_each_key(|key| {
793 keys.push(key.to_vec());
794 Ok(())
795 })
796 .await?;
797 Ok(keys)
798 }
799
800 /// Returns the number of entries in the collection.
801 /// ```rust
802 /// # tokio_test::block_on(async {
803 /// # use linera_views::context::MemoryContext;
804 /// # use linera_views::collection_view::ByteCollectionView;
805 /// # use linera_views::register_view::RegisterView;
806 /// # use linera_views::views::View;
807 /// # let context = MemoryContext::new_for_testing(());
808 /// let mut view: ByteCollectionView<_, RegisterView<_, String>> =
809 /// ByteCollectionView::load(context).await.unwrap();
810 /// view.load_entry_mut(&[0, 1]).await.unwrap();
811 /// view.load_entry_mut(&[0, 2]).await.unwrap();
812 /// assert_eq!(view.count().await.unwrap(), 2);
813 /// # })
814 /// ```
815 pub async fn count(&self) -> Result<usize, ViewError> {
816 let mut count = 0;
817 self.for_each_key(|_key| {
818 count += 1;
819 Ok(())
820 })
821 .await?;
822 Ok(count)
823 }
824}
825
826impl<W: HashableView> HashableView for ByteCollectionView<W::Context, W> {
827 type Hasher = sha3::Sha3_256;
828
829 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
830 #[cfg(with_metrics)]
831 let _hash_latency = metrics::COLLECTION_VIEW_HASH_RUNTIME.measure_latency();
832 let mut hasher = sha3::Sha3_256::default();
833 let keys = self.keys().await?;
834 let count = keys.len() as u32;
835 hasher.update_with_bcs_bytes(&count)?;
836 let updates = self.updates.get_mut();
837 for key in keys {
838 hasher.update_with_bytes(&key)?;
839 let hash = match updates.get_mut(&key) {
840 Some(entry) => {
841 let Update::Set(view) = entry else {
842 unreachable!();
843 };
844 view.hash_mut().await?
845 }
846 None => {
847 let key = self
848 .context
849 .base_key()
850 .base_tag_index(KeyTag::Subview as u8, &key);
851 let context = self.context.clone_with_base_key(key);
852 let mut view = W::load(context).await?;
853 view.hash_mut().await?
854 }
855 };
856 hasher.write_all(hash.as_ref())?;
857 }
858 Ok(hasher.finalize())
859 }
860
861 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
862 #[cfg(with_metrics)]
863 let _hash_latency = metrics::COLLECTION_VIEW_HASH_RUNTIME.measure_latency();
864 let mut hasher = sha3::Sha3_256::default();
865 let updates = self.updates.read().await; // Acquire the lock to prevent writes.
866 let keys = self.keys().await?;
867 let count = keys.len() as u32;
868 hasher.update_with_bcs_bytes(&count)?;
869 for key in keys {
870 hasher.update_with_bytes(&key)?;
871 let hash = match updates.get(&key) {
872 Some(entry) => {
873 let Update::Set(view) = entry else {
874 unreachable!();
875 };
876 view.hash().await?
877 }
878 None => {
879 let key = self
880 .context
881 .base_key()
882 .base_tag_index(KeyTag::Subview as u8, &key);
883 let context = self.context.clone_with_base_key(key);
884 let view = W::load(context).await?;
885 view.hash().await?
886 }
887 };
888 hasher.write_all(hash.as_ref())?;
889 }
890 Ok(hasher.finalize())
891 }
892}
893
894/// A view that supports accessing a collection of views of the same kind, indexed by a
895/// key, one subview at a time.
896#[derive(Debug, Allocative)]
897#[allocative(bound = "C, I, W: Allocative")]
898pub struct CollectionView<C, I, W> {
899 collection: ByteCollectionView<C, W>,
900 #[allocative(skip)]
901 _phantom: PhantomData<I>,
902}
903
904impl<W: View, I> View for CollectionView<W::Context, I, W>
905where
906 I: Send + Sync + Serialize + DeserializeOwned,
907{
908 const NUM_INIT_KEYS: usize = ByteCollectionView::<W::Context, W>::NUM_INIT_KEYS;
909
910 type Context = W::Context;
911
912 fn context(&self) -> &Self::Context {
913 self.collection.context()
914 }
915
916 fn pre_load(context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
917 ByteCollectionView::<W::Context, W>::pre_load(context)
918 }
919
920 fn post_load(context: Self::Context, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
921 let collection = ByteCollectionView::post_load(context, values)?;
922 Ok(CollectionView {
923 collection,
924 _phantom: PhantomData,
925 })
926 }
927
928 fn rollback(&mut self) {
929 self.collection.rollback()
930 }
931
932 async fn has_pending_changes(&self) -> bool {
933 self.collection.has_pending_changes().await
934 }
935
936 fn pre_save(&self, batch: &mut Batch) -> Result<bool, ViewError> {
937 self.collection.pre_save(batch)
938 }
939
940 fn post_save(&mut self) {
941 self.collection.post_save()
942 }
943
944 fn clear(&mut self) {
945 self.collection.clear()
946 }
947}
948
949impl<I, W: ClonableView> ClonableView for CollectionView<W::Context, I, W>
950where
951 I: Send + Sync + Serialize + DeserializeOwned,
952{
953 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
954 Ok(CollectionView {
955 collection: self.collection.clone_unchecked()?,
956 _phantom: PhantomData,
957 })
958 }
959}
960
961impl<I: Serialize, W: View> CollectionView<W::Context, I, W> {
962 /// Loads a subview for the data at the given index in the collection. If an entry
963 /// is absent then a default entry is added to the collection. The resulting view
964 /// can be modified.
965 /// ```rust
966 /// # tokio_test::block_on(async {
967 /// # use linera_views::context::MemoryContext;
968 /// # use linera_views::collection_view::CollectionView;
969 /// # use linera_views::register_view::RegisterView;
970 /// # use linera_views::views::View;
971 /// # let context = MemoryContext::new_for_testing(());
972 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
973 /// CollectionView::load(context).await.unwrap();
974 /// let subview = view.load_entry_mut(&23).await.unwrap();
975 /// let value = subview.get();
976 /// assert_eq!(*value, String::default());
977 /// # })
978 /// ```
979 pub async fn load_entry_mut<Q>(&mut self, index: &Q) -> Result<&mut W, ViewError>
980 where
981 I: Borrow<Q>,
982 Q: Serialize + ?Sized,
983 {
984 let short_key = BaseKey::derive_short_key(index)?;
985 self.collection.load_entry_mut(&short_key).await
986 }
987
988 /// Loads a subview for the data at the given index in the collection. If an entry
989 /// is absent then `None` is returned. The resulting view cannot be modified.
990 /// May fail if one subview is already being visited.
991 /// ```rust
992 /// # tokio_test::block_on(async {
993 /// # use linera_views::context::MemoryContext;
994 /// # use linera_views::collection_view::CollectionView;
995 /// # use linera_views::register_view::RegisterView;
996 /// # use linera_views::views::View;
997 /// # let context = MemoryContext::new_for_testing(());
998 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
999 /// CollectionView::load(context).await.unwrap();
1000 /// {
1001 /// let _subview = view.load_entry_mut(&23).await.unwrap();
1002 /// }
1003 /// {
1004 /// let subview = view.try_load_entry(&23).await.unwrap().unwrap();
1005 /// let value = subview.get();
1006 /// assert_eq!(*value, String::default());
1007 /// }
1008 /// assert!(view.try_load_entry(&24).await.unwrap().is_none());
1009 /// # })
1010 /// ```
1011 pub async fn try_load_entry<Q>(
1012 &self,
1013 index: &Q,
1014 ) -> Result<Option<ReadGuardedView<W>>, ViewError>
1015 where
1016 I: Borrow<Q>,
1017 Q: Serialize + ?Sized,
1018 {
1019 let short_key = BaseKey::derive_short_key(index)?;
1020 self.collection.try_load_entry(&short_key).await
1021 }
1022
1023 /// Load multiple entries for reading at once.
1024 /// The entries in indices have to be all distinct.
1025 /// ```rust
1026 /// # tokio_test::block_on(async {
1027 /// # use linera_views::context::MemoryContext;
1028 /// # use linera_views::collection_view::CollectionView;
1029 /// # use linera_views::register_view::RegisterView;
1030 /// # use linera_views::views::View;
1031 /// # let context = MemoryContext::new_for_testing(());
1032 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1033 /// CollectionView::load(context).await.unwrap();
1034 /// {
1035 /// let _subview = view.load_entry_mut(&23).await.unwrap();
1036 /// }
1037 /// let indices = vec![23, 24];
1038 /// let subviews = view.try_load_entries(&indices).await.unwrap();
1039 /// let value0 = subviews[0].as_ref().unwrap().get();
1040 /// assert_eq!(*value0, String::default());
1041 /// # })
1042 /// ```
1043 pub async fn try_load_entries<'a, Q>(
1044 &self,
1045 indices: impl IntoIterator<Item = &'a Q>,
1046 ) -> Result<Vec<Option<ReadGuardedView<W>>>, ViewError>
1047 where
1048 I: Borrow<Q>,
1049 Q: Serialize + 'a,
1050 {
1051 let short_keys = indices
1052 .into_iter()
1053 .map(|index| BaseKey::derive_short_key(index))
1054 .collect::<Result<_, _>>()?;
1055 self.collection.try_load_entries(short_keys).await
1056 }
1057
1058 /// Loads multiple entries for reading at once with their keys.
1059 /// The entries in indices have to be all distinct.
1060 /// ```rust
1061 /// # tokio_test::block_on(async {
1062 /// # use linera_views::context::MemoryContext;
1063 /// # use linera_views::collection_view::CollectionView;
1064 /// # use linera_views::register_view::RegisterView;
1065 /// # use linera_views::views::View;
1066 /// # let context = MemoryContext::new_for_testing(());
1067 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1068 /// CollectionView::load(context).await.unwrap();
1069 /// {
1070 /// let _subview = view.load_entry_mut(&23).await.unwrap();
1071 /// }
1072 /// let indices = [23, 24];
1073 /// let subviews = view.try_load_entries_pairs(indices).await.unwrap();
1074 /// let value0 = subviews[0].1.as_ref().unwrap().get();
1075 /// assert_eq!(*value0, String::default());
1076 /// # })
1077 /// ```
1078 pub async fn try_load_entries_pairs<Q>(
1079 &self,
1080 indices: impl IntoIterator<Item = Q>,
1081 ) -> Result<Vec<(Q, Option<ReadGuardedView<W>>)>, ViewError>
1082 where
1083 I: Borrow<Q>,
1084 Q: Serialize + Clone,
1085 {
1086 let indices_vec: Vec<Q> = indices.into_iter().collect();
1087 let values = self.try_load_entries(indices_vec.iter()).await?;
1088 Ok(indices_vec.into_iter().zip(values).collect())
1089 }
1090
1091 /// Load all entries for reading at once.
1092 /// ```rust
1093 /// # tokio_test::block_on(async {
1094 /// # use linera_views::context::MemoryContext;
1095 /// # use linera_views::collection_view::CollectionView;
1096 /// # use linera_views::register_view::RegisterView;
1097 /// # use linera_views::views::View;
1098 /// # let context = MemoryContext::new_for_testing(());
1099 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1100 /// CollectionView::load(context).await.unwrap();
1101 /// {
1102 /// let _subview = view.load_entry_mut(&23).await.unwrap();
1103 /// }
1104 /// let subviews = view.try_load_all_entries().await.unwrap();
1105 /// assert_eq!(subviews.len(), 1);
1106 /// # })
1107 /// ```
1108 pub async fn try_load_all_entries(&self) -> Result<Vec<(I, ReadGuardedView<W>)>, ViewError>
1109 where
1110 I: DeserializeOwned,
1111 {
1112 let results = self.collection.try_load_all_entries().await?;
1113 results
1114 .into_iter()
1115 .map(|(short_key, view)| {
1116 let index = BaseKey::deserialize_value(&short_key)?;
1117 Ok((index, view))
1118 })
1119 .collect()
1120 }
1121
1122 /// Resets an entry to the default value.
1123 /// ```rust
1124 /// # tokio_test::block_on(async {
1125 /// # use linera_views::context::MemoryContext;
1126 /// # use linera_views::collection_view::CollectionView;
1127 /// # use linera_views::register_view::RegisterView;
1128 /// # use linera_views::views::View;
1129 /// # let context = MemoryContext::new_for_testing(());
1130 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1131 /// CollectionView::load(context).await.unwrap();
1132 /// let subview = view.load_entry_mut(&23).await.unwrap();
1133 /// let value = subview.get_mut();
1134 /// *value = String::from("Hello");
1135 /// view.reset_entry_to_default(&23).unwrap();
1136 /// let subview = view.load_entry_mut(&23).await.unwrap();
1137 /// let value = subview.get_mut();
1138 /// assert_eq!(*value, String::default());
1139 /// # })
1140 /// ```
1141 pub fn reset_entry_to_default<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1142 where
1143 I: Borrow<Q>,
1144 Q: Serialize + ?Sized,
1145 {
1146 let short_key = BaseKey::derive_short_key(index)?;
1147 self.collection.reset_entry_to_default(&short_key)
1148 }
1149
1150 /// Removes an entry from the `CollectionView`. If absent nothing happens.
1151 /// ```rust
1152 /// # tokio_test::block_on(async {
1153 /// # use linera_views::context::MemoryContext;
1154 /// # use linera_views::collection_view::CollectionView;
1155 /// # use linera_views::register_view::RegisterView;
1156 /// # use linera_views::views::View;
1157 /// # let context = MemoryContext::new_for_testing(());
1158 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1159 /// CollectionView::load(context).await.unwrap();
1160 /// let subview = view.load_entry_mut(&23).await.unwrap();
1161 /// let value = subview.get_mut();
1162 /// assert_eq!(*value, String::default());
1163 /// view.remove_entry(&23);
1164 /// let keys = view.indices().await.unwrap();
1165 /// assert_eq!(keys.len(), 0);
1166 /// # })
1167 /// ```
1168 pub fn remove_entry<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1169 where
1170 I: Borrow<Q>,
1171 Q: Serialize + ?Sized,
1172 {
1173 let short_key = BaseKey::derive_short_key(index)?;
1174 self.collection.remove_entry(short_key);
1175 Ok(())
1176 }
1177
1178 /// Gets the extra data.
1179 pub fn extra(&self) -> &<W::Context as Context>::Extra {
1180 self.collection.extra()
1181 }
1182}
1183
1184impl<I, W: View> CollectionView<W::Context, I, W>
1185where
1186 I: Sync + Send + Serialize + DeserializeOwned,
1187{
1188 /// Returns the list of indices in the collection in the order determined by
1189 /// the serialization.
1190 /// ```rust
1191 /// # tokio_test::block_on(async {
1192 /// # use linera_views::context::MemoryContext;
1193 /// # use linera_views::collection_view::CollectionView;
1194 /// # use linera_views::register_view::RegisterView;
1195 /// # use linera_views::views::View;
1196 /// # let context = MemoryContext::new_for_testing(());
1197 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1198 /// CollectionView::load(context).await.unwrap();
1199 /// view.load_entry_mut(&23).await.unwrap();
1200 /// view.load_entry_mut(&25).await.unwrap();
1201 /// let indices = view.indices().await.unwrap();
1202 /// assert_eq!(indices.len(), 2);
1203 /// # })
1204 /// ```
1205 pub async fn indices(&self) -> Result<Vec<I>, ViewError> {
1206 let mut indices = Vec::new();
1207 self.for_each_index(|index| {
1208 indices.push(index);
1209 Ok(())
1210 })
1211 .await?;
1212 Ok(indices)
1213 }
1214
1215 /// Returns the number of entries in the collection.
1216 /// ```rust
1217 /// # tokio_test::block_on(async {
1218 /// # use linera_views::context::MemoryContext;
1219 /// # use linera_views::collection_view::CollectionView;
1220 /// # use linera_views::register_view::RegisterView;
1221 /// # use linera_views::views::View;
1222 /// # let context = MemoryContext::new_for_testing(());
1223 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1224 /// CollectionView::load(context).await.unwrap();
1225 /// view.load_entry_mut(&23).await.unwrap();
1226 /// view.load_entry_mut(&25).await.unwrap();
1227 /// assert_eq!(view.count().await.unwrap(), 2);
1228 /// # })
1229 /// ```
1230 pub async fn count(&self) -> Result<usize, ViewError> {
1231 self.collection.count().await
1232 }
1233}
1234
1235impl<I: DeserializeOwned, W: View> CollectionView<W::Context, I, W> {
1236 /// Applies a function f on each index. Indices are visited in an order
1237 /// determined by the serialization. If the function returns false then
1238 /// the loop ends prematurely.
1239 /// ```rust
1240 /// # tokio_test::block_on(async {
1241 /// # use linera_views::context::MemoryContext;
1242 /// # use linera_views::collection_view::CollectionView;
1243 /// # use linera_views::register_view::RegisterView;
1244 /// # use linera_views::views::View;
1245 /// # let context = MemoryContext::new_for_testing(());
1246 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1247 /// CollectionView::load(context).await.unwrap();
1248 /// view.load_entry_mut(&23).await.unwrap();
1249 /// view.load_entry_mut(&24).await.unwrap();
1250 /// let mut count = 0;
1251 /// view.for_each_index_while(|_key| {
1252 /// count += 1;
1253 /// Ok(count < 1)
1254 /// })
1255 /// .await
1256 /// .unwrap();
1257 /// assert_eq!(count, 1);
1258 /// # })
1259 /// ```
1260 pub async fn for_each_index_while<F>(&self, mut f: F) -> Result<(), ViewError>
1261 where
1262 F: FnMut(I) -> Result<bool, ViewError> + Send,
1263 {
1264 self.collection
1265 .for_each_key_while(|key| {
1266 let index = BaseKey::deserialize_value(key)?;
1267 f(index)
1268 })
1269 .await?;
1270 Ok(())
1271 }
1272
1273 /// Applies a function f on each index. Indices are visited in an order
1274 /// determined by the serialization.
1275 /// ```rust
1276 /// # tokio_test::block_on(async {
1277 /// # use linera_views::context::MemoryContext;
1278 /// # use linera_views::collection_view::CollectionView;
1279 /// # use linera_views::register_view::RegisterView;
1280 /// # use linera_views::views::View;
1281 /// # let context = MemoryContext::new_for_testing(());
1282 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1283 /// CollectionView::load(context).await.unwrap();
1284 /// view.load_entry_mut(&23).await.unwrap();
1285 /// view.load_entry_mut(&28).await.unwrap();
1286 /// let mut count = 0;
1287 /// view.for_each_index(|_key| {
1288 /// count += 1;
1289 /// Ok(())
1290 /// })
1291 /// .await
1292 /// .unwrap();
1293 /// assert_eq!(count, 2);
1294 /// # })
1295 /// ```
1296 pub async fn for_each_index<F>(&self, mut f: F) -> Result<(), ViewError>
1297 where
1298 F: FnMut(I) -> Result<(), ViewError> + Send,
1299 {
1300 self.collection
1301 .for_each_key(|key| {
1302 let index = BaseKey::deserialize_value(key)?;
1303 f(index)
1304 })
1305 .await?;
1306 Ok(())
1307 }
1308}
1309
1310impl<I, W: HashableView> HashableView for CollectionView<W::Context, I, W>
1311where
1312 I: Send + Sync + Serialize + DeserializeOwned,
1313{
1314 type Hasher = sha3::Sha3_256;
1315
1316 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1317 self.collection.hash_mut().await
1318 }
1319
1320 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1321 self.collection.hash().await
1322 }
1323}
1324
1325/// A map view that serializes the indices.
1326#[derive(Debug, Allocative)]
1327#[allocative(bound = "C, I, W: Allocative")]
1328pub struct CustomCollectionView<C, I, W> {
1329 collection: ByteCollectionView<C, W>,
1330 #[allocative(skip)]
1331 _phantom: PhantomData<I>,
1332}
1333
1334impl<I: Send + Sync, W: View> View for CustomCollectionView<W::Context, I, W> {
1335 const NUM_INIT_KEYS: usize = ByteCollectionView::<W::Context, W>::NUM_INIT_KEYS;
1336
1337 type Context = W::Context;
1338
1339 fn context(&self) -> &Self::Context {
1340 self.collection.context()
1341 }
1342
1343 fn pre_load(context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
1344 ByteCollectionView::<_, W>::pre_load(context)
1345 }
1346
1347 fn post_load(context: Self::Context, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
1348 let collection = ByteCollectionView::post_load(context, values)?;
1349 Ok(CustomCollectionView {
1350 collection,
1351 _phantom: PhantomData,
1352 })
1353 }
1354
1355 fn rollback(&mut self) {
1356 self.collection.rollback()
1357 }
1358
1359 async fn has_pending_changes(&self) -> bool {
1360 self.collection.has_pending_changes().await
1361 }
1362
1363 fn pre_save(&self, batch: &mut Batch) -> Result<bool, ViewError> {
1364 self.collection.pre_save(batch)
1365 }
1366
1367 fn post_save(&mut self) {
1368 self.collection.post_save()
1369 }
1370
1371 fn clear(&mut self) {
1372 self.collection.clear()
1373 }
1374}
1375
1376impl<I: Send + Sync, W: ClonableView> ClonableView for CustomCollectionView<W::Context, I, W> {
1377 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
1378 Ok(CustomCollectionView {
1379 collection: self.collection.clone_unchecked()?,
1380 _phantom: PhantomData,
1381 })
1382 }
1383}
1384
1385impl<I: CustomSerialize, W: View> CustomCollectionView<W::Context, I, W> {
1386 /// Loads a subview for the data at the given index in the collection. If an entry
1387 /// is absent then a default entry is added to the collection. The resulting view
1388 /// can be modified.
1389 /// ```rust
1390 /// # tokio_test::block_on(async {
1391 /// # use linera_views::context::MemoryContext;
1392 /// # use linera_views::collection_view::CustomCollectionView;
1393 /// # use linera_views::register_view::RegisterView;
1394 /// # use linera_views::views::View;
1395 /// # let context = MemoryContext::new_for_testing(());
1396 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1397 /// CustomCollectionView::load(context).await.unwrap();
1398 /// let subview = view.load_entry_mut(&23).await.unwrap();
1399 /// let value = subview.get();
1400 /// assert_eq!(*value, String::default());
1401 /// # })
1402 /// ```
1403 pub async fn load_entry_mut<Q>(&mut self, index: &Q) -> Result<&mut W, ViewError>
1404 where
1405 I: Borrow<Q>,
1406 Q: CustomSerialize,
1407 {
1408 let short_key = index.to_custom_bytes()?;
1409 self.collection.load_entry_mut(&short_key).await
1410 }
1411
1412 /// Loads a subview for the data at the given index in the collection. If an entry
1413 /// is absent then `None` is returned. The resulting view cannot be modified.
1414 /// May fail if one subview is already being visited.
1415 /// ```rust
1416 /// # tokio_test::block_on(async {
1417 /// # use linera_views::context::MemoryContext;
1418 /// # use linera_views::collection_view::CustomCollectionView;
1419 /// # use linera_views::register_view::RegisterView;
1420 /// # use linera_views::views::View;
1421 /// # let context = MemoryContext::new_for_testing(());
1422 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1423 /// CustomCollectionView::load(context).await.unwrap();
1424 /// {
1425 /// let _subview = view.load_entry_mut(&23).await.unwrap();
1426 /// }
1427 /// {
1428 /// let subview = view.try_load_entry(&23).await.unwrap().unwrap();
1429 /// let value = subview.get();
1430 /// assert_eq!(*value, String::default());
1431 /// }
1432 /// assert!(view.try_load_entry(&24).await.unwrap().is_none());
1433 /// # })
1434 /// ```
1435 pub async fn try_load_entry<Q>(
1436 &self,
1437 index: &Q,
1438 ) -> Result<Option<ReadGuardedView<W>>, ViewError>
1439 where
1440 I: Borrow<Q>,
1441 Q: CustomSerialize,
1442 {
1443 let short_key = index.to_custom_bytes()?;
1444 self.collection.try_load_entry(&short_key).await
1445 }
1446
1447 /// Load multiple entries for reading at once.
1448 /// The entries in indices have to be all distinct.
1449 /// ```rust
1450 /// # tokio_test::block_on(async {
1451 /// # use linera_views::context::MemoryContext;
1452 /// # use linera_views::collection_view::CustomCollectionView;
1453 /// # use linera_views::register_view::RegisterView;
1454 /// # use linera_views::views::View;
1455 /// # let context = MemoryContext::new_for_testing(());
1456 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1457 /// CustomCollectionView::load(context).await.unwrap();
1458 /// {
1459 /// let _subview = view.load_entry_mut(&23).await.unwrap();
1460 /// }
1461 /// let subviews = view.try_load_entries(&[23, 42]).await.unwrap();
1462 /// let value0 = subviews[0].as_ref().unwrap().get();
1463 /// assert_eq!(*value0, String::default());
1464 /// # })
1465 /// ```
1466 pub async fn try_load_entries<'a, Q>(
1467 &self,
1468 indices: impl IntoIterator<Item = &'a Q>,
1469 ) -> Result<Vec<Option<ReadGuardedView<W>>>, ViewError>
1470 where
1471 I: Borrow<Q>,
1472 Q: CustomSerialize + 'a,
1473 {
1474 let short_keys = indices
1475 .into_iter()
1476 .map(|index| index.to_custom_bytes())
1477 .collect::<Result<_, _>>()?;
1478 self.collection.try_load_entries(short_keys).await
1479 }
1480
1481 /// Loads multiple entries for reading at once with their keys.
1482 /// The entries in indices have to be all distinct.
1483 /// ```rust
1484 /// # tokio_test::block_on(async {
1485 /// # use linera_views::context::MemoryContext;
1486 /// # use linera_views::collection_view::CustomCollectionView;
1487 /// # use linera_views::register_view::RegisterView;
1488 /// # use linera_views::views::View;
1489 /// # let context = MemoryContext::new_for_testing(());
1490 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1491 /// CustomCollectionView::load(context).await.unwrap();
1492 /// {
1493 /// let _subview = view.load_entry_mut(&23).await.unwrap();
1494 /// }
1495 /// let indices = [23, 42];
1496 /// let subviews = view.try_load_entries_pairs(indices).await.unwrap();
1497 /// let value0 = subviews[0].1.as_ref().unwrap().get();
1498 /// assert_eq!(*value0, String::default());
1499 /// # })
1500 /// ```
1501 pub async fn try_load_entries_pairs<Q>(
1502 &self,
1503 indices: impl IntoIterator<Item = Q>,
1504 ) -> Result<Vec<(Q, Option<ReadGuardedView<W>>)>, ViewError>
1505 where
1506 I: Borrow<Q>,
1507 Q: CustomSerialize + Clone,
1508 {
1509 let indices_vec: Vec<Q> = indices.into_iter().collect();
1510 let values = self.try_load_entries(indices_vec.iter()).await?;
1511 Ok(indices_vec.into_iter().zip(values).collect())
1512 }
1513
1514 /// Load all entries for reading at once.
1515 /// ```rust
1516 /// # tokio_test::block_on(async {
1517 /// # use linera_views::context::MemoryContext;
1518 /// # use linera_views::collection_view::CustomCollectionView;
1519 /// # use linera_views::register_view::RegisterView;
1520 /// # use linera_views::views::View;
1521 /// # let context = MemoryContext::new_for_testing(());
1522 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1523 /// CustomCollectionView::load(context).await.unwrap();
1524 /// {
1525 /// let _subview = view.load_entry_mut(&23).await.unwrap();
1526 /// }
1527 /// let subviews = view.try_load_all_entries().await.unwrap();
1528 /// assert_eq!(subviews.len(), 1);
1529 /// # })
1530 /// ```
1531 pub async fn try_load_all_entries(&self) -> Result<Vec<(I, ReadGuardedView<W>)>, ViewError>
1532 where
1533 I: CustomSerialize,
1534 {
1535 let results = self.collection.try_load_all_entries().await?;
1536 results
1537 .into_iter()
1538 .map(|(short_key, view)| {
1539 let index = I::from_custom_bytes(&short_key)?;
1540 Ok((index, view))
1541 })
1542 .collect()
1543 }
1544
1545 /// Marks the entry so that it is removed in the next flush.
1546 /// ```rust
1547 /// # tokio_test::block_on(async {
1548 /// # use linera_views::context::MemoryContext;
1549 /// # use linera_views::collection_view::CustomCollectionView;
1550 /// # use linera_views::register_view::RegisterView;
1551 /// # use linera_views::views::View;
1552 /// # let context = MemoryContext::new_for_testing(());
1553 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1554 /// CustomCollectionView::load(context).await.unwrap();
1555 /// let subview = view.load_entry_mut(&23).await.unwrap();
1556 /// let value = subview.get_mut();
1557 /// *value = String::from("Hello");
1558 /// view.reset_entry_to_default(&23).unwrap();
1559 /// let subview = view.load_entry_mut(&23).await.unwrap();
1560 /// let value = subview.get_mut();
1561 /// assert_eq!(*value, String::default());
1562 /// # })
1563 /// ```
1564 pub fn reset_entry_to_default<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1565 where
1566 I: Borrow<Q>,
1567 Q: CustomSerialize,
1568 {
1569 let short_key = index.to_custom_bytes()?;
1570 self.collection.reset_entry_to_default(&short_key)
1571 }
1572
1573 /// Removes an entry from the `CollectionView`. If absent nothing happens.
1574 /// ```rust
1575 /// # tokio_test::block_on(async {
1576 /// # use linera_views::context::MemoryContext;
1577 /// # use linera_views::collection_view::CustomCollectionView;
1578 /// # use linera_views::register_view::RegisterView;
1579 /// # use linera_views::views::View;
1580 /// # let context = MemoryContext::new_for_testing(());
1581 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1582 /// CustomCollectionView::load(context).await.unwrap();
1583 /// let subview = view.load_entry_mut(&23).await.unwrap();
1584 /// let value = subview.get_mut();
1585 /// assert_eq!(*value, String::default());
1586 /// view.remove_entry(&23);
1587 /// let keys = view.indices().await.unwrap();
1588 /// assert_eq!(keys.len(), 0);
1589 /// # })
1590 /// ```
1591 pub fn remove_entry<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1592 where
1593 I: Borrow<Q>,
1594 Q: CustomSerialize,
1595 {
1596 let short_key = index.to_custom_bytes()?;
1597 self.collection.remove_entry(short_key);
1598 Ok(())
1599 }
1600
1601 /// Gets the extra data.
1602 pub fn extra(&self) -> &<W::Context as Context>::Extra {
1603 self.collection.extra()
1604 }
1605}
1606
1607impl<I: CustomSerialize + Send, W: View> CustomCollectionView<W::Context, I, W> {
1608 /// Returns the list of indices in the collection in the order determined by the custom serialization.
1609 /// ```rust
1610 /// # tokio_test::block_on(async {
1611 /// # use linera_views::context::MemoryContext;
1612 /// # use linera_views::collection_view::CustomCollectionView;
1613 /// # use linera_views::register_view::RegisterView;
1614 /// # use linera_views::views::View;
1615 /// # let context = MemoryContext::new_for_testing(());
1616 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1617 /// CustomCollectionView::load(context).await.unwrap();
1618 /// view.load_entry_mut(&23).await.unwrap();
1619 /// view.load_entry_mut(&25).await.unwrap();
1620 /// let indices = view.indices().await.unwrap();
1621 /// assert_eq!(indices, vec![23, 25]);
1622 /// # })
1623 /// ```
1624 pub async fn indices(&self) -> Result<Vec<I>, ViewError> {
1625 let mut indices = Vec::new();
1626 self.for_each_index(|index| {
1627 indices.push(index);
1628 Ok(())
1629 })
1630 .await?;
1631 Ok(indices)
1632 }
1633
1634 /// Returns the number of entries in the collection.
1635 /// ```rust
1636 /// # tokio_test::block_on(async {
1637 /// # use linera_views::context::MemoryContext;
1638 /// # use linera_views::collection_view::CollectionView;
1639 /// # use linera_views::register_view::RegisterView;
1640 /// # use linera_views::views::View;
1641 /// # let context = MemoryContext::new_for_testing(());
1642 /// let mut view: CollectionView<_, u64, RegisterView<_, String>> =
1643 /// CollectionView::load(context).await.unwrap();
1644 /// view.load_entry_mut(&23).await.unwrap();
1645 /// view.load_entry_mut(&25).await.unwrap();
1646 /// assert_eq!(view.count().await.unwrap(), 2);
1647 /// # })
1648 /// ```
1649 pub async fn count(&self) -> Result<usize, ViewError> {
1650 self.collection.count().await
1651 }
1652}
1653
1654impl<I: CustomSerialize, W: View> CustomCollectionView<W::Context, I, W> {
1655 /// Applies a function f on each index. Indices are visited in an order
1656 /// determined by the custom serialization. If the function f returns false,
1657 /// then the loop ends prematurely.
1658 /// ```rust
1659 /// # tokio_test::block_on(async {
1660 /// # use linera_views::context::MemoryContext;
1661 /// # use linera_views::collection_view::CustomCollectionView;
1662 /// # use linera_views::register_view::RegisterView;
1663 /// # use linera_views::views::View;
1664 /// # let context = MemoryContext::new_for_testing(());
1665 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1666 /// CustomCollectionView::load(context).await.unwrap();
1667 /// view.load_entry_mut(&28).await.unwrap();
1668 /// view.load_entry_mut(&24).await.unwrap();
1669 /// view.load_entry_mut(&23).await.unwrap();
1670 /// let mut part_indices = Vec::new();
1671 /// view.for_each_index_while(|index| {
1672 /// part_indices.push(index);
1673 /// Ok(part_indices.len() < 2)
1674 /// })
1675 /// .await
1676 /// .unwrap();
1677 /// assert_eq!(part_indices, vec![23, 24]);
1678 /// # })
1679 /// ```
1680 pub async fn for_each_index_while<F>(&self, mut f: F) -> Result<(), ViewError>
1681 where
1682 F: FnMut(I) -> Result<bool, ViewError> + Send,
1683 {
1684 self.collection
1685 .for_each_key_while(|key| {
1686 let index = I::from_custom_bytes(key)?;
1687 f(index)
1688 })
1689 .await?;
1690 Ok(())
1691 }
1692
1693 /// Applies a function on each index. Indices are visited in an order
1694 /// determined by the custom serialization.
1695 /// ```rust
1696 /// # tokio_test::block_on(async {
1697 /// # use linera_views::context::MemoryContext;
1698 /// # use linera_views::collection_view::CustomCollectionView;
1699 /// # use linera_views::register_view::RegisterView;
1700 /// # use linera_views::views::View;
1701 /// # let context = MemoryContext::new_for_testing(());
1702 /// let mut view: CustomCollectionView<_, u128, RegisterView<_, String>> =
1703 /// CustomCollectionView::load(context).await.unwrap();
1704 /// view.load_entry_mut(&28).await.unwrap();
1705 /// view.load_entry_mut(&24).await.unwrap();
1706 /// view.load_entry_mut(&23).await.unwrap();
1707 /// let mut indices = Vec::new();
1708 /// view.for_each_index(|index| {
1709 /// indices.push(index);
1710 /// Ok(())
1711 /// })
1712 /// .await
1713 /// .unwrap();
1714 /// assert_eq!(indices, vec![23, 24, 28]);
1715 /// # })
1716 /// ```
1717 pub async fn for_each_index<F>(&self, mut f: F) -> Result<(), ViewError>
1718 where
1719 F: FnMut(I) -> Result<(), ViewError> + Send,
1720 {
1721 self.collection
1722 .for_each_key(|key| {
1723 let index = I::from_custom_bytes(key)?;
1724 f(index)
1725 })
1726 .await?;
1727 Ok(())
1728 }
1729}
1730
1731impl<I, W: HashableView> HashableView for CustomCollectionView<W::Context, I, W>
1732where
1733 Self: View,
1734{
1735 type Hasher = sha3::Sha3_256;
1736
1737 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1738 self.collection.hash_mut().await
1739 }
1740
1741 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1742 self.collection.hash().await
1743 }
1744}
1745
1746/// Type wrapping `ByteCollectionView` while memoizing the hash.
1747pub type HashedByteCollectionView<C, W> =
1748 WrappedHashableContainerView<C, ByteCollectionView<C, W>, HasherOutput>;
1749
1750/// Wrapper around `ByteCollectionView` to compute hashes based on the history of changes.
1751pub type HistoricallyHashedByteCollectionView<C, W> =
1752 HistoricallyHashableView<C, ByteCollectionView<C, W>>;
1753
1754/// Type wrapping `CollectionView` while memoizing the hash.
1755pub type HashedCollectionView<C, I, W> =
1756 WrappedHashableContainerView<C, CollectionView<C, I, W>, HasherOutput>;
1757
1758/// Wrapper around `CollectionView` to compute hashes based on the history of changes.
1759pub type HistoricallyHashedCollectionView<C, I, W> =
1760 HistoricallyHashableView<C, CollectionView<C, I, W>>;
1761
1762/// Type wrapping `CustomCollectionView` while memoizing the hash.
1763pub type HashedCustomCollectionView<C, I, W> =
1764 WrappedHashableContainerView<C, CustomCollectionView<C, I, W>, HasherOutput>;
1765
1766/// Wrapper around `CustomCollectionView` to compute hashes based on the history of changes.
1767pub type HistoricallyHashedCustomCollectionView<C, I, W> =
1768 HistoricallyHashableView<C, CustomCollectionView<C, I, W>>;
1769
1770#[cfg(with_graphql)]
1771mod graphql {
1772 use std::borrow::Cow;
1773
1774 use super::{CollectionView, CustomCollectionView, ReadGuardedView};
1775 use crate::{
1776 graphql::{hash_name, mangle, missing_key_error, Entry, MapInput},
1777 views::View,
1778 };
1779
1780 impl<T: async_graphql::OutputType> async_graphql::OutputType for ReadGuardedView<'_, T> {
1781 fn type_name() -> Cow<'static, str> {
1782 T::type_name()
1783 }
1784
1785 fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
1786 T::create_type_info(registry)
1787 }
1788
1789 async fn resolve(
1790 &self,
1791 ctx: &async_graphql::ContextSelectionSet<'_>,
1792 field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
1793 ) -> async_graphql::ServerResult<async_graphql::Value> {
1794 (**self).resolve(ctx, field).await
1795 }
1796 }
1797
1798 impl<C: Send + Sync, K: async_graphql::OutputType, V: async_graphql::OutputType>
1799 async_graphql::TypeName for CollectionView<C, K, V>
1800 {
1801 fn type_name() -> Cow<'static, str> {
1802 format!(
1803 "CollectionView_{}_{}_{:08x}",
1804 mangle(K::type_name()),
1805 mangle(V::type_name()),
1806 hash_name::<(K, V)>(),
1807 )
1808 .into()
1809 }
1810 }
1811
1812 #[async_graphql::Object(cache_control(no_cache), name_type)]
1813 impl<K, V> CollectionView<V::Context, K, V>
1814 where
1815 K: async_graphql::InputType
1816 + async_graphql::OutputType
1817 + serde::ser::Serialize
1818 + serde::de::DeserializeOwned
1819 + std::fmt::Debug,
1820 V: View + async_graphql::OutputType,
1821 {
1822 async fn keys(&self) -> Result<Vec<K>, async_graphql::Error> {
1823 Ok(self.indices().await?)
1824 }
1825
1826 #[graphql(derived(name = "count"))]
1827 async fn count_(&self) -> Result<u32, async_graphql::Error> {
1828 Ok(self.count().await? as u32)
1829 }
1830
1831 async fn entry(
1832 &self,
1833 key: K,
1834 ) -> Result<Entry<K, ReadGuardedView<V>>, async_graphql::Error> {
1835 let value = self
1836 .try_load_entry(&key)
1837 .await?
1838 .ok_or_else(|| missing_key_error(&key))?;
1839 Ok(Entry { value, key })
1840 }
1841
1842 async fn entries(
1843 &self,
1844 input: Option<MapInput<K>>,
1845 ) -> Result<Vec<Entry<K, ReadGuardedView<V>>>, async_graphql::Error> {
1846 let keys = if let Some(keys) = input
1847 .and_then(|input| input.filters)
1848 .and_then(|filters| filters.keys)
1849 {
1850 keys
1851 } else {
1852 self.indices().await?
1853 };
1854
1855 let values = self.try_load_entries(&keys).await?;
1856 Ok(values
1857 .into_iter()
1858 .zip(keys)
1859 .filter_map(|(value, key)| value.map(|value| Entry { value, key }))
1860 .collect())
1861 }
1862 }
1863
1864 impl<C: Send + Sync, K: async_graphql::InputType, V: async_graphql::OutputType>
1865 async_graphql::TypeName for CustomCollectionView<C, K, V>
1866 {
1867 fn type_name() -> Cow<'static, str> {
1868 format!(
1869 "CustomCollectionView_{}_{}_{:08x}",
1870 mangle(K::type_name()),
1871 mangle(V::type_name()),
1872 hash_name::<(K, V)>(),
1873 )
1874 .into()
1875 }
1876 }
1877
1878 #[async_graphql::Object(cache_control(no_cache), name_type)]
1879 impl<K, V> CustomCollectionView<V::Context, K, V>
1880 where
1881 K: async_graphql::InputType
1882 + async_graphql::OutputType
1883 + crate::common::CustomSerialize
1884 + std::fmt::Debug,
1885 V: View + async_graphql::OutputType,
1886 {
1887 async fn keys(&self) -> Result<Vec<K>, async_graphql::Error> {
1888 Ok(self.indices().await?)
1889 }
1890
1891 #[graphql(derived(name = "count"))]
1892 async fn count_(&self) -> Result<u32, async_graphql::Error> {
1893 Ok(self.count().await? as u32)
1894 }
1895
1896 async fn entry(
1897 &self,
1898 key: K,
1899 ) -> Result<Entry<K, ReadGuardedView<V>>, async_graphql::Error> {
1900 let value = self
1901 .try_load_entry(&key)
1902 .await?
1903 .ok_or_else(|| missing_key_error(&key))?;
1904 Ok(Entry { value, key })
1905 }
1906
1907 async fn entries(
1908 &self,
1909 input: Option<MapInput<K>>,
1910 ) -> Result<Vec<Entry<K, ReadGuardedView<V>>>, async_graphql::Error> {
1911 let keys = if let Some(keys) = input
1912 .and_then(|input| input.filters)
1913 .and_then(|filters| filters.keys)
1914 {
1915 keys
1916 } else {
1917 self.indices().await?
1918 };
1919
1920 let values = self.try_load_entries(&keys).await?;
1921 Ok(values
1922 .into_iter()
1923 .zip(keys)
1924 .filter_map(|(value, key)| value.map(|value| Entry { value, key }))
1925 .collect())
1926 }
1927 }
1928}