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