Skip to main content

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}