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 "Entry should have been inserted as Update::Set by try_load_view_mut"
596 )
597 };
598 Ok(WriteGuardedView(
599 view.clone()
600 .try_write_arc()
601 .ok_or_else(|| ViewError::TryLockError(short_key))?,
602 ))
603 })
604 .collect()
605 }
606
607 /// Loads multiple entries for writing at once with their keys.
608 /// The entries in short_keys have to be all distinct.
609 /// ```rust
610 /// # tokio_test::block_on(async {
611 /// # use linera_views::context::MemoryContext;
612 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
613 /// # use linera_views::register_view::RegisterView;
614 /// # use linera_views::views::View;
615 /// # let context = MemoryContext::new_for_testing(());
616 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
617 /// ReentrantByteCollectionView::load(context).await.unwrap();
618 /// {
619 /// let mut subview = view.try_load_entry_mut(&vec![0, 1]).await.unwrap();
620 /// *subview.get_mut() = "Bonjour".to_string();
621 /// }
622 /// let short_keys = vec![vec![0, 1], vec![2, 3]];
623 /// let subviews = view.try_load_entries_pairs_mut(short_keys).await.unwrap();
624 /// let value1 = subviews[0].1.get();
625 /// let value2 = subviews[1].1.get();
626 /// assert_eq!(*value1, "Bonjour".to_string());
627 /// assert_eq!(*value2, String::default());
628 /// # })
629 /// ```
630 pub async fn try_load_entries_pairs_mut(
631 &mut self,
632 short_keys: Vec<Vec<u8>>,
633 ) -> Result<Vec<(Vec<u8>, WriteGuardedView<W>)>, ViewError> {
634 let values = self.try_load_entries_mut(short_keys.clone()).await?;
635 Ok(short_keys.into_iter().zip(values).collect())
636 }
637
638 /// Loads multiple entries for reading at once.
639 /// The entries in `short_keys` have to be all distinct.
640 /// ```rust
641 /// # tokio_test::block_on(async {
642 /// # use linera_views::context::MemoryContext;
643 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
644 /// # use linera_views::register_view::RegisterView;
645 /// # use linera_views::views::View;
646 /// # let context = MemoryContext::new_for_testing(());
647 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
648 /// ReentrantByteCollectionView::load(context).await.unwrap();
649 /// {
650 /// let _subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
651 /// }
652 /// let short_keys = vec![vec![0, 1], vec![2, 3]];
653 /// let subviews = view.try_load_entries(short_keys).await.unwrap();
654 /// assert!(subviews[1].is_none());
655 /// let value0 = subviews[0].as_ref().unwrap().get();
656 /// assert_eq!(*value0, String::default());
657 /// # })
658 /// ```
659 pub async fn try_load_entries(
660 &self,
661 short_keys: Vec<Vec<u8>>,
662 ) -> Result<Vec<Option<ReadGuardedView<W>>>, ViewError> {
663 let mut results = vec![None; short_keys.len()];
664 let mut keys_to_check = Vec::new();
665 let mut keys_to_check_metadata = Vec::new();
666
667 for (position, short_key) in short_keys.into_iter().enumerate() {
668 if let Some(update) = self.updates.get(&short_key) {
669 if let Update::Set(view) = update {
670 results[position] = Some((short_key, view.clone()));
671 }
672 } else if !self.delete_storage_first {
673 let key_index = self
674 .context
675 .base_key()
676 .base_tag_index(KeyTag::Index as u8, &short_key);
677 keys_to_check.push(key_index);
678 keys_to_check_metadata.push((position, short_key));
679 }
680 }
681
682 let found_keys = self.context.store().contains_keys(&keys_to_check).await?;
683 let entries_to_load = keys_to_check_metadata
684 .into_iter()
685 .zip(found_keys)
686 .filter_map(|(metadata, found)| found.then_some(metadata))
687 .map(|(position, short_key)| {
688 let subview_key = self
689 .context
690 .base_key()
691 .base_tag_index(KeyTag::Subview as u8, &short_key);
692 let subview_context = self.context.clone_with_base_key(subview_key);
693 (position, short_key.to_owned(), subview_context)
694 })
695 .collect::<Vec<_>>();
696 if !entries_to_load.is_empty() {
697 let mut keys_to_load = Vec::with_capacity(entries_to_load.len() * W::NUM_INIT_KEYS);
698 for (_, _, context) in &entries_to_load {
699 keys_to_load.extend(W::pre_load(context)?);
700 }
701 let values = self
702 .context
703 .store()
704 .read_multi_values_bytes(&keys_to_load)
705 .await?;
706 for (loaded_values, (position, short_key, context)) in values
707 .chunks_exact_or_repeat(W::NUM_INIT_KEYS)
708 .zip(entries_to_load)
709 {
710 let view = W::post_load(context, loaded_values)?;
711 let wrapped_view = Arc::new(RwLock::new(view));
712 results[position] = Some((short_key, wrapped_view));
713 }
714 }
715
716 results
717 .into_iter()
718 .map(|maybe_view| match maybe_view {
719 Some((short_key, view)) => Ok(Some(ReadGuardedView(
720 view.try_read_arc()
721 .ok_or_else(|| ViewError::TryLockError(short_key))?,
722 ))),
723 None => Ok(None),
724 })
725 .collect()
726 }
727
728 /// Loads multiple entries for reading at once with their keys.
729 /// The entries in short_keys have to be all distinct.
730 /// ```rust
731 /// # tokio_test::block_on(async {
732 /// # use linera_views::context::MemoryContext;
733 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
734 /// # use linera_views::register_view::RegisterView;
735 /// # use linera_views::views::View;
736 /// # let context = MemoryContext::new_for_testing(());
737 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
738 /// ReentrantByteCollectionView::load(context).await.unwrap();
739 /// {
740 /// let _subview = view.try_load_entry_mut(&vec![0, 1]).await.unwrap();
741 /// }
742 /// let short_keys = vec![vec![0, 1], vec![0, 2]];
743 /// let subviews = view.try_load_entries_pairs(short_keys).await.unwrap();
744 /// assert!(subviews[1].1.is_none());
745 /// let value0 = subviews[0].1.as_ref().unwrap().get();
746 /// assert_eq!(*value0, String::default());
747 /// # })
748 /// ```
749 pub async fn try_load_entries_pairs(
750 &self,
751 short_keys: Vec<Vec<u8>>,
752 ) -> Result<Vec<(Vec<u8>, Option<ReadGuardedView<W>>)>, ViewError> {
753 let values = self.try_load_entries(short_keys.clone()).await?;
754 Ok(short_keys.into_iter().zip(values).collect())
755 }
756
757 /// Loads all the entries for reading at once.
758 /// ```rust
759 /// # tokio_test::block_on(async {
760 /// # use linera_views::context::MemoryContext;
761 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
762 /// # use linera_views::register_view::RegisterView;
763 /// # use linera_views::views::View;
764 /// # let context = MemoryContext::new_for_testing(());
765 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
766 /// ReentrantByteCollectionView::load(context).await.unwrap();
767 /// {
768 /// let _subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
769 /// }
770 /// let subviews = view.try_load_all_entries().await.unwrap();
771 /// assert_eq!(subviews.len(), 1);
772 /// # })
773 /// ```
774 pub async fn try_load_all_entries(
775 &self,
776 ) -> Result<Vec<(Vec<u8>, ReadGuardedView<W>)>, ViewError> {
777 let short_keys = self.keys().await?;
778 let mut loaded_views = vec![None; short_keys.len()];
779
780 // Load views that are not in updates and not deleted
781 if !self.delete_storage_first {
782 let mut keys = Vec::new();
783 let mut short_keys_and_indexes = Vec::new();
784 for (index, short_key) in short_keys.iter().enumerate() {
785 if !self.updates.contains_key(short_key) {
786 let key = self
787 .context
788 .base_key()
789 .base_tag_index(KeyTag::Subview as u8, short_key);
790 let context = self.context.clone_with_base_key(key);
791 keys.extend(W::pre_load(&context)?);
792 short_keys_and_indexes.push((short_key.to_vec(), index));
793 }
794 }
795 let values = self.context.store().read_multi_values_bytes(&keys).await?;
796 for (loaded_values, (short_key, index)) in values
797 .chunks_exact_or_repeat(W::NUM_INIT_KEYS)
798 .zip(short_keys_and_indexes)
799 {
800 let key = self
801 .context
802 .base_key()
803 .base_tag_index(KeyTag::Subview as u8, &short_key);
804 let context = self.context.clone_with_base_key(key);
805 let view = W::post_load(context, loaded_values)?;
806 let wrapped_view = Arc::new(RwLock::new(view));
807 loaded_views[index] = Some(wrapped_view);
808 }
809 }
810
811 // Create result from updates and loaded views
812 short_keys
813 .into_iter()
814 .zip(loaded_views)
815 .map(|(short_key, loaded_view)| {
816 let view = if let Some(Update::Set(view)) = self.updates.get(&short_key) {
817 view.clone()
818 } else if let Some(view) = loaded_view {
819 view
820 } else {
821 unreachable!("All entries should have been loaded into memory");
822 };
823 let guard = ReadGuardedView(
824 view.try_read_arc()
825 .ok_or_else(|| ViewError::TryLockError(short_key.clone()))?,
826 );
827 Ok((short_key, guard))
828 })
829 .collect()
830 }
831
832 /// Loads all the entries for writing at once.
833 /// ```rust
834 /// # tokio_test::block_on(async {
835 /// # use linera_views::context::MemoryContext;
836 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
837 /// # use linera_views::register_view::RegisterView;
838 /// # use linera_views::views::View;
839 /// # let context = MemoryContext::new_for_testing(());
840 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
841 /// ReentrantByteCollectionView::load(context).await.unwrap();
842 /// {
843 /// let _subview = view.try_load_entry_mut(&[0, 1]).await.unwrap();
844 /// }
845 /// let subviews = view.try_load_all_entries_mut().await.unwrap();
846 /// assert_eq!(subviews.len(), 1);
847 /// # })
848 /// ```
849 pub async fn try_load_all_entries_mut(
850 &mut self,
851 ) -> Result<Vec<(Vec<u8>, WriteGuardedView<W>)>, ViewError> {
852 let short_keys = self.keys().await?;
853 if !self.delete_storage_first {
854 let mut keys = Vec::new();
855 let mut short_keys_to_load = Vec::new();
856
857 for short_key in &short_keys {
858 if !self.updates.contains_key(short_key) {
859 let key = self
860 .context
861 .base_key()
862 .base_tag_index(KeyTag::Subview as u8, short_key);
863 let context = self.context.clone_with_base_key(key);
864 keys.extend(W::pre_load(&context)?);
865 short_keys_to_load.push(short_key.to_vec());
866 }
867 }
868
869 let values = self.context.store().read_multi_values_bytes(&keys).await?;
870 for (loaded_values, short_key) in values
871 .chunks_exact_or_repeat(W::NUM_INIT_KEYS)
872 .zip(short_keys_to_load)
873 {
874 let key = self
875 .context
876 .base_key()
877 .base_tag_index(KeyTag::Subview as u8, &short_key);
878 let context = self.context.clone_with_base_key(key);
879 let view = W::post_load(context, loaded_values)?;
880 let wrapped_view = Arc::new(RwLock::new(view));
881 self.updates
882 .insert(short_key.to_vec(), Update::Set(wrapped_view));
883 }
884 }
885 short_keys
886 .into_iter()
887 .map(|short_key| {
888 let Some(Update::Set(view)) = self.updates.get(&short_key) else {
889 unreachable!("All entries should have been loaded into `updates`")
890 };
891 let guard = WriteGuardedView(
892 view.clone()
893 .try_write_arc()
894 .ok_or_else(|| ViewError::TryLockError(short_key.clone()))?,
895 );
896 Ok((short_key, guard))
897 })
898 .collect()
899 }
900}
901
902impl<W: View> ReentrantByteCollectionView<W::Context, W> {
903 /// Returns the list of indices in the collection in lexicographic order.
904 /// ```rust
905 /// # tokio_test::block_on(async {
906 /// # use linera_views::context::MemoryContext;
907 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
908 /// # use linera_views::register_view::RegisterView;
909 /// # use linera_views::views::View;
910 /// # let context = MemoryContext::new_for_testing(());
911 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
912 /// ReentrantByteCollectionView::load(context).await.unwrap();
913 /// view.try_load_entry_mut(&[0, 1]).await.unwrap();
914 /// view.try_load_entry_mut(&[0, 2]).await.unwrap();
915 /// let keys = view.keys().await.unwrap();
916 /// assert_eq!(keys, vec![vec![0, 1], vec![0, 2]]);
917 /// # })
918 /// ```
919 pub async fn keys(&self) -> Result<Vec<Vec<u8>>, ViewError> {
920 let mut keys = Vec::new();
921 self.for_each_key(|key| {
922 keys.push(key.to_vec());
923 Ok(())
924 })
925 .await?;
926 Ok(keys)
927 }
928
929 /// Returns the number of indices of the collection.
930 /// ```rust
931 /// # tokio_test::block_on(async {
932 /// # use linera_views::context::MemoryContext;
933 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
934 /// # use linera_views::register_view::RegisterView;
935 /// # use linera_views::views::View;
936 /// # let context = MemoryContext::new_for_testing(());
937 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
938 /// ReentrantByteCollectionView::load(context).await.unwrap();
939 /// view.try_load_entry_mut(&[0, 1]).await.unwrap();
940 /// view.try_load_entry_mut(&[0, 2]).await.unwrap();
941 /// assert_eq!(view.iterative_count().await.unwrap(), 2);
942 /// # })
943 /// ```
944 pub async fn iterative_count(&self) -> Result<usize, ViewError> {
945 let mut count = 0;
946 self.for_each_key(|_key| {
947 count += 1;
948 Ok(())
949 })
950 .await?;
951 Ok(count)
952 }
953
954 /// Applies a function f on each index (aka key). Keys are visited in a
955 /// lexicographic order. If the function returns false then the loop
956 /// ends prematurely.
957 /// ```rust
958 /// # tokio_test::block_on(async {
959 /// # use linera_views::context::MemoryContext;
960 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
961 /// # use linera_views::register_view::RegisterView;
962 /// # use linera_views::views::View;
963 /// # let context = MemoryContext::new_for_testing(());
964 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
965 /// ReentrantByteCollectionView::load(context).await.unwrap();
966 /// view.try_load_entry_mut(&[0, 1]).await.unwrap();
967 /// view.try_load_entry_mut(&[0, 2]).await.unwrap();
968 /// let mut count = 0;
969 /// view.for_each_key_while(|_key| {
970 /// count += 1;
971 /// Ok(count < 1)
972 /// })
973 /// .await
974 /// .unwrap();
975 /// assert_eq!(count, 1);
976 /// # })
977 /// ```
978 pub async fn for_each_key_while<F>(&self, mut f: F) -> Result<(), ViewError>
979 where
980 F: FnMut(&[u8]) -> Result<bool, ViewError> + Send,
981 {
982 let mut updates = self.updates.iter();
983 let mut update = updates.next();
984 if !self.delete_storage_first {
985 let base = self.get_index_key(&[]);
986 for index in self.context.store().find_keys_by_prefix(&base).await? {
987 loop {
988 match update {
989 Some((key, value)) if key <= &index => {
990 if let Update::Set(_) = value {
991 if !f(key)? {
992 return Ok(());
993 }
994 }
995 update = updates.next();
996 if key == &index {
997 break;
998 }
999 }
1000 _ => {
1001 if !f(&index)? {
1002 return Ok(());
1003 }
1004 break;
1005 }
1006 }
1007 }
1008 }
1009 }
1010 while let Some((key, value)) = update {
1011 if let Update::Set(_) = value {
1012 if !f(key)? {
1013 return Ok(());
1014 }
1015 }
1016 update = updates.next();
1017 }
1018 Ok(())
1019 }
1020
1021 /// Applies a function f on each index (aka key). Keys are visited in a
1022 /// lexicographic order.
1023 /// ```rust
1024 /// # tokio_test::block_on(async {
1025 /// # use linera_views::context::MemoryContext;
1026 /// # use linera_views::reentrant_collection_view::ReentrantByteCollectionView;
1027 /// # use linera_views::register_view::RegisterView;
1028 /// # use linera_views::views::View;
1029 /// # let context = MemoryContext::new_for_testing(());
1030 /// let mut view: ReentrantByteCollectionView<_, RegisterView<_, String>> =
1031 /// ReentrantByteCollectionView::load(context).await.unwrap();
1032 /// view.try_load_entry_mut(&[0, 1]).await.unwrap();
1033 /// view.try_load_entry_mut(&[0, 2]).await.unwrap();
1034 /// let mut count = 0;
1035 /// view.for_each_key(|_key| {
1036 /// count += 1;
1037 /// Ok(())
1038 /// })
1039 /// .await
1040 /// .unwrap();
1041 /// assert_eq!(count, 2);
1042 /// # })
1043 /// ```
1044 pub async fn for_each_key<F>(&self, mut f: F) -> Result<(), ViewError>
1045 where
1046 F: FnMut(&[u8]) -> Result<(), ViewError> + Send,
1047 {
1048 self.for_each_key_while(|key| {
1049 f(key)?;
1050 Ok(true)
1051 })
1052 .await
1053 }
1054}
1055
1056impl<W: HashableView> HashableView for ReentrantByteCollectionView<W::Context, W> {
1057 type Hasher = sha3::Sha3_256;
1058
1059 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1060 #[cfg(with_metrics)]
1061 let _hash_latency = metrics::REENTRANT_COLLECTION_VIEW_HASH_RUNTIME.measure_latency();
1062 let mut hasher = sha3::Sha3_256::default();
1063 let keys = self.keys().await?;
1064 let count = keys.len() as u32;
1065 hasher.update_with_bcs_bytes(&count)?;
1066 for key in keys {
1067 hasher.update_with_bytes(&key)?;
1068 let hash = if let Some(entry) = self.updates.get_mut(&key) {
1069 let Update::Set(view) = entry else {
1070 unreachable!("Loaded entries in updates should always be Update::Set");
1071 };
1072 let mut view = view
1073 .try_write_arc()
1074 .ok_or_else(|| ViewError::TryLockError(key))?;
1075 view.hash_mut().await?
1076 } else {
1077 let key = self
1078 .context
1079 .base_key()
1080 .base_tag_index(KeyTag::Subview as u8, &key);
1081 let context = self.context.clone_with_base_key(key);
1082 let mut view = W::load(context).await?;
1083 view.hash_mut().await?
1084 };
1085 hasher.write_all(hash.as_ref())?;
1086 }
1087 Ok(hasher.finalize())
1088 }
1089
1090 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1091 #[cfg(with_metrics)]
1092 let _hash_latency = metrics::REENTRANT_COLLECTION_VIEW_HASH_RUNTIME.measure_latency();
1093 let mut hasher = sha3::Sha3_256::default();
1094 let keys = self.keys().await?;
1095 let count = keys.len() as u32;
1096 hasher.update_with_bcs_bytes(&count)?;
1097 for key in keys {
1098 hasher.update_with_bytes(&key)?;
1099 let hash = if let Some(entry) = self.updates.get(&key) {
1100 let Update::Set(view) = entry else {
1101 unreachable!("Loaded entries in updates should always be Update::Set");
1102 };
1103 let view = view
1104 .try_read_arc()
1105 .ok_or_else(|| ViewError::TryLockError(key))?;
1106 view.hash().await?
1107 } else {
1108 let key = self
1109 .context
1110 .base_key()
1111 .base_tag_index(KeyTag::Subview as u8, &key);
1112 let context = self.context.clone_with_base_key(key);
1113 let view = W::load(context).await?;
1114 view.hash().await?
1115 };
1116 hasher.write_all(hash.as_ref())?;
1117 }
1118 Ok(hasher.finalize())
1119 }
1120}
1121
1122/// A view that supports accessing a collection of views of the same kind, indexed by keys,
1123/// possibly several subviews at a time.
1124#[derive(Debug, Allocative)]
1125#[allocative(bound = "C, I, W: Allocative")]
1126pub struct ReentrantCollectionView<C, I, W> {
1127 collection: ReentrantByteCollectionView<C, W>,
1128 #[allocative(skip)]
1129 _phantom: PhantomData<I>,
1130}
1131
1132impl<I, W, C2> ReplaceContext<C2> for ReentrantCollectionView<W::Context, I, W>
1133where
1134 W: View + ReplaceContext<C2>,
1135 I: Send + Sync + Serialize + DeserializeOwned,
1136 C2: Context,
1137{
1138 type Target = ReentrantCollectionView<C2, I, <W as ReplaceContext<C2>>::Target>;
1139
1140 async fn with_context(
1141 &mut self,
1142 ctx: impl FnOnce(&Self::Context) -> C2 + Clone,
1143 ) -> Self::Target {
1144 ReentrantCollectionView {
1145 collection: self.collection.with_context(ctx).await,
1146 _phantom: self._phantom,
1147 }
1148 }
1149}
1150
1151impl<I, W> View for ReentrantCollectionView<W::Context, I, W>
1152where
1153 W: View,
1154 I: Send + Sync + Serialize + DeserializeOwned,
1155{
1156 const NUM_INIT_KEYS: usize = ReentrantByteCollectionView::<W::Context, W>::NUM_INIT_KEYS;
1157
1158 type Context = W::Context;
1159
1160 fn context(&self) -> Self::Context {
1161 self.collection.context()
1162 }
1163
1164 fn pre_load(context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
1165 ReentrantByteCollectionView::<W::Context, W>::pre_load(context)
1166 }
1167
1168 fn post_load(context: Self::Context, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
1169 let collection = ReentrantByteCollectionView::post_load(context, values)?;
1170 Ok(ReentrantCollectionView {
1171 collection,
1172 _phantom: PhantomData,
1173 })
1174 }
1175
1176 fn rollback(&mut self) {
1177 self.collection.rollback()
1178 }
1179
1180 async fn has_pending_changes(&self) -> bool {
1181 self.collection.has_pending_changes().await
1182 }
1183
1184 fn pre_save(&self, batch: &mut Batch) -> Result<bool, ViewError> {
1185 self.collection.pre_save(batch)
1186 }
1187
1188 fn post_save(&mut self) {
1189 self.collection.post_save()
1190 }
1191
1192 fn clear(&mut self) {
1193 self.collection.clear()
1194 }
1195}
1196
1197impl<I, W> ClonableView for ReentrantCollectionView<W::Context, I, W>
1198where
1199 W: ClonableView,
1200 I: Send + Sync + Serialize + DeserializeOwned,
1201{
1202 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
1203 Ok(ReentrantCollectionView {
1204 collection: self.collection.clone_unchecked()?,
1205 _phantom: PhantomData,
1206 })
1207 }
1208}
1209
1210impl<I, W> ReentrantCollectionView<W::Context, I, W>
1211where
1212 W: View,
1213 I: Sync + Send + Serialize + DeserializeOwned,
1214{
1215 /// Loads a subview for the data at the given index in the collection. If an entry
1216 /// is absent then a default entry is put on the collection. The obtained view can
1217 /// then be modified.
1218 /// ```rust
1219 /// # tokio_test::block_on(async {
1220 /// # use linera_views::context::MemoryContext;
1221 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1222 /// # use linera_views::register_view::RegisterView;
1223 /// # use linera_views::views::View;
1224 /// # let context = MemoryContext::new_for_testing(());
1225 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1226 /// ReentrantCollectionView::load(context).await.unwrap();
1227 /// let subview = view.try_load_entry_mut(&23).await.unwrap();
1228 /// let value = subview.get();
1229 /// assert_eq!(*value, String::default());
1230 /// # })
1231 /// ```
1232 pub async fn try_load_entry_mut<Q>(
1233 &mut self,
1234 index: &Q,
1235 ) -> Result<WriteGuardedView<W>, ViewError>
1236 where
1237 I: Borrow<Q>,
1238 Q: Serialize + ?Sized,
1239 {
1240 let short_key = BaseKey::derive_short_key(index)?;
1241 self.collection.try_load_entry_mut(&short_key).await
1242 }
1243
1244 /// Loads a subview at the given index in the collection and gives read-only access to the data.
1245 /// If an entry is absent then `None` is returned.
1246 /// ```rust
1247 /// # tokio_test::block_on(async {
1248 /// # use linera_views::context::MemoryContext;
1249 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1250 /// # use linera_views::register_view::RegisterView;
1251 /// # use linera_views::views::View;
1252 /// # let context = MemoryContext::new_for_testing(());
1253 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1254 /// ReentrantCollectionView::load(context).await.unwrap();
1255 /// {
1256 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1257 /// }
1258 /// let subview = view.try_load_entry(&23).await.unwrap().unwrap();
1259 /// let value = subview.get();
1260 /// assert_eq!(*value, String::default());
1261 /// # })
1262 /// ```
1263 pub async fn try_load_entry<Q>(
1264 &self,
1265 index: &Q,
1266 ) -> Result<Option<ReadGuardedView<W>>, ViewError>
1267 where
1268 I: Borrow<Q>,
1269 Q: Serialize + ?Sized,
1270 {
1271 let short_key = BaseKey::derive_short_key(index)?;
1272 self.collection.try_load_entry(&short_key).await
1273 }
1274
1275 /// Returns `true` if the collection contains a value for the specified key.
1276 /// ```rust
1277 /// # tokio_test::block_on(async {
1278 /// # use linera_views::context::MemoryContext;
1279 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1280 /// # use linera_views::register_view::RegisterView;
1281 /// # use linera_views::views::View;
1282 /// # let context = MemoryContext::new_for_testing(());
1283 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1284 /// ReentrantCollectionView::load(context).await.unwrap();
1285 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1286 /// assert!(view.contains_key(&23).await.unwrap());
1287 /// assert!(!view.contains_key(&24).await.unwrap());
1288 /// # })
1289 /// ```
1290 pub async fn contains_key<Q>(&self, index: &Q) -> Result<bool, ViewError>
1291 where
1292 I: Borrow<Q>,
1293 Q: Serialize + ?Sized,
1294 {
1295 let short_key = BaseKey::derive_short_key(index)?;
1296 self.collection.contains_key(&short_key).await
1297 }
1298
1299 /// Marks the entry so that it is removed in the next flush.
1300 /// ```rust
1301 /// # tokio_test::block_on(async {
1302 /// # use linera_views::context::MemoryContext;
1303 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1304 /// # use linera_views::register_view::RegisterView;
1305 /// # use linera_views::views::View;
1306 /// # let context = MemoryContext::new_for_testing(());
1307 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1308 /// ReentrantCollectionView::load(context).await.unwrap();
1309 /// let mut subview = view.try_load_entry_mut(&23).await.unwrap();
1310 /// let value = subview.get_mut();
1311 /// assert_eq!(*value, String::default());
1312 /// view.remove_entry(&23);
1313 /// let keys = view.indices().await.unwrap();
1314 /// assert_eq!(keys.len(), 0);
1315 /// # })
1316 /// ```
1317 pub fn remove_entry<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1318 where
1319 I: Borrow<Q>,
1320 Q: Serialize + ?Sized,
1321 {
1322 let short_key = BaseKey::derive_short_key(index)?;
1323 self.collection.remove_entry(short_key);
1324 Ok(())
1325 }
1326
1327 /// Marks the entry so that it is removed in the next flush.
1328 /// ```rust
1329 /// # tokio_test::block_on(async {
1330 /// # use linera_views::context::MemoryContext;
1331 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1332 /// # use linera_views::register_view::RegisterView;
1333 /// # use linera_views::views::View;
1334 /// # let context = MemoryContext::new_for_testing(());
1335 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1336 /// ReentrantCollectionView::load(context).await.unwrap();
1337 /// {
1338 /// let mut subview = view.try_load_entry_mut(&23).await.unwrap();
1339 /// let value = subview.get_mut();
1340 /// *value = String::from("Hello");
1341 /// }
1342 /// view.try_reset_entry_to_default(&23).unwrap();
1343 /// let mut subview = view.try_load_entry_mut(&23).await.unwrap();
1344 /// let value = subview.get_mut();
1345 /// assert_eq!(*value, String::default());
1346 /// # })
1347 /// ```
1348 pub fn try_reset_entry_to_default<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1349 where
1350 I: Borrow<Q>,
1351 Q: Serialize + ?Sized,
1352 {
1353 let short_key = BaseKey::derive_short_key(index)?;
1354 self.collection.try_reset_entry_to_default(&short_key)
1355 }
1356
1357 /// Gets the extra data.
1358 pub fn extra(&self) -> &<W::Context as Context>::Extra {
1359 self.collection.extra()
1360 }
1361}
1362
1363impl<I, W> ReentrantCollectionView<W::Context, I, W>
1364where
1365 W: View,
1366 I: Sync + Send + Serialize + DeserializeOwned,
1367{
1368 /// Load multiple entries for writing at once.
1369 /// The entries in indices have to be all distinct.
1370 /// ```rust
1371 /// # tokio_test::block_on(async {
1372 /// # use linera_views::context::MemoryContext;
1373 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1374 /// # use linera_views::register_view::RegisterView;
1375 /// # use linera_views::views::View;
1376 /// # let context = MemoryContext::new_for_testing(());
1377 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1378 /// ReentrantCollectionView::load(context).await.unwrap();
1379 /// let indices = vec![23, 42];
1380 /// let subviews = view.try_load_entries_mut(&indices).await.unwrap();
1381 /// let value1 = subviews[0].get();
1382 /// let value2 = subviews[1].get();
1383 /// assert_eq!(*value1, String::default());
1384 /// assert_eq!(*value2, String::default());
1385 /// # })
1386 /// ```
1387 pub async fn try_load_entries_mut<'a, Q>(
1388 &'a mut self,
1389 indices: impl IntoIterator<Item = &'a Q>,
1390 ) -> Result<Vec<WriteGuardedView<W>>, ViewError>
1391 where
1392 I: Borrow<Q>,
1393 Q: Serialize + 'a,
1394 {
1395 let short_keys = indices
1396 .into_iter()
1397 .map(|index| BaseKey::derive_short_key(index))
1398 .collect::<Result<_, _>>()?;
1399 self.collection.try_load_entries_mut(short_keys).await
1400 }
1401
1402 /// Loads multiple entries for writing at once with their keys.
1403 /// The entries in indices have to be all distinct.
1404 /// ```rust
1405 /// # tokio_test::block_on(async {
1406 /// # use linera_views::context::MemoryContext;
1407 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1408 /// # use linera_views::register_view::RegisterView;
1409 /// # use linera_views::views::View;
1410 /// # let context = MemoryContext::new_for_testing(());
1411 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1412 /// ReentrantCollectionView::load(context).await.unwrap();
1413 /// let indices = [23, 42];
1414 /// let subviews = view.try_load_entries_pairs_mut(indices).await.unwrap();
1415 /// let value1 = subviews[0].1.get();
1416 /// let value2 = subviews[1].1.get();
1417 /// assert_eq!(*value1, String::default());
1418 /// assert_eq!(*value2, String::default());
1419 /// # })
1420 /// ```
1421 pub async fn try_load_entries_pairs_mut<Q>(
1422 &mut self,
1423 indices: impl IntoIterator<Item = Q>,
1424 ) -> Result<Vec<(Q, WriteGuardedView<W>)>, ViewError>
1425 where
1426 I: Borrow<Q>,
1427 Q: Serialize + Clone,
1428 {
1429 let indices_vec: Vec<Q> = indices.into_iter().collect();
1430 let values = self.try_load_entries_mut(indices_vec.iter()).await?;
1431 Ok(indices_vec.into_iter().zip(values).collect())
1432 }
1433
1434 /// Load multiple entries for reading at once.
1435 /// The entries in indices have to be all distinct.
1436 /// ```rust
1437 /// # tokio_test::block_on(async {
1438 /// # use linera_views::context::MemoryContext;
1439 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1440 /// # use linera_views::register_view::RegisterView;
1441 /// # use linera_views::views::View;
1442 /// # let context = MemoryContext::new_for_testing(());
1443 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1444 /// ReentrantCollectionView::load(context).await.unwrap();
1445 /// {
1446 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1447 /// }
1448 /// let indices = vec![23, 42];
1449 /// let subviews = view.try_load_entries(&indices).await.unwrap();
1450 /// assert!(subviews[1].is_none());
1451 /// let value0 = subviews[0].as_ref().unwrap().get();
1452 /// assert_eq!(*value0, String::default());
1453 /// # })
1454 /// ```
1455 pub async fn try_load_entries<'a, Q>(
1456 &'a self,
1457 indices: impl IntoIterator<Item = &'a Q>,
1458 ) -> Result<Vec<Option<ReadGuardedView<W>>>, ViewError>
1459 where
1460 I: Borrow<Q>,
1461 Q: Serialize + 'a,
1462 {
1463 let short_keys = indices
1464 .into_iter()
1465 .map(|index| BaseKey::derive_short_key(index))
1466 .collect::<Result<_, _>>()?;
1467 self.collection.try_load_entries(short_keys).await
1468 }
1469
1470 /// Loads multiple entries for reading at once with their keys.
1471 /// The entries in indices have to be all distinct.
1472 /// ```rust
1473 /// # tokio_test::block_on(async {
1474 /// # use linera_views::context::MemoryContext;
1475 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1476 /// # use linera_views::register_view::RegisterView;
1477 /// # use linera_views::views::View;
1478 /// # let context = MemoryContext::new_for_testing(());
1479 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1480 /// ReentrantCollectionView::load(context).await.unwrap();
1481 /// {
1482 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1483 /// }
1484 /// let indices = [23, 42];
1485 /// let subviews = view.try_load_entries_pairs(indices).await.unwrap();
1486 /// assert!(subviews[1].1.is_none());
1487 /// let value0 = subviews[0].1.as_ref().unwrap().get();
1488 /// assert_eq!(*value0, String::default());
1489 /// # })
1490 /// ```
1491 pub async fn try_load_entries_pairs<Q>(
1492 &self,
1493 indices: impl IntoIterator<Item = Q>,
1494 ) -> Result<Vec<(Q, Option<ReadGuardedView<W>>)>, ViewError>
1495 where
1496 I: Borrow<Q>,
1497 Q: Serialize + Clone,
1498 {
1499 let indices_vec: Vec<Q> = indices.into_iter().collect();
1500 let values = self.try_load_entries(indices_vec.iter()).await?;
1501 Ok(indices_vec.into_iter().zip(values).collect())
1502 }
1503
1504 /// Loads all entries for writing at once.
1505 /// The entries in indices have to be all distinct.
1506 /// ```rust
1507 /// # tokio_test::block_on(async {
1508 /// # use linera_views::context::MemoryContext;
1509 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1510 /// # use linera_views::register_view::RegisterView;
1511 /// # use linera_views::views::View;
1512 /// # let context = MemoryContext::new_for_testing(());
1513 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1514 /// ReentrantCollectionView::load(context).await.unwrap();
1515 /// {
1516 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1517 /// }
1518 /// let subviews = view.try_load_all_entries_mut().await.unwrap();
1519 /// assert_eq!(subviews.len(), 1);
1520 /// # })
1521 /// ```
1522 pub async fn try_load_all_entries_mut(
1523 &mut self,
1524 ) -> Result<Vec<(I, WriteGuardedView<W>)>, ViewError> {
1525 let results = self.collection.try_load_all_entries_mut().await?;
1526 results
1527 .into_iter()
1528 .map(|(short_key, view)| {
1529 let index = BaseKey::deserialize_value(&short_key)?;
1530 Ok((index, view))
1531 })
1532 .collect()
1533 }
1534
1535 /// Load multiple entries for reading at once.
1536 /// The entries in indices have to be all distinct.
1537 /// ```rust
1538 /// # tokio_test::block_on(async {
1539 /// # use linera_views::context::MemoryContext;
1540 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1541 /// # use linera_views::register_view::RegisterView;
1542 /// # use linera_views::views::View;
1543 /// # let context = MemoryContext::new_for_testing(());
1544 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1545 /// ReentrantCollectionView::load(context).await.unwrap();
1546 /// {
1547 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1548 /// }
1549 /// let subviews = view.try_load_all_entries().await.unwrap();
1550 /// assert_eq!(subviews.len(), 1);
1551 /// # })
1552 /// ```
1553 pub async fn try_load_all_entries(&self) -> Result<Vec<(I, ReadGuardedView<W>)>, ViewError> {
1554 let results = self.collection.try_load_all_entries().await?;
1555 results
1556 .into_iter()
1557 .map(|(short_key, view)| {
1558 let index = BaseKey::deserialize_value(&short_key)?;
1559 Ok((index, view))
1560 })
1561 .collect()
1562 }
1563}
1564
1565impl<I, W> ReentrantCollectionView<W::Context, I, W>
1566where
1567 W: View,
1568 I: Sync + Send + Serialize + DeserializeOwned,
1569{
1570 /// Returns the list of indices in the collection in an order determined
1571 /// by serialization.
1572 /// ```rust
1573 /// # tokio_test::block_on(async {
1574 /// # use linera_views::context::MemoryContext;
1575 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1576 /// # use linera_views::register_view::RegisterView;
1577 /// # use linera_views::views::View;
1578 /// # let context = MemoryContext::new_for_testing(());
1579 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1580 /// ReentrantCollectionView::load(context).await.unwrap();
1581 /// view.try_load_entry_mut(&23).await.unwrap();
1582 /// view.try_load_entry_mut(&25).await.unwrap();
1583 /// let indices = view.indices().await.unwrap();
1584 /// assert_eq!(indices.len(), 2);
1585 /// # })
1586 /// ```
1587 pub async fn indices(&self) -> Result<Vec<I>, ViewError> {
1588 let mut indices = Vec::new();
1589 self.for_each_index(|index| {
1590 indices.push(index);
1591 Ok(())
1592 })
1593 .await?;
1594 Ok(indices)
1595 }
1596
1597 /// Returns the number of indices in the collection.
1598 /// ```rust
1599 /// # tokio_test::block_on(async {
1600 /// # use linera_views::context::MemoryContext;
1601 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1602 /// # use linera_views::register_view::RegisterView;
1603 /// # use linera_views::views::View;
1604 /// # let context = MemoryContext::new_for_testing(());
1605 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1606 /// ReentrantCollectionView::load(context).await.unwrap();
1607 /// view.try_load_entry_mut(&23).await.unwrap();
1608 /// view.try_load_entry_mut(&25).await.unwrap();
1609 /// assert_eq!(view.iterative_count().await.unwrap(), 2);
1610 /// # })
1611 /// ```
1612 pub async fn iterative_count(&self) -> Result<usize, ViewError> {
1613 self.collection.iterative_count().await
1614 }
1615
1616 /// Applies a function f on each index. Indices are visited in an order
1617 /// determined by the serialization. If the function f returns false then
1618 /// the loop ends prematurely.
1619 /// ```rust
1620 /// # tokio_test::block_on(async {
1621 /// # use linera_views::context::MemoryContext;
1622 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1623 /// # use linera_views::register_view::RegisterView;
1624 /// # use linera_views::views::View;
1625 /// # let context = MemoryContext::new_for_testing(());
1626 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1627 /// ReentrantCollectionView::load(context).await.unwrap();
1628 /// view.try_load_entry_mut(&23).await.unwrap();
1629 /// view.try_load_entry_mut(&24).await.unwrap();
1630 /// let mut count = 0;
1631 /// view.for_each_index_while(|_key| {
1632 /// count += 1;
1633 /// Ok(count < 1)
1634 /// })
1635 /// .await
1636 /// .unwrap();
1637 /// assert_eq!(count, 1);
1638 /// # })
1639 /// ```
1640 pub async fn for_each_index_while<F>(&self, mut f: F) -> Result<(), ViewError>
1641 where
1642 F: FnMut(I) -> Result<bool, ViewError> + Send,
1643 {
1644 self.collection
1645 .for_each_key_while(|key| {
1646 let index = BaseKey::deserialize_value(key)?;
1647 f(index)
1648 })
1649 .await?;
1650 Ok(())
1651 }
1652
1653 /// Applies a function f on each index. Indices are visited in an order
1654 /// determined by the serialization.
1655 /// ```rust
1656 /// # tokio_test::block_on(async {
1657 /// # use linera_views::context::MemoryContext;
1658 /// # use linera_views::reentrant_collection_view::ReentrantCollectionView;
1659 /// # use linera_views::register_view::RegisterView;
1660 /// # use linera_views::views::View;
1661 /// # let context = MemoryContext::new_for_testing(());
1662 /// let mut view: ReentrantCollectionView<_, u64, RegisterView<_, String>> =
1663 /// ReentrantCollectionView::load(context).await.unwrap();
1664 /// view.try_load_entry_mut(&23).await.unwrap();
1665 /// view.try_load_entry_mut(&28).await.unwrap();
1666 /// let mut count = 0;
1667 /// view.for_each_index(|_key| {
1668 /// count += 1;
1669 /// Ok(())
1670 /// })
1671 /// .await
1672 /// .unwrap();
1673 /// assert_eq!(count, 2);
1674 /// # })
1675 /// ```
1676 pub async fn for_each_index<F>(&self, mut f: F) -> Result<(), ViewError>
1677 where
1678 F: FnMut(I) -> Result<(), ViewError> + Send,
1679 {
1680 self.collection
1681 .for_each_key(|key| {
1682 let index = BaseKey::deserialize_value(key)?;
1683 f(index)
1684 })
1685 .await?;
1686 Ok(())
1687 }
1688}
1689
1690impl<I, W> HashableView for ReentrantCollectionView<W::Context, I, W>
1691where
1692 W: HashableView,
1693 I: Send + Sync + Serialize + DeserializeOwned,
1694{
1695 type Hasher = sha3::Sha3_256;
1696
1697 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1698 self.collection.hash_mut().await
1699 }
1700
1701 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
1702 self.collection.hash().await
1703 }
1704}
1705
1706/// A view that supports accessing a collection of views of the same kind, indexed by an ordered key,
1707/// possibly several subviews at a time.
1708#[derive(Debug, Allocative)]
1709#[allocative(bound = "C, I, W: Allocative")]
1710pub struct ReentrantCustomCollectionView<C, I, W> {
1711 collection: ReentrantByteCollectionView<C, W>,
1712 #[allocative(skip)]
1713 _phantom: PhantomData<I>,
1714}
1715
1716impl<I, W> View for ReentrantCustomCollectionView<W::Context, I, W>
1717where
1718 W: View,
1719 I: Send + Sync + CustomSerialize,
1720{
1721 const NUM_INIT_KEYS: usize = ReentrantByteCollectionView::<W::Context, W>::NUM_INIT_KEYS;
1722
1723 type Context = W::Context;
1724
1725 fn context(&self) -> Self::Context {
1726 self.collection.context()
1727 }
1728
1729 fn pre_load(context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
1730 ReentrantByteCollectionView::<_, W>::pre_load(context)
1731 }
1732
1733 fn post_load(context: Self::Context, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
1734 let collection = ReentrantByteCollectionView::post_load(context, values)?;
1735 Ok(ReentrantCustomCollectionView {
1736 collection,
1737 _phantom: PhantomData,
1738 })
1739 }
1740
1741 fn rollback(&mut self) {
1742 self.collection.rollback()
1743 }
1744
1745 async fn has_pending_changes(&self) -> bool {
1746 self.collection.has_pending_changes().await
1747 }
1748
1749 fn pre_save(&self, batch: &mut Batch) -> Result<bool, ViewError> {
1750 self.collection.pre_save(batch)
1751 }
1752
1753 fn post_save(&mut self) {
1754 self.collection.post_save()
1755 }
1756
1757 fn clear(&mut self) {
1758 self.collection.clear()
1759 }
1760}
1761
1762impl<I, W> ClonableView for ReentrantCustomCollectionView<W::Context, I, W>
1763where
1764 W: ClonableView,
1765 Self: View,
1766{
1767 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
1768 Ok(ReentrantCustomCollectionView {
1769 collection: self.collection.clone_unchecked()?,
1770 _phantom: PhantomData,
1771 })
1772 }
1773}
1774
1775impl<I, W> ReentrantCustomCollectionView<W::Context, I, W>
1776where
1777 W: View,
1778 I: Sync + Send + CustomSerialize,
1779{
1780 /// Loads a subview for the data at the given index in the collection. If an entry
1781 /// is absent then a default entry is put in the collection on this index.
1782 /// ```rust
1783 /// # tokio_test::block_on(async {
1784 /// # use linera_views::context::MemoryContext;
1785 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1786 /// # use linera_views::register_view::RegisterView;
1787 /// # use linera_views::views::View;
1788 /// # let context = MemoryContext::new_for_testing(());
1789 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1790 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1791 /// let subview = view.try_load_entry_mut(&23).await.unwrap();
1792 /// let value = subview.get();
1793 /// assert_eq!(*value, String::default());
1794 /// # })
1795 /// ```
1796 pub async fn try_load_entry_mut<Q>(
1797 &mut self,
1798 index: &Q,
1799 ) -> Result<WriteGuardedView<W>, ViewError>
1800 where
1801 I: Borrow<Q>,
1802 Q: CustomSerialize,
1803 {
1804 let short_key = index.to_custom_bytes()?;
1805 self.collection.try_load_entry_mut(&short_key).await
1806 }
1807
1808 /// Loads a subview at the given index in the collection and gives read-only access to the data.
1809 /// If an entry is absent then `None` is returned.
1810 /// ```rust
1811 /// # tokio_test::block_on(async {
1812 /// # use linera_views::context::MemoryContext;
1813 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1814 /// # use linera_views::register_view::RegisterView;
1815 /// # use linera_views::views::View;
1816 /// # let context = MemoryContext::new_for_testing(());
1817 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1818 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1819 /// {
1820 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1821 /// }
1822 /// let subview = view.try_load_entry(&23).await.unwrap().unwrap();
1823 /// let value = subview.get();
1824 /// assert_eq!(*value, String::default());
1825 /// # })
1826 /// ```
1827 pub async fn try_load_entry<Q>(
1828 &self,
1829 index: &Q,
1830 ) -> Result<Option<ReadGuardedView<W>>, ViewError>
1831 where
1832 I: Borrow<Q>,
1833 Q: CustomSerialize,
1834 {
1835 let short_key = index.to_custom_bytes()?;
1836 self.collection.try_load_entry(&short_key).await
1837 }
1838
1839 /// Returns `true` if the collection contains a value for the specified key.
1840 /// ```rust
1841 /// # tokio_test::block_on(async {
1842 /// # use linera_views::context::MemoryContext;
1843 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1844 /// # use linera_views::register_view::RegisterView;
1845 /// # use linera_views::views::View;
1846 /// # let context = MemoryContext::new_for_testing(());
1847 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1848 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1849 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
1850 /// assert!(view.contains_key(&23).await.unwrap());
1851 /// assert!(!view.contains_key(&24).await.unwrap());
1852 /// # })
1853 /// ```
1854 pub async fn contains_key<Q>(&self, index: &Q) -> Result<bool, ViewError>
1855 where
1856 I: Borrow<Q>,
1857 Q: CustomSerialize,
1858 {
1859 let short_key = index.to_custom_bytes()?;
1860 self.collection.contains_key(&short_key).await
1861 }
1862
1863 /// Removes an entry. If absent then nothing happens.
1864 /// ```rust
1865 /// # tokio_test::block_on(async {
1866 /// # use linera_views::context::MemoryContext;
1867 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1868 /// # use linera_views::register_view::RegisterView;
1869 /// # use linera_views::views::View;
1870 /// # let context = MemoryContext::new_for_testing(());
1871 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1872 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1873 /// let mut subview = view.try_load_entry_mut(&23).await.unwrap();
1874 /// let value = subview.get_mut();
1875 /// assert_eq!(*value, String::default());
1876 /// view.remove_entry(&23);
1877 /// let keys = view.indices().await.unwrap();
1878 /// assert_eq!(keys.len(), 0);
1879 /// # })
1880 /// ```
1881 pub fn remove_entry<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1882 where
1883 I: Borrow<Q>,
1884 Q: CustomSerialize,
1885 {
1886 let short_key = index.to_custom_bytes()?;
1887 self.collection.remove_entry(short_key);
1888 Ok(())
1889 }
1890
1891 /// Marks the entry so that it is removed in the next flush.
1892 /// ```rust
1893 /// # tokio_test::block_on(async {
1894 /// # use linera_views::context::MemoryContext;
1895 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1896 /// # use linera_views::register_view::RegisterView;
1897 /// # use linera_views::views::View;
1898 /// # let context = MemoryContext::new_for_testing(());
1899 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1900 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1901 /// {
1902 /// let mut subview = view.try_load_entry_mut(&23).await.unwrap();
1903 /// let value = subview.get_mut();
1904 /// *value = String::from("Hello");
1905 /// }
1906 /// {
1907 /// view.try_reset_entry_to_default(&23).unwrap();
1908 /// let subview = view.try_load_entry(&23).await.unwrap().unwrap();
1909 /// let value = subview.get();
1910 /// assert_eq!(*value, String::default());
1911 /// }
1912 /// # })
1913 /// ```
1914 pub fn try_reset_entry_to_default<Q>(&mut self, index: &Q) -> Result<(), ViewError>
1915 where
1916 I: Borrow<Q>,
1917 Q: CustomSerialize,
1918 {
1919 let short_key = index.to_custom_bytes()?;
1920 self.collection.try_reset_entry_to_default(&short_key)
1921 }
1922
1923 /// Gets the extra data.
1924 pub fn extra(&self) -> &<W::Context as Context>::Extra {
1925 self.collection.extra()
1926 }
1927}
1928
1929impl<I, W: View> ReentrantCustomCollectionView<W::Context, I, W>
1930where
1931 I: Sync + Send + CustomSerialize,
1932{
1933 /// Load multiple entries for writing at once.
1934 /// The entries in indices have to be all distinct.
1935 /// ```rust
1936 /// # tokio_test::block_on(async {
1937 /// # use linera_views::context::MemoryContext;
1938 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1939 /// # use linera_views::register_view::RegisterView;
1940 /// # use linera_views::views::View;
1941 /// # let context = MemoryContext::new_for_testing(());
1942 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1943 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1944 /// let subviews = view.try_load_entries_mut(&[23, 42]).await.unwrap();
1945 /// let value1 = subviews[0].get();
1946 /// let value2 = subviews[1].get();
1947 /// assert_eq!(*value1, String::default());
1948 /// assert_eq!(*value2, String::default());
1949 /// # })
1950 /// ```
1951 pub async fn try_load_entries_mut<'a, Q>(
1952 &mut self,
1953 indices: impl IntoIterator<Item = &'a Q>,
1954 ) -> Result<Vec<WriteGuardedView<W>>, ViewError>
1955 where
1956 I: Borrow<Q>,
1957 Q: CustomSerialize + 'a,
1958 {
1959 let short_keys = indices
1960 .into_iter()
1961 .map(|index| index.to_custom_bytes())
1962 .collect::<Result<_, _>>()?;
1963 self.collection.try_load_entries_mut(short_keys).await
1964 }
1965
1966 /// Loads multiple entries for writing at once with their keys.
1967 /// The entries in indices have to be all distinct.
1968 /// ```rust
1969 /// # tokio_test::block_on(async {
1970 /// # use linera_views::context::MemoryContext;
1971 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
1972 /// # use linera_views::register_view::RegisterView;
1973 /// # use linera_views::views::View;
1974 /// # let context = MemoryContext::new_for_testing(());
1975 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
1976 /// ReentrantCustomCollectionView::load(context).await.unwrap();
1977 /// let indices = [23, 42];
1978 /// let subviews = view.try_load_entries_pairs_mut(indices).await.unwrap();
1979 /// let value1 = subviews[0].1.get();
1980 /// let value2 = subviews[1].1.get();
1981 /// assert_eq!(*value1, String::default());
1982 /// assert_eq!(*value2, String::default());
1983 /// # })
1984 /// ```
1985 pub async fn try_load_entries_pairs_mut<Q>(
1986 &mut self,
1987 indices: impl IntoIterator<Item = Q>,
1988 ) -> Result<Vec<(Q, WriteGuardedView<W>)>, ViewError>
1989 where
1990 I: Borrow<Q>,
1991 Q: CustomSerialize + Clone,
1992 {
1993 let indices_vec: Vec<Q> = indices.into_iter().collect();
1994 let values = self.try_load_entries_mut(indices_vec.iter()).await?;
1995 Ok(indices_vec.into_iter().zip(values).collect())
1996 }
1997
1998 /// Load multiple entries for reading at once.
1999 /// The entries in indices have to be all distinct.
2000 /// ```rust
2001 /// # tokio_test::block_on(async {
2002 /// # use linera_views::context::MemoryContext;
2003 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2004 /// # use linera_views::register_view::RegisterView;
2005 /// # use linera_views::views::View;
2006 /// # let context = MemoryContext::new_for_testing(());
2007 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2008 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2009 /// {
2010 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
2011 /// }
2012 /// let subviews = view.try_load_entries(&[23, 42]).await.unwrap();
2013 /// assert!(subviews[1].is_none());
2014 /// let value0 = subviews[0].as_ref().unwrap().get();
2015 /// assert_eq!(*value0, String::default());
2016 /// # })
2017 /// ```
2018 pub async fn try_load_entries<'a, Q>(
2019 &self,
2020 indices: impl IntoIterator<Item = &'a Q>,
2021 ) -> Result<Vec<Option<ReadGuardedView<W>>>, ViewError>
2022 where
2023 I: Borrow<Q>,
2024 Q: CustomSerialize + 'a,
2025 {
2026 let short_keys = indices
2027 .into_iter()
2028 .map(|index| index.to_custom_bytes())
2029 .collect::<Result<_, _>>()?;
2030 self.collection.try_load_entries(short_keys).await
2031 }
2032
2033 /// Loads multiple entries for reading at once with their keys.
2034 /// The entries in indices have to be all distinct.
2035 /// ```rust
2036 /// # tokio_test::block_on(async {
2037 /// # use linera_views::context::MemoryContext;
2038 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2039 /// # use linera_views::register_view::RegisterView;
2040 /// # use linera_views::views::View;
2041 /// # let context = MemoryContext::new_for_testing(());
2042 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2043 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2044 /// {
2045 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
2046 /// }
2047 /// let indices = [23, 42];
2048 /// let subviews = view.try_load_entries_pairs(indices).await.unwrap();
2049 /// assert!(subviews[1].1.is_none());
2050 /// let value0 = subviews[0].1.as_ref().unwrap().get();
2051 /// assert_eq!(*value0, String::default());
2052 /// # })
2053 /// ```
2054 pub async fn try_load_entries_pairs<Q>(
2055 &self,
2056 indices: impl IntoIterator<Item = Q>,
2057 ) -> Result<Vec<(Q, Option<ReadGuardedView<W>>)>, ViewError>
2058 where
2059 I: Borrow<Q>,
2060 Q: CustomSerialize + Clone,
2061 {
2062 let indices_vec: Vec<Q> = indices.into_iter().collect();
2063 let values = self.try_load_entries(indices_vec.iter()).await?;
2064 Ok(indices_vec.into_iter().zip(values).collect())
2065 }
2066
2067 /// Loads all entries for writing at once.
2068 /// The entries in indices have to be all distinct.
2069 /// ```rust
2070 /// # tokio_test::block_on(async {
2071 /// # use linera_views::context::MemoryContext;
2072 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2073 /// # use linera_views::register_view::RegisterView;
2074 /// # use linera_views::views::View;
2075 /// # let context = MemoryContext::new_for_testing(());
2076 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2077 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2078 /// {
2079 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
2080 /// }
2081 /// let subviews = view.try_load_all_entries_mut().await.unwrap();
2082 /// assert_eq!(subviews.len(), 1);
2083 /// # })
2084 /// ```
2085 pub async fn try_load_all_entries_mut(
2086 &mut self,
2087 ) -> Result<Vec<(I, WriteGuardedView<W>)>, ViewError> {
2088 let results = self.collection.try_load_all_entries_mut().await?;
2089 results
2090 .into_iter()
2091 .map(|(short_key, view)| {
2092 let index = I::from_custom_bytes(&short_key)?;
2093 Ok((index, view))
2094 })
2095 .collect()
2096 }
2097
2098 /// Load multiple entries for reading at once.
2099 /// The entries in indices have to be all distinct.
2100 /// ```rust
2101 /// # tokio_test::block_on(async {
2102 /// # use linera_views::context::MemoryContext;
2103 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2104 /// # use linera_views::register_view::RegisterView;
2105 /// # use linera_views::views::View;
2106 /// # let context = MemoryContext::new_for_testing(());
2107 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2108 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2109 /// {
2110 /// let _subview = view.try_load_entry_mut(&23).await.unwrap();
2111 /// }
2112 /// let subviews = view.try_load_all_entries().await.unwrap();
2113 /// assert_eq!(subviews.len(), 1);
2114 /// # })
2115 /// ```
2116 pub async fn try_load_all_entries(&self) -> Result<Vec<(I, ReadGuardedView<W>)>, ViewError> {
2117 let results = self.collection.try_load_all_entries().await?;
2118 results
2119 .into_iter()
2120 .map(|(short_key, view)| {
2121 let index = I::from_custom_bytes(&short_key)?;
2122 Ok((index, view))
2123 })
2124 .collect()
2125 }
2126}
2127
2128impl<I, W> ReentrantCustomCollectionView<W::Context, I, W>
2129where
2130 W: View,
2131 I: Sync + Send + CustomSerialize,
2132{
2133 /// Returns the list of indices in the collection. The order is determined by
2134 /// the custom serialization.
2135 /// ```rust
2136 /// # tokio_test::block_on(async {
2137 /// # use linera_views::context::MemoryContext;
2138 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2139 /// # use linera_views::register_view::RegisterView;
2140 /// # use linera_views::views::View;
2141 /// # let context = MemoryContext::new_for_testing(());
2142 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2143 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2144 /// view.try_load_entry_mut(&23).await.unwrap();
2145 /// view.try_load_entry_mut(&25).await.unwrap();
2146 /// let indices = view.indices().await.unwrap();
2147 /// assert_eq!(indices, vec![23, 25]);
2148 /// # })
2149 /// ```
2150 pub async fn indices(&self) -> Result<Vec<I>, ViewError> {
2151 let mut indices = Vec::new();
2152 self.for_each_index(|index| {
2153 indices.push(index);
2154 Ok(())
2155 })
2156 .await?;
2157 Ok(indices)
2158 }
2159
2160 /// Returns the number of entries in the collection.
2161 /// ```rust
2162 /// # tokio_test::block_on(async {
2163 /// # use linera_views::context::MemoryContext;
2164 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2165 /// # use linera_views::register_view::RegisterView;
2166 /// # use linera_views::views::View;
2167 /// # let context = MemoryContext::new_for_testing(());
2168 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2169 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2170 /// view.try_load_entry_mut(&23).await.unwrap();
2171 /// view.try_load_entry_mut(&25).await.unwrap();
2172 /// assert_eq!(view.iterative_count().await.unwrap(), 2);
2173 /// # })
2174 /// ```
2175 pub async fn iterative_count(&self) -> Result<usize, ViewError> {
2176 self.collection.iterative_count().await
2177 }
2178
2179 /// Applies a function f on each index. Indices are visited in an order
2180 /// determined by the custom serialization. If the function f returns false
2181 /// then the loop ends prematurely.
2182 /// ```rust
2183 /// # tokio_test::block_on(async {
2184 /// # use linera_views::context::MemoryContext;
2185 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2186 /// # use linera_views::register_view::RegisterView;
2187 /// # use linera_views::views::View;
2188 /// # let context = MemoryContext::new_for_testing(());
2189 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2190 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2191 /// view.try_load_entry_mut(&28).await.unwrap();
2192 /// view.try_load_entry_mut(&24).await.unwrap();
2193 /// view.try_load_entry_mut(&23).await.unwrap();
2194 /// let mut part_indices = Vec::new();
2195 /// view.for_each_index_while(|index| {
2196 /// part_indices.push(index);
2197 /// Ok(part_indices.len() < 2)
2198 /// })
2199 /// .await
2200 /// .unwrap();
2201 /// assert_eq!(part_indices, vec![23, 24]);
2202 /// # })
2203 /// ```
2204 pub async fn for_each_index_while<F>(&self, mut f: F) -> Result<(), ViewError>
2205 where
2206 F: FnMut(I) -> Result<bool, ViewError> + Send,
2207 {
2208 self.collection
2209 .for_each_key_while(|key| {
2210 let index = I::from_custom_bytes(key)?;
2211 f(index)
2212 })
2213 .await?;
2214 Ok(())
2215 }
2216
2217 /// Applies a function f on each index. Indices are visited in an order
2218 /// determined by the custom serialization.
2219 /// ```rust
2220 /// # tokio_test::block_on(async {
2221 /// # use linera_views::context::MemoryContext;
2222 /// # use linera_views::reentrant_collection_view::ReentrantCustomCollectionView;
2223 /// # use linera_views::register_view::RegisterView;
2224 /// # use linera_views::views::View;
2225 /// # let context = MemoryContext::new_for_testing(());
2226 /// let mut view: ReentrantCustomCollectionView<_, u128, RegisterView<_, String>> =
2227 /// ReentrantCustomCollectionView::load(context).await.unwrap();
2228 /// view.try_load_entry_mut(&28).await.unwrap();
2229 /// view.try_load_entry_mut(&24).await.unwrap();
2230 /// view.try_load_entry_mut(&23).await.unwrap();
2231 /// let mut indices = Vec::new();
2232 /// view.for_each_index(|index| {
2233 /// indices.push(index);
2234 /// Ok(())
2235 /// })
2236 /// .await
2237 /// .unwrap();
2238 /// assert_eq!(indices, vec![23, 24, 28]);
2239 /// # })
2240 /// ```
2241 pub async fn for_each_index<F>(&self, mut f: F) -> Result<(), ViewError>
2242 where
2243 F: FnMut(I) -> Result<(), ViewError> + Send,
2244 {
2245 self.collection
2246 .for_each_key(|key| {
2247 let index = I::from_custom_bytes(key)?;
2248 f(index)
2249 })
2250 .await?;
2251 Ok(())
2252 }
2253}
2254
2255impl<I, W> HashableView for ReentrantCustomCollectionView<W::Context, I, W>
2256where
2257 W: HashableView,
2258 I: Send + Sync + CustomSerialize,
2259{
2260 type Hasher = sha3::Sha3_256;
2261
2262 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
2263 self.collection.hash_mut().await
2264 }
2265
2266 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
2267 self.collection.hash().await
2268 }
2269}
2270
2271/// Type wrapping `ReentrantByteCollectionView` while memoizing the hash.
2272pub type HashedReentrantByteCollectionView<C, W> =
2273 WrappedHashableContainerView<C, ReentrantByteCollectionView<C, W>, HasherOutput>;
2274
2275/// Type wrapping `ReentrantCollectionView` while memoizing the hash.
2276pub type HashedReentrantCollectionView<C, I, W> =
2277 WrappedHashableContainerView<C, ReentrantCollectionView<C, I, W>, HasherOutput>;
2278
2279/// Type wrapping `ReentrantCustomCollectionView` while memoizing the hash.
2280pub type HashedReentrantCustomCollectionView<C, I, W> =
2281 WrappedHashableContainerView<C, ReentrantCustomCollectionView<C, I, W>, HasherOutput>;
2282
2283/// Wrapper around `ReentrantByteCollectionView` to compute hashes based on the history of changes.
2284pub type HistoricallyHashedReentrantByteCollectionView<C, W> =
2285 HistoricallyHashableView<C, ReentrantByteCollectionView<C, W>>;
2286
2287/// Wrapper around `ReentrantCollectionView` to compute hashes based on the history of changes.
2288pub type HistoricallyHashedReentrantCollectionView<C, I, W> =
2289 HistoricallyHashableView<C, ReentrantCollectionView<C, I, W>>;
2290
2291/// Wrapper around `ReentrantCustomCollectionView` to compute hashes based on the history of changes.
2292pub type HistoricallyHashedReentrantCustomCollectionView<C, I, W> =
2293 HistoricallyHashableView<C, ReentrantCustomCollectionView<C, I, W>>;
2294
2295#[cfg(with_graphql)]
2296mod graphql {
2297 use std::borrow::Cow;
2298
2299 use super::{ReadGuardedView, ReentrantCollectionView};
2300 use crate::{
2301 graphql::{hash_name, mangle, missing_key_error, Entry, MapInput},
2302 views::View,
2303 };
2304
2305 impl<T: async_graphql::OutputType> async_graphql::OutputType for ReadGuardedView<T> {
2306 fn type_name() -> Cow<'static, str> {
2307 T::type_name()
2308 }
2309
2310 fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
2311 T::create_type_info(registry)
2312 }
2313
2314 async fn resolve(
2315 &self,
2316 ctx: &async_graphql::ContextSelectionSet<'_>,
2317 field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
2318 ) -> async_graphql::ServerResult<async_graphql::Value> {
2319 (**self).resolve(ctx, field).await
2320 }
2321 }
2322
2323 impl<C: Send + Sync, K: async_graphql::OutputType, V: async_graphql::OutputType>
2324 async_graphql::TypeName for ReentrantCollectionView<C, K, V>
2325 {
2326 fn type_name() -> Cow<'static, str> {
2327 format!(
2328 "ReentrantCollectionView_{}_{}_{:08x}",
2329 mangle(K::type_name()),
2330 mangle(V::type_name()),
2331 hash_name::<(K, V)>(),
2332 )
2333 .into()
2334 }
2335 }
2336
2337 #[async_graphql::Object(cache_control(no_cache), name_type)]
2338 impl<K, V> ReentrantCollectionView<V::Context, K, V>
2339 where
2340 K: async_graphql::InputType
2341 + async_graphql::OutputType
2342 + serde::ser::Serialize
2343 + serde::de::DeserializeOwned
2344 + std::fmt::Debug,
2345 V: View + async_graphql::OutputType,
2346 {
2347 async fn keys(&self) -> Result<Vec<K>, async_graphql::Error> {
2348 Ok(self.indices().await?)
2349 }
2350
2351 #[graphql(derived(name = "count"))]
2352 async fn count_(&self) -> Result<u32, async_graphql::Error> {
2353 Ok(self.iterative_count().await? as u32)
2354 }
2355
2356 async fn entry(
2357 &self,
2358 key: K,
2359 ) -> Result<Entry<K, ReadGuardedView<V>>, async_graphql::Error> {
2360 let value = self
2361 .try_load_entry(&key)
2362 .await?
2363 .ok_or_else(|| missing_key_error(&key))?;
2364 Ok(Entry { value, key })
2365 }
2366
2367 async fn entries(
2368 &self,
2369 input: Option<MapInput<K>>,
2370 ) -> Result<Vec<Entry<K, ReadGuardedView<V>>>, async_graphql::Error> {
2371 let keys = if let Some(keys) = input
2372 .and_then(|input| input.filters)
2373 .and_then(|filters| filters.keys)
2374 {
2375 keys
2376 } else {
2377 self.indices().await?
2378 };
2379
2380 let values = self.try_load_entries(&keys).await?;
2381 Ok(values
2382 .into_iter()
2383 .zip(keys)
2384 .filter_map(|(value, key)| value.map(|value| Entry { value, key }))
2385 .collect())
2386 }
2387 }
2388
2389 use crate::reentrant_collection_view::ReentrantCustomCollectionView;
2390 impl<C: Send + Sync, K: async_graphql::OutputType, V: async_graphql::OutputType>
2391 async_graphql::TypeName for ReentrantCustomCollectionView<C, K, V>
2392 {
2393 fn type_name() -> Cow<'static, str> {
2394 format!(
2395 "ReentrantCustomCollectionView_{}_{}_{:08x}",
2396 mangle(K::type_name()),
2397 mangle(V::type_name()),
2398 hash_name::<(K, V)>(),
2399 )
2400 .into()
2401 }
2402 }
2403
2404 #[async_graphql::Object(cache_control(no_cache), name_type)]
2405 impl<K, V> ReentrantCustomCollectionView<V::Context, K, V>
2406 where
2407 K: async_graphql::InputType
2408 + async_graphql::OutputType
2409 + crate::common::CustomSerialize
2410 + std::fmt::Debug,
2411 V: View + async_graphql::OutputType,
2412 {
2413 async fn keys(&self) -> Result<Vec<K>, async_graphql::Error> {
2414 Ok(self.indices().await?)
2415 }
2416
2417 async fn entry(
2418 &self,
2419 key: K,
2420 ) -> Result<Entry<K, ReadGuardedView<V>>, async_graphql::Error> {
2421 let value = self
2422 .try_load_entry(&key)
2423 .await?
2424 .ok_or_else(|| missing_key_error(&key))?;
2425 Ok(Entry { value, key })
2426 }
2427
2428 async fn entries(
2429 &self,
2430 input: Option<MapInput<K>>,
2431 ) -> Result<Vec<Entry<K, ReadGuardedView<V>>>, async_graphql::Error> {
2432 let keys = if let Some(keys) = input
2433 .and_then(|input| input.filters)
2434 .and_then(|filters| filters.keys)
2435 {
2436 keys
2437 } else {
2438 self.indices().await?
2439 };
2440
2441 let values = self.try_load_entries(&keys).await?;
2442 Ok(values
2443 .into_iter()
2444 .zip(keys)
2445 .filter_map(|(value, key)| value.map(|value| Entry { value, key }))
2446 .collect())
2447 }
2448 }
2449}