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