linera_views/views/
mod.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{fmt::Debug, io::Write};
5
6use linera_base::crypto::CryptoHash;
7pub use linera_views_derive::{
8    ClonableView, CryptoHashRootView, CryptoHashView, HashableView, RootView, View,
9};
10use serde::Serialize;
11
12use crate::{batch::Batch, common::HasherOutput, ViewError};
13
14#[cfg(test)]
15#[path = "unit_tests/views.rs"]
16mod tests;
17
18/// The `RegisterView` implements a register for a single value.
19pub mod register_view;
20
21/// The `LogView` implements a log list that can be pushed.
22pub mod log_view;
23
24/// The `BucketQueueView` implements a queue that can push on the back and delete on the front and group data in buckets.
25pub mod bucket_queue_view;
26
27/// The `QueueView` implements a queue that can push on the back and delete on the front.
28pub mod queue_view;
29
30/// The `MapView` implements a map with ordered keys.
31pub mod map_view;
32
33/// The `SetView` implements a set with ordered entries.
34pub mod set_view;
35
36/// The `CollectionView` implements a map structure whose keys are ordered and the values are views.
37pub mod collection_view;
38
39/// The `ReentrantCollectionView` implements a map structure whose keys are ordered and the values are views with concurrent access.
40pub mod reentrant_collection_view;
41
42/// The implementation of a key-value store view.
43pub mod key_value_store_view;
44
45/// Wrapping a view to compute a hash.
46pub mod hashable_wrapper;
47
48/// The minimum value for the view tags. Values in `0..MIN_VIEW_TAG` are used for other purposes.
49pub const MIN_VIEW_TAG: u8 = 1;
50
51/// A view gives exclusive access to read and write the data stored at an underlying
52/// address in storage.
53#[cfg_attr(not(web), trait_variant::make(Send + Sync))]
54pub trait View: Sized {
55    /// The number of keys used for the initialization
56    const NUM_INIT_KEYS: usize;
57
58    /// The type of context stored in this view
59    type Context: crate::context::Context;
60
61    /// Obtains a mutable reference to the internal context.
62    fn context(&self) -> &Self::Context;
63
64    /// Creates the keys needed for loading the view
65    fn pre_load(context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError>;
66
67    /// Loads a view from the values
68    fn post_load(context: Self::Context, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError>;
69
70    /// Loads a view
71    async fn load(context: Self::Context) -> Result<Self, ViewError>;
72
73    /// Discards all pending changes. After that `flush` should have no effect to storage.
74    fn rollback(&mut self);
75
76    /// Returns [`true`] if flushing this view would result in changes to the persistent storage.
77    async fn has_pending_changes(&self) -> bool;
78
79    /// Clears the view. That can be seen as resetting to default. If the clear is followed
80    /// by a flush then all the relevant data is removed on the storage.
81    fn clear(&mut self);
82
83    /// Persists changes to storage. This leaves the view still usable and is essentially neutral to the
84    /// program running. Crash-resistant storage implementations are expected to accumulate the desired
85    /// changes in the `batch` variable first. If the view is dropped without calling `flush`, staged
86    /// changes are simply lost.
87    /// The returned boolean indicates whether the operation removes the view or not.
88    fn flush(&mut self, batch: &mut Batch) -> Result<bool, ViewError>;
89
90    /// Builds a trivial view that is already deleted
91    fn new(context: Self::Context) -> Result<Self, ViewError> {
92        let values = vec![None; Self::NUM_INIT_KEYS];
93        let mut view = Self::post_load(context, &values)?;
94        view.clear();
95        Ok(view)
96    }
97}
98
99/// A view which can have its context replaced.
100pub trait ReplaceContext<C: crate::context::Context>: View {
101    /// The type returned after replacing the context.
102    type Target: View<Context = C>;
103
104    /// Returns a view with a replaced context.
105    async fn with_context(&mut self, ctx: impl FnOnce(&Self::Context) -> C + Clone)
106        -> Self::Target;
107}
108
109/// A view that supports hashing its values.
110#[cfg_attr(not(web), trait_variant::make(Send))]
111pub trait HashableView: View {
112    /// How to compute hashes.
113    type Hasher: Hasher;
114
115    /// Computes the hash of the values.
116    ///
117    /// Implementations do not need to include a type tag. However, the usual precautions
118    /// to enforce collision resistance must be applied (e.g. including the length of a
119    /// collection of values).
120    async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError>;
121
122    /// Computes the hash of the values.
123    ///
124    /// Implementations do not need to include a type tag. However, the usual precautions
125    /// to enforce collision resistance must be applied (e.g. including the length of a
126    /// collection of values).
127    async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError>;
128}
129
130/// The requirement for the hasher type in [`HashableView`].
131pub trait Hasher: Default + Write + Send + Sync + 'static {
132    /// The output type.
133    type Output: Debug + Clone + Eq + AsRef<[u8]> + 'static;
134
135    /// Finishes the hashing process and returns its output.
136    fn finalize(self) -> Self::Output;
137
138    /// Serializes a value with BCS and includes it in the hash.
139    fn update_with_bcs_bytes(&mut self, value: &impl Serialize) -> Result<(), ViewError> {
140        bcs::serialize_into(self, value)?;
141        Ok(())
142    }
143
144    /// Includes bytes in the hash.
145    fn update_with_bytes(&mut self, value: &[u8]) -> Result<(), ViewError> {
146        self.write_all(value)?;
147        Ok(())
148    }
149}
150
151impl Hasher for sha3::Sha3_256 {
152    type Output = HasherOutput;
153
154    fn finalize(self) -> Self::Output {
155        <sha3::Sha3_256 as sha3::Digest>::finalize(self)
156    }
157}
158
159/// A [`View`] whose staged modifications can be saved in storage.
160#[cfg_attr(not(web), trait_variant::make(Send))]
161pub trait RootView: View {
162    /// Saves the root view to the database context
163    async fn save(&mut self) -> Result<(), ViewError>;
164}
165
166/// A [`View`] that also supports crypto hash
167#[cfg_attr(not(web), trait_variant::make(Send))]
168pub trait CryptoHashView: HashableView {
169    /// Computing the hash and attributing the type to it.
170    async fn crypto_hash(&self) -> Result<CryptoHash, ViewError>;
171
172    /// Computing the hash and attributing the type to it.
173    async fn crypto_hash_mut(&mut self) -> Result<CryptoHash, ViewError>;
174}
175
176/// A [`RootView`] that also supports crypto hash
177#[cfg_attr(not(web), trait_variant::make(Send))]
178pub trait CryptoHashRootView: RootView + CryptoHashView {}
179
180/// A [`ClonableView`] supports being shared (unsafely) by cloning it.
181///
182/// Sharing is unsafe because by having two view instances for the same data, they may have invalid
183/// state if both are used for writing.
184///
185/// Sharing the view is guaranteed to not cause data races if only one of the shared view instances
186/// is used for writing at any given point in time.
187pub trait ClonableView: View {
188    /// Creates a clone of this view, sharing the underlying storage context but prone to
189    /// data races which can corrupt the view state.
190    fn clone_unchecked(&mut self) -> Result<Self, ViewError>;
191}