linera_views/views/reentrant_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 sync::Arc,
12};
13
14use allocative::{Allocative, Key, Visitor};
15use async_lock::{RwLock, RwLockReadGuardArc, RwLockWriteGuardArc};
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, ReplaceContext, 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 REENTRANT_COLLECTION_VIEW_HASH_RUNTIME: LazyLock<HistogramVec> =
39 LazyLock::new(|| {
40 register_histogram_vec(
41 "reentrant_collection_view_hash_runtime",
42 "ReentrantCollectionView hash runtime",
43 &[],
44 exponential_bucket_latencies(5.0),
45 )
46 });
47}
48
49/// A read-only accessor for a particular subview in a [`ReentrantCollectionView`].
50#[derive(Debug)]
51pub struct ReadGuardedView<T>(RwLockReadGuardArc<T>);
52
53impl<T> std::ops::Deref for ReadGuardedView<T> {
54 type Target = T;
55 fn deref(&self) -> &T {
56 self.0.deref()
57 }
58}
59
60/// A read-write accessor for a particular subview in a [`ReentrantCollectionView`].
61#[derive(Debug)]
62pub struct WriteGuardedView<T>(RwLockWriteGuardArc<T>);
63
64impl<T> std::ops::Deref for WriteGuardedView<T> {
65 type Target = T;
66 fn deref(&self) -> &T {
67 self.0.deref()
68 }
69}
70
71impl<T> std::ops::DerefMut for WriteGuardedView<T> {
72 fn deref_mut(&mut self) -> &mut T {
73 self.0.deref_mut()
74 }
75}
76
77/// A view that supports accessing a collection of views of the same kind, indexed by `Vec<u8>`,
78/// possibly several subviews at a time.
79#[derive(Debug)]
80pub struct ReentrantByteCollectionView<C, W> {
81 /// The view [`Context`].
82 context: C,
83 /// If the current persisted data will be completely erased and replaced on the next flush.
84 delete_storage_first: bool,
85 /// Entries that may have staged changes.
86 updates: BTreeMap<Vec<u8>, Update<Arc<RwLock<W>>>>,
87}
88
89impl<C, W: Allocative> Allocative for ReentrantByteCollectionView<C, W> {
90 fn visit<'a, 'b: 'a>(&self, visitor: &'a mut Visitor<'b>) {
91 let name = Key::new("ReentrantByteCollectionView");
92 let size = mem::size_of::<Self>();
93 let mut visitor = visitor.enter(name, size);
94
95 for (k, v) in &self.updates {
96 let key_name = Key::new("key");
97 visitor.visit_field(key_name, k);
98 match v {
99 Update::Removed => {
100 let key = Key::new("update_removed");
101 visitor.visit_field(key, &());
102 }
103 Update::Set(v) => {
104 if let Some(v) = v.try_read() {
105 let key = Key::new("update_set");
106 visitor.visit_field(key, v.deref());
107 }
108 }
109 }
110 }
111 visitor.exit();
112 }
113}
114
115impl<W, C2> ReplaceContext<C2> for ReentrantByteCollectionView<W::Context, W>
116where
117 W: View + ReplaceContext<C2>,
118 C2: Context,
119{
120 type Target = ReentrantByteCollectionView<C2, <W as ReplaceContext<C2>>::Target>;
121
122 async fn with_context(
123 &mut self,
124 ctx: impl FnOnce(&Self::Context) -> C2 + Clone,
125 ) -> Self::Target {
126 let mut updates: BTreeMap<_, Update<Arc<RwLock<W::Target>>>> = BTreeMap::new();
127 for (key, update) in &self.updates {
128 let new_value = match update {
129 Update::Removed => Update::Removed,
130 Update::Set(x) => Update::Set(Arc::new(RwLock::new(
131 x.write().await.with_context(ctx.clone()).await,
132 ))),
133 };
134 updates.insert(key.clone(), new_value);
135 }
136 ReentrantByteCollectionView {
137 context: ctx(&self.context),
138 delete_storage_first: self.delete_storage_first,
139 updates,
140 }
141 }
142}
143
144/// We need to find new base keys in order to implement the collection view.
145/// We do this by appending a value to the base key.
146///
147/// Sub-views in a collection share a common key prefix, like in other view types. However,
148/// just concatenating the shared prefix with sub-view keys makes it impossible to distinguish if a
149/// given key belongs to a child sub-view or a grandchild sub-view (consider for example if a
150/// collection is stored inside the collection).
151#[repr(u8)]
152enum KeyTag {
153 /// Prefix for specifying an index and serves to indicate the existence of an entry in the collection.
154 Index = MIN_VIEW_TAG,
155 /// Prefix for specifying as the prefix for the sub-view.
156 Subview,
157}
158
159impl<W: View> View for ReentrantByteCollectionView<W::Context, W> {
160 const NUM_INIT_KEYS: usize = 0;
161
162 type Context = W::Context;
163
164 fn context(&self) -> Self::Context {
165 self.context.clone()
166 }
167
168 fn pre_load(_context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
169 Ok(Vec::new())
170 }
171
172 fn post_load(context: Self::Context, _values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
173 Ok(Self {
174 context,
175 delete_storage_first: false,
176 updates: BTreeMap::new(),
177 })
178 }
179
180 fn rollback(&mut self) {
181 self.delete_storage_first = false;
182 self.updates.clear();
183 }
184
185 async fn has_pending_changes(&self) -> bool {
186 if self.delete_storage_first {
187 return true;
188 }
189 !self.updates.is_empty()
190 }
191
192 fn pre_save(&self, batch: &mut Batch) -> Result<bool, ViewError> {
193 let mut delete_view = false;
194 if self.delete_storage_first {
195 delete_view = true;
196 batch.delete_key_prefix(self.context.base_key().bytes.clone());
197 for (index, update) in &self.updates {
198 if let Update::Set(view) = update {
199 let view = view
200 .try_read()
201 .ok_or_else(|| ViewError::TryLockError(index.clone()))?;
202 view.pre_save(batch)?;
203 self.add_index(batch, index);
204 delete_view = false;
205 }
206 }
207 } else {
208 for (index, update) in &self.updates {
209 match update {
210 Update::Set(view) => {
211 let view = view
212 .try_read()
213 .ok_or_else(|| ViewError::TryLockError(index.clone()))?;
214 view.pre_save(batch)?;
215 self.add_index(batch, index);
216 }
217 Update::Removed => {
218 let key_subview = self.get_subview_key(index);
219 let key_index = self.get_index_key(index);
220 batch.delete_key(key_index);
221 batch.delete_key_prefix(key_subview);
222 }
223 }
224 }
225 }
226 Ok(delete_view)
227 }
228
229 fn post_save(&mut self) {
230 for (_index, update) in mem::take(&mut self.updates) {
231 if let Update::Set(view) = update {
232 let mut view = view.try_write().expect("pre_save was called before");
233 view.post_save();
234 }
235 }
236 self.delete_storage_first = false;
237 }
238
239 fn clear(&mut self) {
240 self.delete_storage_first = true;
241 self.updates.clear();
242 }
243}
244
245impl<W: ClonableView> ClonableView for ReentrantByteCollectionView<W::Context, W> {
246 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
247 let cloned_updates = self
248 .updates
249 .iter()
250 .map(|(key, value)| {
251 let cloned_value = match value {
252 Update::Removed => Update::Removed,
253 Update::Set(view_lock) => {
254 let mut view = view_lock
255 .try_write()
256 .ok_or_else(|| ViewError::TryLockError(key.clone()))?;
257 Update::Set(Arc::new(RwLock::new(view.clone_unchecked()?)))
258 }
259 };
260 Ok::<_, ViewError>((key.clone(), cloned_value))
261 })
262 .collect::<Result<_, _>>()?;
263
264 Ok(ReentrantByteCollectionView {
265 context: self.context.clone(),
266 delete_storage_first: self.delete_storage_first,
267 updates: cloned_updates,
268 })
269 }
270}
271
272impl<C: Context, W> ReentrantByteCollectionView<C, W> {
273 fn get_index_key(&self, index: &[u8]) -> Vec<u8> {
274 self.context
275 .base_key()
276 .base_tag_index(KeyTag::Index as u8, index)
277 }
278
279 fn get_subview_key(&self, index: &[u8]) -> Vec<u8> {
280 self.context
281 .base_key()
282 .base_tag_index(KeyTag::Subview as u8, index)
283 }
284
285 fn add_index(&self, batch: &mut Batch, index: &[u8]) {
286 let key = self.get_index_key(index);
287 batch.put_key_value_bytes(key, vec![]);
288 }
289}
290
291impl<W: View> ReentrantByteCollectionView<W::Context, W> {
292 /// Reads the view and if missing returns the default view
293 async fn wrapped_view(
294 context: &W::Context,
295 delete_storage_first: bool,
296 short_key: &[u8],
297 ) -> Result<Arc<RwLock<W>>, ViewError> {
298 let key = context
299 .base_key()
300 .base_tag_index(KeyTag::Subview as u8, short_key);
301 let context = context.clone_with_base_key(key);
302 // Obtain a view and set its pending state to the default (e.g. empty) state
303 let view = if delete_storage_first {
304 W::new(context)?
305 } else {
306 W::load(context).await?
307 };
308 Ok(Arc::new(RwLock::new(view)))
309 }
310
311 /// Load the view and insert it into the updates if needed.
312 /// If the entry is missing, then it is set to default.
313 async fn try_load_view_mut(&mut self, short_key: &[u8]) -> Result<Arc<RwLock<W>>, ViewError> {
314 use btree_map::Entry::*;
315 Ok(match self.updates.entry(short_key.to_owned()) {
316 Occupied(mut entry) => match entry.get_mut() {
317 Update::Set(view) => view.clone(),
318 entry @ Update::Removed => {
319 let wrapped_view = Self::wrapped_view(&self.context, true, short_key).await?;
320 *entry = Update::Set(wrapped_view.clone());
321 wrapped_view
322 }
323 },
324 Vacant(entry) => {
325 let wrapped_view =
326 Self::wrapped_view(&self.context, self.delete_storage_first, short_key).await?;
327 entry.insert(Update::Set(wrapped_view.clone()));
328 wrapped_view
329 }
330 })
331 }
332
333 /// Load the view from the update is available.
334 /// If missing, then the entry is loaded from storage and if
335 /// missing there an error is reported.
336 async fn try_load_view(&self, short_key: &[u8]) -> Result<Option<Arc<RwLock<W>>>, ViewError> {
337 Ok(if let Some(entry) = self.updates.get(short_key) {
338 match entry {
339 Update::Set(view) => Some(view.clone()),
340 _entry @ Update::Removed => None,
341 }
342 } else if self.delete_storage_first {
343 None
344 } else {
345 let key_index = self
346 .context
347 .base_key()
348 .base_tag_index(KeyTag::Index as u8, short_key);
349 if self.context.store().contains_key(&key_index).await? {
350 let view = Self::wrapped_view(&self.context, false, short_key).await?;
351 Some(view)
352 } else {
353 None
354 }
355 })
356 }
357
358 /// Loads a subview for the data at the given index in the collection. If an entry
359 /// is absent then a default entry is added to the collection. The resulting view
360 /// can be modified.
361 /// ```rust
362 /// # tokio_test::block_on(async {
363 /// # use linera_views::context::MemoryContext;
364 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
365 /// # use linera_views::register_view::RegisterView;
366 /// # use linera_views::views::View;
367 /// # let context = MemoryContext::new_for_testing(());
368 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
369 /// ReentrantByteCollectionView::load(context).await.unwrap();
370 /// let subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
371 /// let value = subview.get();
372 /// assert_eq!(*value, String::default());
373 /// # })
374 /// ```
375 pub async fn try_load_entry_mut(
376 &mut self,
377 short_key: &[u8],
378 ) -> Result<WriteGuardedView<W>, ViewError> {
379 Ok(WriteGuardedView(
380 self.try_load_view_mut(short_key)
381 .await?
382 .try_write_arc()
383 .ok_or_else(|| ViewError::TryLockError(short_key.to_vec()))?,
384 ))
385 }
386
387 /// Loads a subview at the given index in the collection and gives read-only access to the data.
388 /// If an entry is absent then `None` is returned.
389 /// ```rust
390 /// # tokio_test::block_on(async {
391 /// # use linera_views::context::MemoryContext;
392 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
393 /// # use linera_views::register_view::RegisterView;
394 /// # use linera_views::views::View;
395 /// # let context = MemoryContext::new_for_testing(());
396 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
397 /// ReentrantByteCollectionView::load(context).await.unwrap();
398 /// {
399 /// let _subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
400 /// }
401 /// let subview = view.try_load_entry(&[0, 1]).await.unwrap().unwrap();
402 /// let value = subview.get();
403 /// assert_eq!(*value, String::default());
404 /// # })
405 /// ```
406 pub async fn try_load_entry(
407 &self,
408 short_key: &[u8],
409 ) -> Result<Option<ReadGuardedView<W>>, ViewError> {
410 match self.try_load_view(short_key).await? {
411 None => Ok(None),
412 Some(view) => Ok(Some(ReadGuardedView(
413 view.try_read_arc()
414 .ok_or_else(|| ViewError::TryLockError(short_key.to_vec()))?,
415 ))),
416 }
417 }
418
419 /// Returns `true` if the collection contains a value for the specified key.
420 /// ```rust
421 /// # tokio_test::block_on(async {
422 /// # use linera_views::context::MemoryContext;
423 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
424 /// # use linera_views::register_view::RegisterView;
425 /// # use linera_views::views::View;
426 /// # let context = MemoryContext::new_for_testing(());
427 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
428 /// ReentrantByteCollectionView::load(context).await.unwrap();
429 /// let _subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
430 /// assert!(view.contains_key(&[0, 1]).await.unwrap());
431 /// assert!(!view.contains_key(&[0, 2]).await.unwrap());
432 /// # })
433 /// ```
434 pub async fn contains_key(&self, short_key: &[u8]) -> Result<bool, ViewError> {
435 Ok(if let Some(entry) = self.updates.get(short_key) {
436 match entry {
437 Update::Set(_view) => true,
438 Update::Removed => false,
439 }
440 } else if self.delete_storage_first {
441 false
442 } else {
443 let key_index = self
444 .context
445 .base_key()
446 .base_tag_index(KeyTag::Index as u8, short_key);
447 self.context.store().contains_key(&key_index).await?
448 })
449 }
450
451 /// Removes an entry. If absent then nothing happens.
452 /// ```rust
453 /// # tokio_test::block_on(async {
454 /// # use linera_views::context::MemoryContext;
455 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
456 /// # use linera_views::register_view::RegisterView;
457 /// # use linera_views::views::View;
458 /// # let context = MemoryContext::new_for_testing(());
459 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
460 /// ReentrantByteCollectionView::load(context).await.unwrap();
461 /// let mut subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
462 /// let value = subview.get_mut();
463 /// assert_eq!(*value, String::default());
464 /// view.remove_entry(vec![0, 1]);
465 /// let keys = view.keys().await.unwrap();
466 /// assert_eq!(keys.len(), 0);
467 /// # })
468 /// ```
469 pub fn remove_entry(&mut self, short_key: Vec<u8>) {
470 if self.delete_storage_first {
471 // Optimization: No need to mark `short_key` for deletion as we are going to remove all the keys at once.
472 self.updates.remove(&short_key);
473 } else {
474 self.updates.insert(short_key, Update::Removed);
475 }
476 }
477
478 /// Marks the entry so that it is removed in the next flush.
479 /// ```rust
480 /// # tokio_test::block_on(async {
481 /// # use linera_views::context::MemoryContext;
482 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
483 /// # use linera_views::register_view::RegisterView;
484 /// # use linera_views::views::View;
485 /// # let context = MemoryContext::new_for_testing(());
486 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
487 /// ReentrantByteCollectionView::load(context).await.unwrap();
488 /// {
489 /// let mut subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
490 /// let value = subview.get_mut();
491 /// *value = String::from("Hello");
492 /// }
493 /// view.try_reset_entry_to_default(&[0, 1]).unwrap();
494 /// let mut subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
495 /// let value = subview.get_mut();
496 /// assert_eq!(*value, String::default());
497 /// # })
498 /// ```
499 pub fn try_reset_entry_to_default(&mut self, short_key: &[u8]) -> Result<(), ViewError> {
500 let key = self
501 .context
502 .base_key()
503 .base_tag_index(KeyTag::Subview as u8, short_key);
504 let context = self.context.clone_with_base_key(key);
505 let view = W::new(context)?;
506 let view = Arc::new(RwLock::new(view));
507 let view = Update::Set(view);
508 self.updates.insert(short_key.to_vec(), view);
509 Ok(())
510 }
511
512 /// Gets the extra data.
513 pub fn extra(&self) -> &<W::Context as Context>::Extra {
514 self.context.extra()
515 }
516}
517
518impl<W: View> ReentrantByteCollectionView<W::Context, W> {
519 /// Loads multiple entries for writing at once.
520 /// The entries in `short_keys` have to be all distinct.
521 /// ```rust
522 /// # tokio_test::block_on(async {
523 /// # use linera_views::context::MemoryContext;
524 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
525 /// # use linera_views::register_view::RegisterView;
526 /// # use linera_views::views::View;
527 /// # let context = MemoryContext::new_for_testing(());
528 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
529 /// ReentrantByteCollectionView::load(context).await.unwrap();
530 /// {
531 /// let mut subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
532 /// *subview.get_mut() = "Bonjour".to_string();
533 /// }
534 /// let short_keys = vec![vec![0, 1], vec![2, 3]];
535 /// let subviews = view.try_load_entries_mut(short_keys).await.unwrap();
536 /// let value1 = subviews[0].get();
537 /// let value2 = subviews[1].get();
538 /// assert_eq!(*value1, "Bonjour".to_string());
539 /// assert_eq!(*value2, String::default());
540 /// # })
541 /// ```
542 pub async fn try_load_entries_mut(
543 &mut self,
544 short_keys: Vec<Vec<u8>>,
545 ) -> Result<Vec<WriteGuardedView<W>>, ViewError> {
546 let mut short_keys_to_load = Vec::new();
547 let mut keys = Vec::new();
548 for short_key in &short_keys {
549 let key = self
550 .context
551 .base_key()
552 .base_tag_index(KeyTag::Subview as u8, short_key);
553 let context = self.context.clone_with_base_key(key);
554 match self.updates.entry(short_key.to_vec()) {
555 btree_map::Entry::Occupied(mut entry) => {
556 if let Update::Removed = entry.get() {
557 let view = W::new(context)?;
558 let view = Arc::new(RwLock::new(view));
559 entry.insert(Update::Set(view));
560 }
561 }
562 btree_map::Entry::Vacant(entry) => {
563 if self.delete_storage_first {
564 let view = W::new(context)?;
565 let view = Arc::new(RwLock::new(view));
566 entry.insert(Update::Set(view));
567 } else {
568 keys.extend(W::pre_load(&context)?);
569 short_keys_to_load.push(short_key.to_vec());
570 }
571 }
572 }
573 }
574 let values = self.context.store().read_multi_values_bytes(&keys).await?;
575 for (loaded_values, short_key) in values
576 .chunks_exact_or_repeat(W::NUM_INIT_KEYS)
577 .zip(short_keys_to_load)
578 {
579 let key = self
580 .context
581 .base_key()
582 .base_tag_index(KeyTag::Subview as u8, &short_key);
583 let context = self.context.clone_with_base_key(key);
584 let view = W::post_load(context, loaded_values)?;
585 let wrapped_view = Arc::new(RwLock::new(view));
586 self.updates
587 .insert(short_key.to_vec(), Update::Set(wrapped_view));
588 }
589
590 short_keys
591 .into_iter()
592 .map(|short_key| {
593 let Some(Update::Set(view)) = self.updates.get(&short_key) else {
594 unreachable!()
595 };
596 Ok(WriteGuardedView(
597 view.clone()
598 .try_write_arc()
599 .ok_or_else(|| ViewError::TryLockError(short_key))?,
600 ))
601 })
602 .collect()
603 }
604
605 /// Loads multiple entries for writing at once with their keys.
606 /// The entries in short_keys have to be all distinct.
607 /// ```rust
608 /// # tokio_test::block_on(async {
609 /// # use linera_views::context::MemoryContext;
610 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
611 /// # use linera_views::register_view::RegisterView;
612 /// # use linera_views::views::View;
613 /// # let context = MemoryContext::new_for_testing(());
614 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
615 /// ReentrantByteCollectionView::load(context).await.unwrap();
616 /// {
617 /// let mut subview = view.try_load_entry_mut(&vec![0, 1]).await.unwrap();
618 /// *subview.get_mut() = "Bonjour".to_string();
619 /// }
620 /// let short_keys = vec![vec![0, 1], vec![2, 3]];
621 /// let subviews = view.try_load_entries_pairs_mut(short_keys).await.unwrap();
622 /// let value1 = subviews[0].1.get();
623 /// let value2 = subviews[1].1.get();
624 /// assert_eq!(*value1, "Bonjour".to_string());
625 /// assert_eq!(*value2, String::default());
626 /// # })
627 /// ```
628 pub async fn try_load_entries_pairs_mut(
629 &mut self,
630 short_keys: Vec<Vec<u8>>,
631 ) -> Result<Vec<(Vec<u8>, WriteGuardedView<W>)>, ViewError> {
632 let values = self.try_load_entries_mut(short_keys.clone()).await?;
633 Ok(short_keys.into_iter().zip(values).collect())
634 }
635
636 /// Loads multiple entries for reading at once.
637 /// The entries in `short_keys` have to be all distinct.
638 /// ```rust
639 /// # tokio_test::block_on(async {
640 /// # use linera_views::context::MemoryContext;
641 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
642 /// # use linera_views::register_view::RegisterView;
643 /// # use linera_views::views::View;
644 /// # let context = MemoryContext::new_for_testing(());
645 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
646 /// ReentrantByteCollectionView::load(context).await.unwrap();
647 /// {
648 /// let _subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
649 /// }
650 /// let short_keys = vec![vec![0, 1], vec![2, 3]];
651 /// let subviews = view.try_load_entries(short_keys).await.unwrap();
652 /// assert!(subviews[1].is_none());
653 /// let value0 = subviews[0].as_ref().unwrap().get();
654 /// assert_eq!(*value0, String::default());
655 /// # })
656 /// ```
657 pub async fn try_load_entries(
658 &self,
659 short_keys: Vec<Vec<u8>>,
660 ) -> Result<Vec<Option<ReadGuardedView<W>>>, ViewError> {
661 let mut results = vec![None; short_keys.len()];
662 let mut keys_to_check = Vec::new();
663 let mut keys_to_check_metadata = Vec::new();
664
665 for (position, short_key) in short_keys.into_iter().enumerate() {
666 if let Some(update) = self.updates.get(&short_key) {
667 if let Update::Set(view) = update {
668 results[position] = Some((short_key, view.clone()));
669 }
670 } else if !self.delete_storage_first {
671 let key_index = self
672 .context
673 .base_key()
674 .base_tag_index(KeyTag::Index as u8, &short_key);
675 keys_to_check.push(key_index);
676 keys_to_check_metadata.push((position, short_key));
677 }
678 }
679
680 let found_keys = self.context.store().contains_keys(&keys_to_check).await?;
681 let entries_to_load = keys_to_check_metadata
682 .into_iter()
683 .zip(found_keys)
684 .filter_map(|(metadata, found)| found.then_some(metadata))
685 .map(|(position, short_key)| {
686 let subview_key = self
687 .context
688 .base_key()
689 .base_tag_index(KeyTag::Subview as u8, &short_key);
690 let subview_context = self.context.clone_with_base_key(subview_key);
691 (position, short_key.to_owned(), subview_context)
692 })
693 .collect::<Vec<_>>();
694 if !entries_to_load.is_empty() {
695 let mut keys_to_load = Vec::with_capacity(entries_to_load.len() * W::NUM_INIT_KEYS);
696 for (_, _, context) in &entries_to_load {
697 keys_to_load.extend(W::pre_load(context)?);
698 }
699 let values = self
700 .context
701 .store()
702 .read_multi_values_bytes(&keys_to_load)
703 .await?;
704 for (loaded_values, (position, short_key, context)) in values
705 .chunks_exact_or_repeat(W::NUM_INIT_KEYS)
706 .zip(entries_to_load)
707 {
708 let view = W::post_load(context, loaded_values)?;
709 let wrapped_view = Arc::new(RwLock::new(view));
710 results[position] = Some((short_key, wrapped_view));
711 }
712 }
713
714 results
715 .into_iter()
716 .map(|maybe_view| match maybe_view {
717 Some((short_key, view)) => Ok(Some(ReadGuardedView(
718 view.try_read_arc()
719 .ok_or_else(|| ViewError::TryLockError(short_key))?,
720 ))),
721 None => Ok(None),
722 })
723 .collect()
724 }
725
726 /// Loads multiple entries for reading at once with their keys.
727 /// The entries in short_keys have to be all distinct.
728 /// ```rust
729 /// # tokio_test::block_on(async {
730 /// # use linera_views::context::MemoryContext;
731 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
732 /// # use linera_views::register_view::RegisterView;
733 /// # use linera_views::views::View;
734 /// # let context = MemoryContext::new_for_testing(());
735 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
736 /// ReentrantByteCollectionView::load(context).await.unwrap();
737 /// {
738 /// let _subview = view.try_load_entry_mut(&vec![0, 1]).await.unwrap();
739 /// }
740 /// let short_keys = vec![vec![0, 1], vec![0, 2]];
741 /// let subviews = view.try_load_entries_pairs(short_keys).await.unwrap();
742 /// assert!(subviews[1].1.is_none());
743 /// let value0 = subviews[0].1.as_ref().unwrap().get();
744 /// assert_eq!(*value0, String::default());
745 /// # })
746 /// ```
747 pub async fn try_load_entries_pairs(
748 &self,
749 short_keys: Vec<Vec<u8>>,
750 ) -> Result<Vec<(Vec<u8>, Option<ReadGuardedView<W>>)>, ViewError> {
751 let values = self.try_load_entries(short_keys.clone()).await?;
752 Ok(short_keys.into_iter().zip(values).collect())
753 }
754
755 /// Loads all the entries for reading at once.
756 /// ```rust
757 /// # tokio_test::block_on(async {
758 /// # use linera_views::context::MemoryContext;
759 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
760 /// # use linera_views::register_view::RegisterView;
761 /// # use linera_views::views::View;
762 /// # let context = MemoryContext::new_for_testing(());
763 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
764 /// ReentrantByteCollectionView::load(context).await.unwrap();
765 /// {
766 /// let _subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
767 /// }
768 /// let subviews = view.try_load_all_entries().await.unwrap();
769 /// assert_eq!(subviews.len(), 1);
770 /// # })
771 /// ```
772 pub async fn try_load_all_entries(
773 &self,
774 ) -> Result<Vec<(Vec<u8>, ReadGuardedView<W>)>, ViewError> {
775 let short_keys = self.keys().await?;
776 let mut loaded_views = vec![None; short_keys.len()];
777
778 // Load views that are not in updates and not deleted
779 if !self.delete_storage_first {
780 let mut keys = Vec::new();
781 let mut short_keys_and_indexes = Vec::new();
782 for (index, short_key) in short_keys.iter().enumerate() {
783 if !self.updates.contains_key(short_key) {
784 let key = self
785 .context
786 .base_key()
787 .base_tag_index(KeyTag::Subview as u8, short_key);
788 let context = self.context.clone_with_base_key(key);
789 keys.extend(W::pre_load(&context)?);
790 short_keys_and_indexes.push((short_key.to_vec(), index));
791 }
792 }
793 let values = self.context.store().read_multi_values_bytes(&keys).await?;
794 for (loaded_values, (short_key, index)) in values
795 .chunks_exact_or_repeat(W::NUM_INIT_KEYS)
796 .zip(short_keys_and_indexes)
797 {
798 let key = self
799 .context
800 .base_key()
801 .base_tag_index(KeyTag::Subview as u8, &short_key);
802 let context = self.context.clone_with_base_key(key);
803 let view = W::post_load(context, loaded_values)?;
804 let wrapped_view = Arc::new(RwLock::new(view));
805 loaded_views[index] = Some(wrapped_view);
806 }
807 }
808
809 // Create result from updates and loaded views
810 short_keys
811 .into_iter()
812 .zip(loaded_views)
813 .map(|(short_key, loaded_view)| {
814 let view = if let Some(Update::Set(view)) = self.updates.get(&short_key) {
815 view.clone()
816 } else if let Some(view) = loaded_view {
817 view
818 } else {
819 unreachable!("All entries should have been loaded into memory");
820 };
821 let guard = ReadGuardedView(
822 view.try_read_arc()
823 .ok_or_else(|| ViewError::TryLockError(short_key.clone()))?,
824 );
825 Ok((short_key, guard))
826 })
827 .collect()
828 }
829
830 /// Loads all the entries for writing at once.
831 /// ```rust
832 /// # tokio_test::block_on(async {
833 /// # use linera_views::context::MemoryContext;
834 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
835 /// # use linera_views::register_view::RegisterView;
836 /// # use linera_views::views::View;
837 /// # let context = MemoryContext::new_for_testing(());
838 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
839 /// ReentrantByteCollectionView::load(context).await.unwrap();
840 /// {
841 /// let _subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
842 /// }
843 /// let subviews = view.try_load_all_entries_mut().await.unwrap();
844 /// assert_eq!(subviews.len(), 1);
845 /// # })
846 /// ```
847 pub async fn try_load_all_entries_mut(
848 &mut self,
849 ) -> Result<Vec<(Vec<u8>, WriteGuardedView<W>)>, ViewError> {
850 let short_keys = self.keys().await?;
851 if !self.delete_storage_first {
852 let mut keys = Vec::new();
853 let mut short_keys_to_load = Vec::new();
854
855 for short_key in &short_keys {
856 if !self.updates.contains_key(short_key) {
857 let key = self
858 .context
859 .base_key()
860 .base_tag_index(KeyTag::Subview as u8, short_key);
861 let context = self.context.clone_with_base_key(key);
862 keys.extend(W::pre_load(&context)?);
863 short_keys_to_load.push(short_key.to_vec());
864 }
865 }
866
867 let values = self.context.store().read_multi_values_bytes(&keys).await?;
868 for (loaded_values, short_key) in values
869 .chunks_exact_or_repeat(W::NUM_INIT_KEYS)
870 .zip(short_keys_to_load)
871 {
872 let key = self
873 .context
874 .base_key()
875 .base_tag_index(KeyTag::Subview as u8, &short_key);
876 let context = self.context.clone_with_base_key(key);
877 let view = W::post_load(context, loaded_values)?;
878 let wrapped_view = Arc::new(RwLock::new(view));
879 self.updates
880 .insert(short_key.to_vec(), Update::Set(wrapped_view));
881 }
882 }
883 short_keys
884 .into_iter()
885 .map(|short_key| {
886 let Some(Update::Set(view)) = self.updates.get(&short_key) else {
887 unreachable!("All entries should have been loaded into `updates`")
888 };
889 let guard = WriteGuardedView(
890 view.clone()
891 .try_write_arc()
892 .ok_or_else(|| ViewError::TryLockError(short_key.clone()))?,
893 );
894 Ok((short_key, guard))
895 })
896 .collect()
897 }
898}
899
900impl<W: View> ReentrantByteCollectionView<W::Context, W> {
901 /// Returns the list of indices in the collection in lexicographic order.
902 /// ```rust
903 /// # tokio_test::block_on(async {
904 /// # use linera_views::context::MemoryContext;
905 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
906 /// # use linera_views::register_view::RegisterView;
907 /// # use linera_views::views::View;
908 /// # let context = MemoryContext::new_for_testing(());
909 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
910 /// ReentrantByteCollectionView::load(context).await.unwrap();
911 /// view.try_load_entry_mut(&[0, 1]).await.unwrap();
912 /// view.try_load_entry_mut(&[0, 2]).await.unwrap();
913 /// let keys = view.keys().await.unwrap();
914 /// assert_eq!(keys, vec![vec![0, 1], vec![0, 2]]);
915 /// # })
916 /// ```
917 pub async fn keys(&self) -> Result<Vec<Vec<u8>>, ViewError> {
918 let mut keys = Vec::new();
919 self.for_each_key(|key| {
920 keys.push(key.to_vec());
921 Ok(())
922 })
923 .await?;
924 Ok(keys)
925 }
926
927 /// Returns the number of indices of the collection.
928 /// ```rust
929 /// # tokio_test::block_on(async {
930 /// # use linera_views::context::MemoryContext;
931 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
932 /// # use linera_views::register_view::RegisterView;
933 /// # use linera_views::views::View;
934 /// # let context = MemoryContext::new_for_testing(());
935 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
936 /// ReentrantByteCollectionView::load(context).await.unwrap();
937 /// view.try_load_entry_mut(&[0, 1]).await.unwrap();
938 /// view.try_load_entry_mut(&[0, 2]).await.unwrap();
939 /// assert_eq!(view.count().await.unwrap(), 2);
940 /// # })
941 /// ```
942 pub async fn count(&self) -> Result<usize, ViewError> {
943 let mut count = 0;
944 self.for_each_key(|_key| {
945 count += 1;
946 Ok(())
947 })
948 .await?;
949 Ok(count)
950 }
951
952 /// Applies a function f on each index (aka key). Keys are visited in a
953 /// lexicographic order. If the function returns false then the loop
954 /// ends prematurely.
955 /// ```rust
956 /// # tokio_test::block_on(async {
957 /// # use linera_views::context::MemoryContext;
958 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
959 /// # use linera_views::register_view::RegisterView;
960 /// # use linera_views::views::View;
961 /// # let context = MemoryContext::new_for_testing(());
962 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
963 /// ReentrantByteCollectionView::load(context).await.unwrap();
964 /// view.try_load_entry_mut(&[0, 1]).await.unwrap();
965 /// view.try_load_entry_mut(&[0, 2]).await.unwrap();
966 /// let mut count = 0;
967 /// view.for_each_key_while(|_key| {
968 /// count += 1;
969 /// Ok(count < 1)
970 /// })
971 /// .await
972 /// .unwrap();
973 /// assert_eq!(count, 1);
974 /// # })
975 /// ```
976 pub async fn for_each_key_while<F>(&self, mut f: F) -> Result<(), ViewError>
977 where
978 F: FnMut(&[u8]) -> Result<bool, ViewError> + Send,
979 {
980 let mut updates = self.updates.iter();
981 let mut update = updates.next();
982 if !self.delete_storage_first {
983 let base = self.get_index_key(&[]);
984 for index in self.context.store().find_keys_by_prefix(&base).await? {
985 loop {
986 match update {
987 Some((key, value)) if key <= &index => {
988 if let Update::Set(_) = value {
989 if !f(key)? {
990 return Ok(());
991 }
992 }
993 update = updates.next();
994 if key == &index {
995 break;
996 }
997 }
998 _ => {
999 if !f(&index)? {
1000 return Ok(());
1001 }
1002 break;
1003 }
1004 }
1005 }
1006 }
1007 }
1008 while let Some((key, value)) = update {
1009 if let Update::Set(_) = value {
1010 if !f(key)? {
1011 return Ok(());
1012 }
1013 }
1014 update = updates.next();
1015 }
1016 Ok(())
1017 }
1018
1019 /// Applies a function f on each index (aka key). Keys are visited in a
1020 /// lexicographic order.
1021 /// ```rust
1022 /// # tokio_test::block_on(async {
1023 /// # use linera_views::context::MemoryContext;
1024 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
1025 /// # use linera_views::register_view::RegisterView;
1026 /// # use linera_views::views::View;
1027 /// # let context = MemoryContext::new_for_testing(());
1028 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
1029 /// ReentrantByteCollectionView::load(context).await.unwrap();
1030 /// view.try_load_entry_mut(&[0, 1]).await.unwrap();
1031 /// view.try_load_entry_mut(&[0, 2]).await.unwrap();
1032 /// let mut count = 0;
1033 /// view.for_each_key(|_key| {
1034 /// count += 1;
1035 /// Ok(())
1036 /// })
1037 /// .await
1038 /// .unwrap();
1039 /// assert_eq!(count, 2);
1040 /// # })
1041 /// ```
1042 pub async fn for_each_key<F>(&self, mut f: F) -> Result<(), ViewError>
1043 where
1044 F: FnMut(&[u8]) -> Result<(), ViewError> + Send,
1045 {
1046 self.for_each_key_while(|key| {
1047 f(key)?;
1048 Ok(true)
1049 })
1050 .await
1051 }
1052}
1053
1054impl<W: HashableView> HashableView for ReentrantByteCollectionView<W::Context, W> {
1055 type Hasher = sha3::Sha3_256;
1056
1057 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1058 #[cfg(with_metrics)]
1059 let _hash_latency = metrics::REENTRANT_COLLECTION_VIEW_HASH_RUNTIME.measure_latency();
1060 let mut hasher = sha3::Sha3_256::default();
1061 let keys = self.keys().await?;
1062 let count = keys.len() as u32;
1063 hasher.update_with_bcs_bytes(&count)?;
1064 for key in keys {
1065 hasher.update_with_bytes(&key)?;
1066 let hash = if let Some(entry) = self.updates.get_mut(&key) {
1067 let Update::Set(view) = entry else {
1068 unreachable!();
1069 };
1070 let mut view = view
1071 .try_write_arc()
1072 .ok_or_else(|| ViewError::TryLockError(key))?;
1073 view.hash_mut().await?
1074 } else {
1075 let key = self
1076 .context
1077 .base_key()
1078 .base_tag_index(KeyTag::Subview as u8, &key);
1079 let context = self.context.clone_with_base_key(key);
1080 let mut view = W::load(context).await?;
1081 view.hash_mut().await?
1082 };
1083 hasher.write_all(hash.as_ref())?;
1084 }
1085 Ok(hasher.finalize())
1086 }
1087
1088 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1089 #[cfg(with_metrics)]
1090 let _hash_latency = metrics::REENTRANT_COLLECTION_VIEW_HASH_RUNTIME.measure_latency();
1091 let mut hasher = sha3::Sha3_256::default();
1092 let keys = self.keys().await?;
1093 let count = keys.len() as u32;
1094 hasher.update_with_bcs_bytes(&count)?;
1095 for key in keys {
1096 hasher.update_with_bytes(&key)?;
1097 let hash = if let Some(entry) = self.updates.get(&key) {
1098 let Update::Set(view) = entry else {
1099 unreachable!();
1100 };
1101 let view = view
1102 .try_read_arc()
1103 .ok_or_else(|| ViewError::TryLockError(key))?;
1104 view.hash().await?
1105 } else {
1106 let key = self
1107 .context
1108 .base_key()
1109 .base_tag_index(KeyTag::Subview as u8, &key);
1110 let context = self.context.clone_with_base_key(key);
1111 let view = W::load(context).await?;
1112 view.hash().await?
1113 };
1114 hasher.write_all(hash.as_ref())?;
1115 }
1116 Ok(hasher.finalize())
1117 }
1118}
1119
1120/// A view that supports accessing a collection of views of the same kind, indexed by keys,
1121/// possibly several subviews at a time.
1122#[derive(Debug, Allocative)]
1123#[allocative(bound = "C, I, W: Allocative")]
1124pub struct ReentrantCollectionView<C, I, W> {
1125 collection: ReentrantByteCollectionView<C, W>,
1126 #[allocative(skip)]
1127 _phantom: PhantomData<I>,
1128}
1129
1130impl<I, W, C2> ReplaceContext<C2> for ReentrantCollectionView<W::Context, I, W>
1131where
1132 W: View + ReplaceContext<C2>,
1133 I: Send + Sync + Serialize + DeserializeOwned,
1134 C2: Context,
1135{
1136 type Target = ReentrantCollectionView<C2, I, <W as ReplaceContext<C2>>::Target>;
1137
1138 async fn with_context(
1139 &mut self,
1140 ctx: impl FnOnce(&Self::Context) -> C2 + Clone,
1141 ) -> Self::Target {
1142 ReentrantCollectionView {
1143 collection: self.collection.with_context(ctx).await,
1144 _phantom: self._phantom,
1145 }
1146 }
1147}
1148
1149impl<I, W> View for ReentrantCollectionView<W::Context, I, W>
1150where
1151 W: View,
1152 I: Send + Sync + Serialize + DeserializeOwned,
1153{
1154 const NUM_INIT_KEYS: usize = ReentrantByteCollectionView::<W::Context, W>::NUM_INIT_KEYS;
1155
1156 type Context = W::Context;
1157
1158 fn context(&self) -> Self::Context {
1159 self.collection.context()
1160 }
1161
1162 fn pre_load(context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
1163 ReentrantByteCollectionView::<W::Context, W>::pre_load(context)
1164 }
1165
1166 fn post_load(context: Self::Context, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
1167 let collection = ReentrantByteCollectionView::post_load(context, values)?;
1168 Ok(ReentrantCollectionView {
1169 collection,
1170 _phantom: PhantomData,
1171 })
1172 }
1173
1174 fn rollback(&mut self) {
1175 self.collection.rollback()
1176 }
1177
1178 async fn has_pending_changes(&self) -> bool {
1179 self.collection.has_pending_changes().await
1180 }
1181
1182 fn pre_save(&self, batch: &mut Batch) -> Result<bool, ViewError> {
1183 self.collection.pre_save(batch)
1184 }
1185
1186 fn post_save(&mut self) {
1187 self.collection.post_save()
1188 }
1189
1190 fn clear(&mut self) {
1191 self.collection.clear()
1192 }
1193}
1194
1195impl<I, W> ClonableView for ReentrantCollectionView<W::Context, I, W>
1196where
1197 W: ClonableView,
1198 I: Send + Sync + Serialize + DeserializeOwned,
1199{
1200 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
1201 Ok(ReentrantCollectionView {
1202 collection: self.collection.clone_unchecked()?,
1203 _phantom: PhantomData,
1204 })
1205 }
1206}
1207
1208impl<I, W> ReentrantCollectionView<W::Context, I, W>
1209where
1210 W: View,
1211 I: Sync + Send + Serialize + DeserializeOwned,
1212{
1213 /// Loads a subview for the data at the given index in the collection. If an entry
1214 /// is absent then a default entry is put on the collection. The obtained view can
1215 /// then be modified.
1216 /// ```rust
1217 /// # tokio_test::block_on(async {
1218 /// # use linera_views::context::MemoryContext;
1219 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1220 /// # use linera_views::register_view::RegisterView;
1221 /// # use linera_views::views::View;
1222 /// # let context = MemoryContext::new_for_testing(());
1223 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1224 /// ReentrantCollectionView::load(context).await.unwrap();
1225 /// let subview = view.try_load_entry_mut(&23).await.unwrap();
1226 /// let value = subview.get();
1227 /// assert_eq!(*value, String::default());
1228 /// # })
1229 /// ```
1230 pub async fn try_load_entry_mut<Q>(
1231 &mut self,
1232 index: &Q,
1233 ) -> Result<WriteGuardedView<W>, ViewError>
1234 where
1235 I: Borrow<Q>,
1236 Q: Serialize + ?Sized,
1237 {
1238 let short_key = BaseKey::derive_short_key(index)?;
1239 self.collection.try_load_entry_mut(&short_key).await
1240 }
1241
1242 /// Loads a subview at the given index in the collection and gives read-only access to the data.
1243 /// If an entry is absent then `None` is returned.
1244 /// ```rust
1245 /// # tokio_test::block_on(async {
1246 /// # use linera_views::context::MemoryContext;
1247 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1248 /// # use linera_views::register_view::RegisterView;
1249 /// # use linera_views::views::View;
1250 /// # let context = MemoryContext::new_for_testing(());
1251 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1252 /// ReentrantCollectionView::load(context).await.unwrap();
1253 /// {
1254 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1255 /// }
1256 /// let subview = view.try_load_entry(&23).await.unwrap().unwrap();
1257 /// let value = subview.get();
1258 /// assert_eq!(*value, String::default());
1259 /// # })
1260 /// ```
1261 pub async fn try_load_entry<Q>(
1262 &self,
1263 index: &Q,
1264 ) -> Result<Option<ReadGuardedView<W>>, ViewError>
1265 where
1266 I: Borrow<Q>,
1267 Q: Serialize + ?Sized,
1268 {
1269 let short_key = BaseKey::derive_short_key(index)?;
1270 self.collection.try_load_entry(&short_key).await
1271 }
1272
1273 /// Returns `true` if the collection contains a value for the specified key.
1274 /// ```rust
1275 /// # tokio_test::block_on(async {
1276 /// # use linera_views::context::MemoryContext;
1277 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1278 /// # use linera_views::register_view::RegisterView;
1279 /// # use linera_views::views::View;
1280 /// # let context = MemoryContext::new_for_testing(());
1281 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1282 /// ReentrantCollectionView::load(context).await.unwrap();
1283 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1284 /// assert!(view.contains_key(&23).await.unwrap());
1285 /// assert!(!view.contains_key(&24).await.unwrap());
1286 /// # })
1287 /// ```
1288 pub async fn contains_key<Q>(&self, index: &Q) -> Result<bool, ViewError>
1289 where
1290 I: Borrow<Q>,
1291 Q: Serialize + ?Sized,
1292 {
1293 let short_key = BaseKey::derive_short_key(index)?;
1294 self.collection.contains_key(&short_key).await
1295 }
1296
1297 /// Marks the entry so that it is removed in the next flush.
1298 /// ```rust
1299 /// # tokio_test::block_on(async {
1300 /// # use linera_views::context::MemoryContext;
1301 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1302 /// # use linera_views::register_view::RegisterView;
1303 /// # use linera_views::views::View;
1304 /// # let context = MemoryContext::new_for_testing(());
1305 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1306 /// ReentrantCollectionView::load(context).await.unwrap();
1307 /// let mut subview = view.try_load_entry_mut(&23).await.unwrap();
1308 /// let value = subview.get_mut();
1309 /// assert_eq!(*value, String::default());
1310 /// view.remove_entry(&23);
1311 /// let keys = view.indices().await.unwrap();
1312 /// assert_eq!(keys.len(), 0);
1313 /// # })
1314 /// ```
1315 pub fn remove_entry<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1316 where
1317 I: Borrow<Q>,
1318 Q: Serialize + ?Sized,
1319 {
1320 let short_key = BaseKey::derive_short_key(index)?;
1321 self.collection.remove_entry(short_key);
1322 Ok(())
1323 }
1324
1325 /// Marks the entry so that it is removed in the next flush.
1326 /// ```rust
1327 /// # tokio_test::block_on(async {
1328 /// # use linera_views::context::MemoryContext;
1329 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1330 /// # use linera_views::register_view::RegisterView;
1331 /// # use linera_views::views::View;
1332 /// # let context = MemoryContext::new_for_testing(());
1333 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1334 /// ReentrantCollectionView::load(context).await.unwrap();
1335 /// {
1336 /// let mut subview = view.try_load_entry_mut(&23).await.unwrap();
1337 /// let value = subview.get_mut();
1338 /// *value = String::from("Hello");
1339 /// }
1340 /// view.try_reset_entry_to_default(&23).unwrap();
1341 /// let mut subview = view.try_load_entry_mut(&23).await.unwrap();
1342 /// let value = subview.get_mut();
1343 /// assert_eq!(*value, String::default());
1344 /// # })
1345 /// ```
1346 pub fn try_reset_entry_to_default<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1347 where
1348 I: Borrow<Q>,
1349 Q: Serialize + ?Sized,
1350 {
1351 let short_key = BaseKey::derive_short_key(index)?;
1352 self.collection.try_reset_entry_to_default(&short_key)
1353 }
1354
1355 /// Gets the extra data.
1356 pub fn extra(&self) -> &<W::Context as Context>::Extra {
1357 self.collection.extra()
1358 }
1359}
1360
1361impl<I, W> ReentrantCollectionView<W::Context, I, W>
1362where
1363 W: View,
1364 I: Sync + Send + Serialize + DeserializeOwned,
1365{
1366 /// Load multiple entries for writing at once.
1367 /// The entries in indices have to be all distinct.
1368 /// ```rust
1369 /// # tokio_test::block_on(async {
1370 /// # use linera_views::context::MemoryContext;
1371 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1372 /// # use linera_views::register_view::RegisterView;
1373 /// # use linera_views::views::View;
1374 /// # let context = MemoryContext::new_for_testing(());
1375 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1376 /// ReentrantCollectionView::load(context).await.unwrap();
1377 /// let indices = vec![23, 42];
1378 /// let subviews = view.try_load_entries_mut(&indices).await.unwrap();
1379 /// let value1 = subviews[0].get();
1380 /// let value2 = subviews[1].get();
1381 /// assert_eq!(*value1, String::default());
1382 /// assert_eq!(*value2, String::default());
1383 /// # })
1384 /// ```
1385 pub async fn try_load_entries_mut<'a, Q>(
1386 &'a mut self,
1387 indices: impl IntoIterator<Item = &'a Q>,
1388 ) -> Result<Vec<WriteGuardedView<W>>, ViewError>
1389 where
1390 I: Borrow<Q>,
1391 Q: Serialize + 'a,
1392 {
1393 let short_keys = indices
1394 .into_iter()
1395 .map(|index| BaseKey::derive_short_key(index))
1396 .collect::<Result<_, _>>()?;
1397 self.collection.try_load_entries_mut(short_keys).await
1398 }
1399
1400 /// Loads multiple entries for writing at once with their keys.
1401 /// The entries in indices have to be all distinct.
1402 /// ```rust
1403 /// # tokio_test::block_on(async {
1404 /// # use linera_views::context::MemoryContext;
1405 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1406 /// # use linera_views::register_view::RegisterView;
1407 /// # use linera_views::views::View;
1408 /// # let context = MemoryContext::new_for_testing(());
1409 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1410 /// ReentrantCollectionView::load(context).await.unwrap();
1411 /// let indices = [23, 42];
1412 /// let subviews = view.try_load_entries_pairs_mut(indices).await.unwrap();
1413 /// let value1 = subviews[0].1.get();
1414 /// let value2 = subviews[1].1.get();
1415 /// assert_eq!(*value1, String::default());
1416 /// assert_eq!(*value2, String::default());
1417 /// # })
1418 /// ```
1419 pub async fn try_load_entries_pairs_mut<Q>(
1420 &mut self,
1421 indices: impl IntoIterator<Item = Q>,
1422 ) -> Result<Vec<(Q, WriteGuardedView<W>)>, ViewError>
1423 where
1424 I: Borrow<Q>,
1425 Q: Serialize + Clone,
1426 {
1427 let indices_vec: Vec<Q> = indices.into_iter().collect();
1428 let values = self.try_load_entries_mut(indices_vec.iter()).await?;
1429 Ok(indices_vec.into_iter().zip(values).collect())
1430 }
1431
1432 /// Load multiple entries for reading at once.
1433 /// The entries in indices have to be all distinct.
1434 /// ```rust
1435 /// # tokio_test::block_on(async {
1436 /// # use linera_views::context::MemoryContext;
1437 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1438 /// # use linera_views::register_view::RegisterView;
1439 /// # use linera_views::views::View;
1440 /// # let context = MemoryContext::new_for_testing(());
1441 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1442 /// ReentrantCollectionView::load(context).await.unwrap();
1443 /// {
1444 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1445 /// }
1446 /// let indices = vec![23, 42];
1447 /// let subviews = view.try_load_entries(&indices).await.unwrap();
1448 /// assert!(subviews[1].is_none());
1449 /// let value0 = subviews[0].as_ref().unwrap().get();
1450 /// assert_eq!(*value0, String::default());
1451 /// # })
1452 /// ```
1453 pub async fn try_load_entries<'a, Q>(
1454 &'a self,
1455 indices: impl IntoIterator<Item = &'a Q>,
1456 ) -> Result<Vec<Option<ReadGuardedView<W>>>, ViewError>
1457 where
1458 I: Borrow<Q>,
1459 Q: Serialize + 'a,
1460 {
1461 let short_keys = indices
1462 .into_iter()
1463 .map(|index| BaseKey::derive_short_key(index))
1464 .collect::<Result<_, _>>()?;
1465 self.collection.try_load_entries(short_keys).await
1466 }
1467
1468 /// Loads multiple entries for reading at once with their keys.
1469 /// The entries in indices have to be all distinct.
1470 /// ```rust
1471 /// # tokio_test::block_on(async {
1472 /// # use linera_views::context::MemoryContext;
1473 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1474 /// # use linera_views::register_view::RegisterView;
1475 /// # use linera_views::views::View;
1476 /// # let context = MemoryContext::new_for_testing(());
1477 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1478 /// ReentrantCollectionView::load(context).await.unwrap();
1479 /// {
1480 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1481 /// }
1482 /// let indices = [23, 42];
1483 /// let subviews = view.try_load_entries_pairs(indices).await.unwrap();
1484 /// assert!(subviews[1].1.is_none());
1485 /// let value0 = subviews[0].1.as_ref().unwrap().get();
1486 /// assert_eq!(*value0, String::default());
1487 /// # })
1488 /// ```
1489 pub async fn try_load_entries_pairs<Q>(
1490 &self,
1491 indices: impl IntoIterator<Item = Q>,
1492 ) -> Result<Vec<(Q, Option<ReadGuardedView<W>>)>, ViewError>
1493 where
1494 I: Borrow<Q>,
1495 Q: Serialize + Clone,
1496 {
1497 let indices_vec: Vec<Q> = indices.into_iter().collect();
1498 let values = self.try_load_entries(indices_vec.iter()).await?;
1499 Ok(indices_vec.into_iter().zip(values).collect())
1500 }
1501
1502 /// Loads all entries for writing at once.
1503 /// The entries in indices have to be all distinct.
1504 /// ```rust
1505 /// # tokio_test::block_on(async {
1506 /// # use linera_views::context::MemoryContext;
1507 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1508 /// # use linera_views::register_view::RegisterView;
1509 /// # use linera_views::views::View;
1510 /// # let context = MemoryContext::new_for_testing(());
1511 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1512 /// ReentrantCollectionView::load(context).await.unwrap();
1513 /// {
1514 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1515 /// }
1516 /// let subviews = view.try_load_all_entries_mut().await.unwrap();
1517 /// assert_eq!(subviews.len(), 1);
1518 /// # })
1519 /// ```
1520 pub async fn try_load_all_entries_mut(
1521 &mut self,
1522 ) -> Result<Vec<(I, WriteGuardedView<W>)>, ViewError> {
1523 let results = self.collection.try_load_all_entries_mut().await?;
1524 results
1525 .into_iter()
1526 .map(|(short_key, view)| {
1527 let index = BaseKey::deserialize_value(&short_key)?;
1528 Ok((index, view))
1529 })
1530 .collect()
1531 }
1532
1533 /// Load multiple entries for reading at once.
1534 /// The entries in indices have to be all distinct.
1535 /// ```rust
1536 /// # tokio_test::block_on(async {
1537 /// # use linera_views::context::MemoryContext;
1538 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1539 /// # use linera_views::register_view::RegisterView;
1540 /// # use linera_views::views::View;
1541 /// # let context = MemoryContext::new_for_testing(());
1542 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1543 /// ReentrantCollectionView::load(context).await.unwrap();
1544 /// {
1545 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1546 /// }
1547 /// let subviews = view.try_load_all_entries().await.unwrap();
1548 /// assert_eq!(subviews.len(), 1);
1549 /// # })
1550 /// ```
1551 pub async fn try_load_all_entries(&self) -> Result<Vec<(I, ReadGuardedView<W>)>, ViewError> {
1552 let results = self.collection.try_load_all_entries().await?;
1553 results
1554 .into_iter()
1555 .map(|(short_key, view)| {
1556 let index = BaseKey::deserialize_value(&short_key)?;
1557 Ok((index, view))
1558 })
1559 .collect()
1560 }
1561}
1562
1563impl<I, W> ReentrantCollectionView<W::Context, I, W>
1564where
1565 W: View,
1566 I: Sync + Send + Serialize + DeserializeOwned,
1567{
1568 /// Returns the list of indices in the collection in an order determined
1569 /// by serialization.
1570 /// ```rust
1571 /// # tokio_test::block_on(async {
1572 /// # use linera_views::context::MemoryContext;
1573 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1574 /// # use linera_views::register_view::RegisterView;
1575 /// # use linera_views::views::View;
1576 /// # let context = MemoryContext::new_for_testing(());
1577 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1578 /// ReentrantCollectionView::load(context).await.unwrap();
1579 /// view.try_load_entry_mut(&23).await.unwrap();
1580 /// view.try_load_entry_mut(&25).await.unwrap();
1581 /// let indices = view.indices().await.unwrap();
1582 /// assert_eq!(indices.len(), 2);
1583 /// # })
1584 /// ```
1585 pub async fn indices(&self) -> Result<Vec<I>, ViewError> {
1586 let mut indices = Vec::new();
1587 self.for_each_index(|index| {
1588 indices.push(index);
1589 Ok(())
1590 })
1591 .await?;
1592 Ok(indices)
1593 }
1594
1595 /// Returns the number of indices in the collection.
1596 /// ```rust
1597 /// # tokio_test::block_on(async {
1598 /// # use linera_views::context::MemoryContext;
1599 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1600 /// # use linera_views::register_view::RegisterView;
1601 /// # use linera_views::views::View;
1602 /// # let context = MemoryContext::new_for_testing(());
1603 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1604 /// ReentrantCollectionView::load(context).await.unwrap();
1605 /// view.try_load_entry_mut(&23).await.unwrap();
1606 /// view.try_load_entry_mut(&25).await.unwrap();
1607 /// assert_eq!(view.count().await.unwrap(), 2);
1608 /// # })
1609 /// ```
1610 pub async fn count(&self) -> Result<usize, ViewError> {
1611 self.collection.count().await
1612 }
1613
1614 /// Applies a function f on each index. Indices are visited in an order
1615 /// determined by the serialization. If the function f returns false then
1616 /// the loop ends prematurely.
1617 /// ```rust
1618 /// # tokio_test::block_on(async {
1619 /// # use linera_views::context::MemoryContext;
1620 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1621 /// # use linera_views::register_view::RegisterView;
1622 /// # use linera_views::views::View;
1623 /// # let context = MemoryContext::new_for_testing(());
1624 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1625 /// ReentrantCollectionView::load(context).await.unwrap();
1626 /// view.try_load_entry_mut(&23).await.unwrap();
1627 /// view.try_load_entry_mut(&24).await.unwrap();
1628 /// let mut count = 0;
1629 /// view.for_each_index_while(|_key| {
1630 /// count += 1;
1631 /// Ok(count < 1)
1632 /// })
1633 /// .await
1634 /// .unwrap();
1635 /// assert_eq!(count, 1);
1636 /// # })
1637 /// ```
1638 pub async fn for_each_index_while<F>(&self, mut f: F) -> Result<(), ViewError>
1639 where
1640 F: FnMut(I) -> Result<bool, ViewError> + Send,
1641 {
1642 self.collection
1643 .for_each_key_while(|key| {
1644 let index = BaseKey::deserialize_value(key)?;
1645 f(index)
1646 })
1647 .await?;
1648 Ok(())
1649 }
1650
1651 /// Applies a function f on each index. Indices are visited in an order
1652 /// determined by the serialization.
1653 /// ```rust
1654 /// # tokio_test::block_on(async {
1655 /// # use linera_views::context::MemoryContext;
1656 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1657 /// # use linera_views::register_view::RegisterView;
1658 /// # use linera_views::views::View;
1659 /// # let context = MemoryContext::new_for_testing(());
1660 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1661 /// ReentrantCollectionView::load(context).await.unwrap();
1662 /// view.try_load_entry_mut(&23).await.unwrap();
1663 /// view.try_load_entry_mut(&28).await.unwrap();
1664 /// let mut count = 0;
1665 /// view.for_each_index(|_key| {
1666 /// count += 1;
1667 /// Ok(())
1668 /// })
1669 /// .await
1670 /// .unwrap();
1671 /// assert_eq!(count, 2);
1672 /// # })
1673 /// ```
1674 pub async fn for_each_index<F>(&self, mut f: F) -> Result<(), ViewError>
1675 where
1676 F: FnMut(I) -> Result<(), ViewError> + Send,
1677 {
1678 self.collection
1679 .for_each_key(|key| {
1680 let index = BaseKey::deserialize_value(key)?;
1681 f(index)
1682 })
1683 .await?;
1684 Ok(())
1685 }
1686}
1687
1688impl<I, W> HashableView for ReentrantCollectionView<W::Context, I, W>
1689where
1690 W: HashableView,
1691 I: Send + Sync + Serialize + DeserializeOwned,
1692{
1693 type Hasher = sha3::Sha3_256;
1694
1695 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1696 self.collection.hash_mut().await
1697 }
1698
1699 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1700 self.collection.hash().await
1701 }
1702}
1703
1704/// A view that supports accessing a collection of views of the same kind, indexed by an ordered key,
1705/// possibly several subviews at a time.
1706#[derive(Debug, Allocative)]
1707#[allocative(bound = "C, I, W: Allocative")]
1708pub struct ReentrantCustomCollectionView<C, I, W> {
1709 collection: ReentrantByteCollectionView<C, W>,
1710 #[allocative(skip)]
1711 _phantom: PhantomData<I>,
1712}
1713
1714impl<I, W> View for ReentrantCustomCollectionView<W::Context, I, W>
1715where
1716 W: View,
1717 I: Send + Sync + CustomSerialize,
1718{
1719 const NUM_INIT_KEYS: usize = ReentrantByteCollectionView::<W::Context, W>::NUM_INIT_KEYS;
1720
1721 type Context = W::Context;
1722
1723 fn context(&self) -> Self::Context {
1724 self.collection.context()
1725 }
1726
1727 fn pre_load(context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
1728 ReentrantByteCollectionView::<_, W>::pre_load(context)
1729 }
1730
1731 fn post_load(context: Self::Context, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
1732 let collection = ReentrantByteCollectionView::post_load(context, values)?;
1733 Ok(ReentrantCustomCollectionView {
1734 collection,
1735 _phantom: PhantomData,
1736 })
1737 }
1738
1739 fn rollback(&mut self) {
1740 self.collection.rollback()
1741 }
1742
1743 async fn has_pending_changes(&self) -> bool {
1744 self.collection.has_pending_changes().await
1745 }
1746
1747 fn pre_save(&self, batch: &mut Batch) -> Result<bool, ViewError> {
1748 self.collection.pre_save(batch)
1749 }
1750
1751 fn post_save(&mut self) {
1752 self.collection.post_save()
1753 }
1754
1755 fn clear(&mut self) {
1756 self.collection.clear()
1757 }
1758}
1759
1760impl<I, W> ClonableView for ReentrantCustomCollectionView<W::Context, I, W>
1761where
1762 W: ClonableView,
1763 Self: View,
1764{
1765 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
1766 Ok(ReentrantCustomCollectionView {
1767 collection: self.collection.clone_unchecked()?,
1768 _phantom: PhantomData,
1769 })
1770 }
1771}
1772
1773impl<I, W> ReentrantCustomCollectionView<W::Context, I, W>
1774where
1775 W: View,
1776 I: Sync + Send + CustomSerialize,
1777{
1778 /// Loads a subview for the data at the given index in the collection. If an entry
1779 /// is absent then a default entry is put in the collection on this index.
1780 /// ```rust
1781 /// # tokio_test::block_on(async {
1782 /// # use linera_views::context::MemoryContext;
1783 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1784 /// # use linera_views::register_view::RegisterView;
1785 /// # use linera_views::views::View;
1786 /// # let context = MemoryContext::new_for_testing(());
1787 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1788 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1789 /// let subview = view.try_load_entry_mut(&23).await.unwrap();
1790 /// let value = subview.get();
1791 /// assert_eq!(*value, String::default());
1792 /// # })
1793 /// ```
1794 pub async fn try_load_entry_mut<Q>(
1795 &mut self,
1796 index: &Q,
1797 ) -> Result<WriteGuardedView<W>, ViewError>
1798 where
1799 I: Borrow<Q>,
1800 Q: CustomSerialize,
1801 {
1802 let short_key = index.to_custom_bytes()?;
1803 self.collection.try_load_entry_mut(&short_key).await
1804 }
1805
1806 /// Loads a subview at the given index in the collection and gives read-only access to the data.
1807 /// If an entry is absent then `None` is returned.
1808 /// ```rust
1809 /// # tokio_test::block_on(async {
1810 /// # use linera_views::context::MemoryContext;
1811 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1812 /// # use linera_views::register_view::RegisterView;
1813 /// # use linera_views::views::View;
1814 /// # let context = MemoryContext::new_for_testing(());
1815 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1816 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1817 /// {
1818 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1819 /// }
1820 /// let subview = view.try_load_entry(&23).await.unwrap().unwrap();
1821 /// let value = subview.get();
1822 /// assert_eq!(*value, String::default());
1823 /// # })
1824 /// ```
1825 pub async fn try_load_entry<Q>(
1826 &self,
1827 index: &Q,
1828 ) -> Result<Option<ReadGuardedView<W>>, ViewError>
1829 where
1830 I: Borrow<Q>,
1831 Q: CustomSerialize,
1832 {
1833 let short_key = index.to_custom_bytes()?;
1834 self.collection.try_load_entry(&short_key).await
1835 }
1836
1837 /// Returns `true` if the collection contains a value for the specified key.
1838 /// ```rust
1839 /// # tokio_test::block_on(async {
1840 /// # use linera_views::context::MemoryContext;
1841 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1842 /// # use linera_views::register_view::RegisterView;
1843 /// # use linera_views::views::View;
1844 /// # let context = MemoryContext::new_for_testing(());
1845 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1846 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1847 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1848 /// assert!(view.contains_key(&23).await.unwrap());
1849 /// assert!(!view.contains_key(&24).await.unwrap());
1850 /// # })
1851 /// ```
1852 pub async fn contains_key<Q>(&self, index: &Q) -> Result<bool, ViewError>
1853 where
1854 I: Borrow<Q>,
1855 Q: CustomSerialize,
1856 {
1857 let short_key = index.to_custom_bytes()?;
1858 self.collection.contains_key(&short_key).await
1859 }
1860
1861 /// Removes an entry. If absent then nothing happens.
1862 /// ```rust
1863 /// # tokio_test::block_on(async {
1864 /// # use linera_views::context::MemoryContext;
1865 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1866 /// # use linera_views::register_view::RegisterView;
1867 /// # use linera_views::views::View;
1868 /// # let context = MemoryContext::new_for_testing(());
1869 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1870 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1871 /// let mut subview = view.try_load_entry_mut(&23).await.unwrap();
1872 /// let value = subview.get_mut();
1873 /// assert_eq!(*value, String::default());
1874 /// view.remove_entry(&23);
1875 /// let keys = view.indices().await.unwrap();
1876 /// assert_eq!(keys.len(), 0);
1877 /// # })
1878 /// ```
1879 pub fn remove_entry<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1880 where
1881 I: Borrow<Q>,
1882 Q: CustomSerialize,
1883 {
1884 let short_key = index.to_custom_bytes()?;
1885 self.collection.remove_entry(short_key);
1886 Ok(())
1887 }
1888
1889 /// Marks the entry so that it is removed in the next flush.
1890 /// ```rust
1891 /// # tokio_test::block_on(async {
1892 /// # use linera_views::context::MemoryContext;
1893 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1894 /// # use linera_views::register_view::RegisterView;
1895 /// # use linera_views::views::View;
1896 /// # let context = MemoryContext::new_for_testing(());
1897 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1898 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1899 /// {
1900 /// let mut subview = view.try_load_entry_mut(&23).await.unwrap();
1901 /// let value = subview.get_mut();
1902 /// *value = String::from("Hello");
1903 /// }
1904 /// {
1905 /// view.try_reset_entry_to_default(&23).unwrap();
1906 /// let subview = view.try_load_entry(&23).await.unwrap().unwrap();
1907 /// let value = subview.get();
1908 /// assert_eq!(*value, String::default());
1909 /// }
1910 /// # })
1911 /// ```
1912 pub fn try_reset_entry_to_default<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1913 where
1914 I: Borrow<Q>,
1915 Q: CustomSerialize,
1916 {
1917 let short_key = index.to_custom_bytes()?;
1918 self.collection.try_reset_entry_to_default(&short_key)
1919 }
1920
1921 /// Gets the extra data.
1922 pub fn extra(&self) -> &<W::Context as Context>::Extra {
1923 self.collection.extra()
1924 }
1925}
1926
1927impl<I, W: View> ReentrantCustomCollectionView<W::Context, I, W>
1928where
1929 I: Sync + Send + CustomSerialize,
1930{
1931 /// Load multiple entries for writing at once.
1932 /// The entries in indices have to be all distinct.
1933 /// ```rust
1934 /// # tokio_test::block_on(async {
1935 /// # use linera_views::context::MemoryContext;
1936 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1937 /// # use linera_views::register_view::RegisterView;
1938 /// # use linera_views::views::View;
1939 /// # let context = MemoryContext::new_for_testing(());
1940 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1941 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1942 /// let subviews = view.try_load_entries_mut(&[23, 42]).await.unwrap();
1943 /// let value1 = subviews[0].get();
1944 /// let value2 = subviews[1].get();
1945 /// assert_eq!(*value1, String::default());
1946 /// assert_eq!(*value2, String::default());
1947 /// # })
1948 /// ```
1949 pub async fn try_load_entries_mut<'a, Q>(
1950 &mut self,
1951 indices: impl IntoIterator<Item = &'a Q>,
1952 ) -> Result<Vec<WriteGuardedView<W>>, ViewError>
1953 where
1954 I: Borrow<Q>,
1955 Q: CustomSerialize + 'a,
1956 {
1957 let short_keys = indices
1958 .into_iter()
1959 .map(|index| index.to_custom_bytes())
1960 .collect::<Result<_, _>>()?;
1961 self.collection.try_load_entries_mut(short_keys).await
1962 }
1963
1964 /// Loads multiple entries for writing at once with their keys.
1965 /// The entries in indices have to be all distinct.
1966 /// ```rust
1967 /// # tokio_test::block_on(async {
1968 /// # use linera_views::context::MemoryContext;
1969 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1970 /// # use linera_views::register_view::RegisterView;
1971 /// # use linera_views::views::View;
1972 /// # let context = MemoryContext::new_for_testing(());
1973 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1974 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1975 /// let indices = [23, 42];
1976 /// let subviews = view.try_load_entries_pairs_mut(indices).await.unwrap();
1977 /// let value1 = subviews[0].1.get();
1978 /// let value2 = subviews[1].1.get();
1979 /// assert_eq!(*value1, String::default());
1980 /// assert_eq!(*value2, String::default());
1981 /// # })
1982 /// ```
1983 pub async fn try_load_entries_pairs_mut<Q>(
1984 &mut self,
1985 indices: impl IntoIterator<Item = Q>,
1986 ) -> Result<Vec<(Q, WriteGuardedView<W>)>, ViewError>
1987 where
1988 I: Borrow<Q>,
1989 Q: CustomSerialize + Clone,
1990 {
1991 let indices_vec: Vec<Q> = indices.into_iter().collect();
1992 let values = self.try_load_entries_mut(indices_vec.iter()).await?;
1993 Ok(indices_vec.into_iter().zip(values).collect())
1994 }
1995
1996 /// Load multiple entries for reading at once.
1997 /// The entries in indices have to be all distinct.
1998 /// ```rust
1999 /// # tokio_test::block_on(async {
2000 /// # use linera_views::context::MemoryContext;
2001 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2002 /// # use linera_views::register_view::RegisterView;
2003 /// # use linera_views::views::View;
2004 /// # let context = MemoryContext::new_for_testing(());
2005 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2006 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2007 /// {
2008 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
2009 /// }
2010 /// let subviews = view.try_load_entries(&[23, 42]).await.unwrap();
2011 /// assert!(subviews[1].is_none());
2012 /// let value0 = subviews[0].as_ref().unwrap().get();
2013 /// assert_eq!(*value0, String::default());
2014 /// # })
2015 /// ```
2016 pub async fn try_load_entries<'a, Q>(
2017 &self,
2018 indices: impl IntoIterator<Item = &'a Q>,
2019 ) -> Result<Vec<Option<ReadGuardedView<W>>>, ViewError>
2020 where
2021 I: Borrow<Q>,
2022 Q: CustomSerialize + 'a,
2023 {
2024 let short_keys = indices
2025 .into_iter()
2026 .map(|index| index.to_custom_bytes())
2027 .collect::<Result<_, _>>()?;
2028 self.collection.try_load_entries(short_keys).await
2029 }
2030
2031 /// Loads multiple entries for reading at once with their keys.
2032 /// The entries in indices have to be all distinct.
2033 /// ```rust
2034 /// # tokio_test::block_on(async {
2035 /// # use linera_views::context::MemoryContext;
2036 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2037 /// # use linera_views::register_view::RegisterView;
2038 /// # use linera_views::views::View;
2039 /// # let context = MemoryContext::new_for_testing(());
2040 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2041 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2042 /// {
2043 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
2044 /// }
2045 /// let indices = [23, 42];
2046 /// let subviews = view.try_load_entries_pairs(indices).await.unwrap();
2047 /// assert!(subviews[1].1.is_none());
2048 /// let value0 = subviews[0].1.as_ref().unwrap().get();
2049 /// assert_eq!(*value0, String::default());
2050 /// # })
2051 /// ```
2052 pub async fn try_load_entries_pairs<Q>(
2053 &self,
2054 indices: impl IntoIterator<Item = Q>,
2055 ) -> Result<Vec<(Q, Option<ReadGuardedView<W>>)>, ViewError>
2056 where
2057 I: Borrow<Q>,
2058 Q: CustomSerialize + Clone,
2059 {
2060 let indices_vec: Vec<Q> = indices.into_iter().collect();
2061 let values = self.try_load_entries(indices_vec.iter()).await?;
2062 Ok(indices_vec.into_iter().zip(values).collect())
2063 }
2064
2065 /// Loads all entries for writing at once.
2066 /// The entries in indices have to be all distinct.
2067 /// ```rust
2068 /// # tokio_test::block_on(async {
2069 /// # use linera_views::context::MemoryContext;
2070 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2071 /// # use linera_views::register_view::RegisterView;
2072 /// # use linera_views::views::View;
2073 /// # let context = MemoryContext::new_for_testing(());
2074 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2075 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2076 /// {
2077 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
2078 /// }
2079 /// let subviews = view.try_load_all_entries_mut().await.unwrap();
2080 /// assert_eq!(subviews.len(), 1);
2081 /// # })
2082 /// ```
2083 pub async fn try_load_all_entries_mut(
2084 &mut self,
2085 ) -> Result<Vec<(I, WriteGuardedView<W>)>, ViewError> {
2086 let results = self.collection.try_load_all_entries_mut().await?;
2087 results
2088 .into_iter()
2089 .map(|(short_key, view)| {
2090 let index = I::from_custom_bytes(&short_key)?;
2091 Ok((index, view))
2092 })
2093 .collect()
2094 }
2095
2096 /// Load multiple entries for reading at once.
2097 /// The entries in indices have to be all distinct.
2098 /// ```rust
2099 /// # tokio_test::block_on(async {
2100 /// # use linera_views::context::MemoryContext;
2101 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2102 /// # use linera_views::register_view::RegisterView;
2103 /// # use linera_views::views::View;
2104 /// # let context = MemoryContext::new_for_testing(());
2105 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2106 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2107 /// {
2108 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
2109 /// }
2110 /// let subviews = view.try_load_all_entries().await.unwrap();
2111 /// assert_eq!(subviews.len(), 1);
2112 /// # })
2113 /// ```
2114 pub async fn try_load_all_entries(&self) -> Result<Vec<(I, ReadGuardedView<W>)>, ViewError> {
2115 let results = self.collection.try_load_all_entries().await?;
2116 results
2117 .into_iter()
2118 .map(|(short_key, view)| {
2119 let index = I::from_custom_bytes(&short_key)?;
2120 Ok((index, view))
2121 })
2122 .collect()
2123 }
2124}
2125
2126impl<I, W> ReentrantCustomCollectionView<W::Context, I, W>
2127where
2128 W: View,
2129 I: Sync + Send + CustomSerialize,
2130{
2131 /// Returns the list of indices in the collection. The order is determined by
2132 /// the custom serialization.
2133 /// ```rust
2134 /// # tokio_test::block_on(async {
2135 /// # use linera_views::context::MemoryContext;
2136 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2137 /// # use linera_views::register_view::RegisterView;
2138 /// # use linera_views::views::View;
2139 /// # let context = MemoryContext::new_for_testing(());
2140 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2141 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2142 /// view.try_load_entry_mut(&23).await.unwrap();
2143 /// view.try_load_entry_mut(&25).await.unwrap();
2144 /// let indices = view.indices().await.unwrap();
2145 /// assert_eq!(indices, vec![23, 25]);
2146 /// # })
2147 /// ```
2148 pub async fn indices(&self) -> Result<Vec<I>, ViewError> {
2149 let mut indices = Vec::new();
2150 self.for_each_index(|index| {
2151 indices.push(index);
2152 Ok(())
2153 })
2154 .await?;
2155 Ok(indices)
2156 }
2157
2158 /// Returns the number of entries in the collection.
2159 /// ```rust
2160 /// # tokio_test::block_on(async {
2161 /// # use linera_views::context::MemoryContext;
2162 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2163 /// # use linera_views::register_view::RegisterView;
2164 /// # use linera_views::views::View;
2165 /// # let context = MemoryContext::new_for_testing(());
2166 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2167 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2168 /// view.try_load_entry_mut(&23).await.unwrap();
2169 /// view.try_load_entry_mut(&25).await.unwrap();
2170 /// assert_eq!(view.count().await.unwrap(), 2);
2171 /// # })
2172 /// ```
2173 pub async fn count(&self) -> Result<usize, ViewError> {
2174 self.collection.count().await
2175 }
2176
2177 /// Applies a function f on each index. Indices are visited in an order
2178 /// determined by the custom serialization. If the function f returns false
2179 /// then the loop ends prematurely.
2180 /// ```rust
2181 /// # tokio_test::block_on(async {
2182 /// # use linera_views::context::MemoryContext;
2183 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2184 /// # use linera_views::register_view::RegisterView;
2185 /// # use linera_views::views::View;
2186 /// # let context = MemoryContext::new_for_testing(());
2187 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2188 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2189 /// view.try_load_entry_mut(&28).await.unwrap();
2190 /// view.try_load_entry_mut(&24).await.unwrap();
2191 /// view.try_load_entry_mut(&23).await.unwrap();
2192 /// let mut part_indices = Vec::new();
2193 /// view.for_each_index_while(|index| {
2194 /// part_indices.push(index);
2195 /// Ok(part_indices.len() < 2)
2196 /// })
2197 /// .await
2198 /// .unwrap();
2199 /// assert_eq!(part_indices, vec![23, 24]);
2200 /// # })
2201 /// ```
2202 pub async fn for_each_index_while<F>(&self, mut f: F) -> Result<(), ViewError>
2203 where
2204 F: FnMut(I) -> Result<bool, ViewError> + Send,
2205 {
2206 self.collection
2207 .for_each_key_while(|key| {
2208 let index = I::from_custom_bytes(key)?;
2209 f(index)
2210 })
2211 .await?;
2212 Ok(())
2213 }
2214
2215 /// Applies a function f on each index. Indices are visited in an order
2216 /// determined by the custom serialization.
2217 /// ```rust
2218 /// # tokio_test::block_on(async {
2219 /// # use linera_views::context::MemoryContext;
2220 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2221 /// # use linera_views::register_view::RegisterView;
2222 /// # use linera_views::views::View;
2223 /// # let context = MemoryContext::new_for_testing(());
2224 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2225 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2226 /// view.try_load_entry_mut(&28).await.unwrap();
2227 /// view.try_load_entry_mut(&24).await.unwrap();
2228 /// view.try_load_entry_mut(&23).await.unwrap();
2229 /// let mut indices = Vec::new();
2230 /// view.for_each_index(|index| {
2231 /// indices.push(index);
2232 /// Ok(())
2233 /// })
2234 /// .await
2235 /// .unwrap();
2236 /// assert_eq!(indices, vec![23, 24, 28]);
2237 /// # })
2238 /// ```
2239 pub async fn for_each_index<F>(&self, mut f: F) -> Result<(), ViewError>
2240 where
2241 F: FnMut(I) -> Result<(), ViewError> + Send,
2242 {
2243 self.collection
2244 .for_each_key(|key| {
2245 let index = I::from_custom_bytes(key)?;
2246 f(index)
2247 })
2248 .await?;
2249 Ok(())
2250 }
2251}
2252
2253impl<I, W> HashableView for ReentrantCustomCollectionView<W::Context, I, W>
2254where
2255 W: HashableView,
2256 I: Send + Sync + CustomSerialize,
2257{
2258 type Hasher = sha3::Sha3_256;
2259
2260 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
2261 self.collection.hash_mut().await
2262 }
2263
2264 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
2265 self.collection.hash().await
2266 }
2267}
2268
2269/// Type wrapping `ReentrantByteCollectionView` while memoizing the hash.
2270pub type HashedReentrantByteCollectionView<C, W> =
2271 WrappedHashableContainerView<C, ReentrantByteCollectionView<C, W>, HasherOutput>;
2272
2273/// Type wrapping `ReentrantCollectionView` while memoizing the hash.
2274pub type HashedReentrantCollectionView<C, I, W> =
2275 WrappedHashableContainerView<C, ReentrantCollectionView<C, I, W>, HasherOutput>;
2276
2277/// Type wrapping `ReentrantCustomCollectionView` while memoizing the hash.
2278pub type HashedReentrantCustomCollectionView<C, I, W> =
2279 WrappedHashableContainerView<C, ReentrantCustomCollectionView<C, I, W>, HasherOutput>;
2280
2281/// Wrapper around `ReentrantByteCollectionView` to compute hashes based on the history of changes.
2282pub type HistoricallyHashedReentrantByteCollectionView<C, W> =
2283 HistoricallyHashableView<C, ReentrantByteCollectionView<C, W>>;
2284
2285/// Wrapper around `ReentrantCollectionView` to compute hashes based on the history of changes.
2286pub type HistoricallyHashedReentrantCollectionView<C, I, W> =
2287 HistoricallyHashableView<C, ReentrantCollectionView<C, I, W>>;
2288
2289/// Wrapper around `ReentrantCustomCollectionView` to compute hashes based on the history of changes.
2290pub type HistoricallyHashedReentrantCustomCollectionView<C, I, W> =
2291 HistoricallyHashableView<C, ReentrantCustomCollectionView<C, I, W>>;
2292
2293#[cfg(with_graphql)]
2294mod graphql {
2295 use std::borrow::Cow;
2296
2297 use super::{ReadGuardedView, ReentrantCollectionView};
2298 use crate::{
2299 graphql::{hash_name, mangle, missing_key_error, Entry, MapInput},
2300 views::View,
2301 };
2302
2303 impl<T: async_graphql::OutputType> async_graphql::OutputType for ReadGuardedView<T> {
2304 fn type_name() -> Cow<'static, str> {
2305 T::type_name()
2306 }
2307
2308 fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
2309 T::create_type_info(registry)
2310 }
2311
2312 async fn resolve(
2313 &self,
2314 ctx: &async_graphql::ContextSelectionSet<'_>,
2315 field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
2316 ) -> async_graphql::ServerResult<async_graphql::Value> {
2317 (**self).resolve(ctx, field).await
2318 }
2319 }
2320
2321 impl<C: Send + Sync, K: async_graphql::OutputType, V: async_graphql::OutputType>
2322 async_graphql::TypeName for ReentrantCollectionView<C, K, V>
2323 {
2324 fn type_name() -> Cow<'static, str> {
2325 format!(
2326 "ReentrantCollectionView_{}_{}_{:08x}",
2327 mangle(K::type_name()),
2328 mangle(V::type_name()),
2329 hash_name::<(K, V)>(),
2330 )
2331 .into()
2332 }
2333 }
2334
2335 #[async_graphql::Object(cache_control(no_cache), name_type)]
2336 impl<K, V> ReentrantCollectionView<V::Context, K, V>
2337 where
2338 K: async_graphql::InputType
2339 + async_graphql::OutputType
2340 + serde::ser::Serialize
2341 + serde::de::DeserializeOwned
2342 + std::fmt::Debug,
2343 V: View + async_graphql::OutputType,
2344 {
2345 async fn keys(&self) -> Result<Vec<K>, async_graphql::Error> {
2346 Ok(self.indices().await?)
2347 }
2348
2349 #[graphql(derived(name = "count"))]
2350 async fn count_(&self) -> Result<u32, async_graphql::Error> {
2351 Ok(self.count().await? as u32)
2352 }
2353
2354 async fn entry(
2355 &self,
2356 key: K,
2357 ) -> Result<Entry<K, ReadGuardedView<V>>, async_graphql::Error> {
2358 let value = self
2359 .try_load_entry(&key)
2360 .await?
2361 .ok_or_else(|| missing_key_error(&key))?;
2362 Ok(Entry { value, key })
2363 }
2364
2365 async fn entries(
2366 &self,
2367 input: Option<MapInput<K>>,
2368 ) -> Result<Vec<Entry<K, ReadGuardedView<V>>>, async_graphql::Error> {
2369 let keys = if let Some(keys) = input
2370 .and_then(|input| input.filters)
2371 .and_then(|filters| filters.keys)
2372 {
2373 keys
2374 } else {
2375 self.indices().await?
2376 };
2377
2378 let values = self.try_load_entries(&keys).await?;
2379 Ok(values
2380 .into_iter()
2381 .zip(keys)
2382 .filter_map(|(value, key)| value.map(|value| Entry { value, key }))
2383 .collect())
2384 }
2385 }
2386
2387 use crate::reentrant_collection_view::ReentrantCustomCollectionView;
2388 impl<C: Send + Sync, K: async_graphql::OutputType, V: async_graphql::OutputType>
2389 async_graphql::TypeName for ReentrantCustomCollectionView<C, K, V>
2390 {
2391 fn type_name() -> Cow<'static, str> {
2392 format!(
2393 "ReentrantCustomCollectionView_{}_{}_{:08x}",
2394 mangle(K::type_name()),
2395 mangle(V::type_name()),
2396 hash_name::<(K, V)>(),
2397 )
2398 .into()
2399 }
2400 }
2401
2402 #[async_graphql::Object(cache_control(no_cache), name_type)]
2403 impl<K, V> ReentrantCustomCollectionView<V::Context, K, V>
2404 where
2405 K: async_graphql::InputType
2406 + async_graphql::OutputType
2407 + crate::common::CustomSerialize
2408 + std::fmt::Debug,
2409 V: View + async_graphql::OutputType,
2410 {
2411 async fn keys(&self) -> Result<Vec<K>, async_graphql::Error> {
2412 Ok(self.indices().await?)
2413 }
2414
2415 async fn entry(
2416 &self,
2417 key: K,
2418 ) -> Result<Entry<K, ReadGuardedView<V>>, async_graphql::Error> {
2419 let value = self
2420 .try_load_entry(&key)
2421 .await?
2422 .ok_or_else(|| missing_key_error(&key))?;
2423 Ok(Entry { value, key })
2424 }
2425
2426 async fn entries(
2427 &self,
2428 input: Option<MapInput<K>>,
2429 ) -> Result<Vec<Entry<K, ReadGuardedView<V>>>, async_graphql::Error> {
2430 let keys = if let Some(keys) = input
2431 .and_then(|input| input.filters)
2432 .and_then(|filters| filters.keys)
2433 {
2434 keys
2435 } else {
2436 self.indices().await?
2437 };
2438
2439 let values = self.try_load_entries(&keys).await?;
2440 Ok(values
2441 .into_iter()
2442 .zip(keys)
2443 .filter_map(|(value, key)| value.map(|value| Entry { value, key }))
2444 .collect())
2445 }
2446 }
2447}