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