linera_views/
context.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use serde::{de::DeserializeOwned, Serialize};
5
6use crate::{
7    batch::DeletePrefixExpander,
8    memory::MemoryStore,
9    store::{KeyValueStoreError, ReadableKeyValueStore, WithError, WritableKeyValueStore},
10    views::MIN_VIEW_TAG,
11};
12
13/// A wrapper over `Vec<u8>` with functions for using it as a key prefix.
14#[derive(Default, Debug, Clone, derive_more::From)]
15pub struct BaseKey {
16    /// The byte value of the key prefix.
17    #[from]
18    pub bytes: Vec<u8>,
19}
20
21impl BaseKey {
22    /// Concatenates the base key and tag.
23    pub fn base_tag(&self, tag: u8) -> Vec<u8> {
24        assert!(tag >= MIN_VIEW_TAG, "tag should be at least MIN_VIEW_TAG");
25        let mut key = Vec::with_capacity(self.bytes.len() + 1);
26        key.extend_from_slice(&self.bytes);
27        key.push(tag);
28        key
29    }
30
31    /// Concatenates the base key, tag and index.
32    pub fn base_tag_index(&self, tag: u8, index: &[u8]) -> Vec<u8> {
33        assert!(tag >= MIN_VIEW_TAG, "tag should be at least MIN_VIEW_TAG");
34        let mut key = Vec::with_capacity(self.bytes.len() + 1 + index.len());
35        key.extend_from_slice(&self.bytes);
36        key.push(tag);
37        key.extend_from_slice(index);
38        key
39    }
40
41    /// Concatenates the base key and index.
42    pub fn base_index(&self, index: &[u8]) -> Vec<u8> {
43        let mut key = Vec::with_capacity(self.bytes.len() + index.len());
44        key.extend_from_slice(&self.bytes);
45        key.extend_from_slice(index);
46        key
47    }
48
49    /// Obtains the `Vec<u8>` key from the key by serialization and using the base key.
50    pub fn derive_key<I: Serialize>(&self, index: &I) -> Result<Vec<u8>, bcs::Error> {
51        let mut key = self.bytes.clone();
52        bcs::serialize_into(&mut key, index)?;
53        assert!(
54            key.len() > self.bytes.len(),
55            "Empty indices are not allowed"
56        );
57        Ok(key)
58    }
59
60    /// Obtains the `Vec<u8>` key from the key by serialization and using the `base_key`.
61    pub fn derive_tag_key<I: Serialize>(&self, tag: u8, index: &I) -> Result<Vec<u8>, bcs::Error> {
62        assert!(tag >= MIN_VIEW_TAG, "tag should be at least MIN_VIEW_TAG");
63        let mut key = self.base_tag(tag);
64        bcs::serialize_into(&mut key, index)?;
65        Ok(key)
66    }
67
68    /// Returns this key with a number of final bytes trimmed.
69    fn trimmed_key(&self, n: usize) -> Result<Vec<u8>, bcs::Error> {
70        if self.bytes.len() < n {
71            return Err(bcs::Error::Custom(format!(
72                "attempted to trim {} bytes from key of length {}",
73                n,
74                self.bytes.len()
75            )));
76        }
77        Ok(self.bytes[0..self.bytes.len() - n].to_vec())
78    }
79
80    /// Obtains the short `Vec<u8>` key from the key by serialization.
81    pub fn derive_short_key<I: Serialize + ?Sized>(index: &I) -> Result<Vec<u8>, bcs::Error> {
82        bcs::to_bytes(index)
83    }
84
85    /// Deserialize `bytes` into type `Item`.
86    pub fn deserialize_value<Item: DeserializeOwned>(bytes: &[u8]) -> Result<Item, bcs::Error> {
87        bcs::from_bytes(bytes)
88    }
89}
90
91/// The context in which a view is operated. Typically, this includes the client to
92/// connect to the database and the address of the current entry.
93#[cfg_attr(not(web), trait_variant::make(Send + Sync))]
94pub trait Context: Clone
95where
96    crate::ViewError: From<Self::Error>,
97{
98    /// The type of the key-value store used by this context.
99    type Store: ReadableKeyValueStore + WritableKeyValueStore + WithError<Error = Self::Error>;
100
101    /// User-provided data to be carried along.
102    type Extra: Clone + linera_base::util::traits::AutoTraits;
103
104    /// The type of errors that may be returned by operations on the `Store`, a
105    /// convenience alias for `<Self::Store as WithError>::Error`.
106    type Error: KeyValueStoreError;
107
108    /// Getter for the store.
109    fn store(&self) -> &Self::Store;
110
111    /// Getter for the user-provided data.
112    fn extra(&self) -> &Self::Extra;
113
114    /// Getter for the address of the base key.
115    fn base_key(&self) -> &BaseKey;
116
117    /// Mutable getter for the address of the base key.
118    fn base_key_mut(&mut self) -> &mut BaseKey;
119
120    /// Obtains a similar [`Context`] implementation with a different base key.
121    fn clone_with_base_key(&self, base_key: Vec<u8>) -> Self {
122        let mut context = self.clone();
123        context.base_key_mut().bytes = base_key;
124        context
125    }
126
127    /// Obtains a similar [`Context`] implementation with the last `n` bytes of the base
128    /// key trimmed.
129    fn clone_with_trimmed_key(&self, n: usize) -> Self {
130        let mut context = self.clone();
131        let key = context.base_key().trimmed_key(n).unwrap();
132        context.base_key_mut().bytes = key;
133        context
134    }
135}
136
137/// A context which can't be used to read or write data, only used for caching views.
138#[derive(Debug, Default, Clone)]
139pub struct InactiveContext(pub BaseKey);
140
141impl Context for InactiveContext {
142    type Store = crate::store::inactive_store::InactiveStore;
143    type Extra = ();
144
145    type Error = crate::store::inactive_store::InactiveStoreError;
146
147    fn store(&self) -> &Self::Store {
148        &crate::store::inactive_store::InactiveStore
149    }
150
151    fn extra(&self) -> &Self::Extra {
152        &()
153    }
154
155    fn base_key(&self) -> &BaseKey {
156        &self.0
157    }
158
159    fn base_key_mut(&mut self) -> &mut BaseKey {
160        &mut self.0
161    }
162}
163
164/// Implementation of the [`Context`] trait on top of a DB client implementing
165/// [`crate::store::KeyValueStore`].
166#[derive(Debug, Default, Clone)]
167pub struct ViewContext<E, S> {
168    /// The DB client that is shared between views.
169    store: S,
170    /// The base key for the context.
171    base_key: BaseKey,
172    /// User-defined data attached to the view.
173    extra: E,
174}
175
176impl<E, S> ViewContext<E, S>
177where
178    S: ReadableKeyValueStore + WritableKeyValueStore,
179{
180    /// Creates a context suitable for a root view, using the given store. If the
181    /// journal's store is non-empty, it will be cleared first, before the context is
182    /// returned.
183    pub async fn create_root_context(store: S, extra: E) -> Result<Self, S::Error> {
184        store.clear_journal().await?;
185        Ok(Self::new_unchecked(store, Vec::new(), extra))
186    }
187}
188
189impl<E, S> ViewContext<E, S> {
190    /// Creates a context for the given base key, store, and an extra argument. NOTE: this
191    /// constructor doesn't check the journal of the store. In doubt, use
192    /// [`ViewContext::create_root_context`] instead.
193    pub fn new_unchecked(store: S, base_key: Vec<u8>, extra: E) -> Self {
194        Self {
195            store,
196            base_key: BaseKey { bytes: base_key },
197            extra,
198        }
199    }
200}
201
202impl<E, S> Context for ViewContext<E, S>
203where
204    E: Clone + linera_base::util::traits::AutoTraits,
205    S: ReadableKeyValueStore + WritableKeyValueStore + Clone,
206    S::Error: From<bcs::Error> + Send + Sync + std::error::Error + 'static,
207{
208    type Extra = E;
209    type Store = S;
210
211    type Error = S::Error;
212
213    fn store(&self) -> &Self::Store {
214        &self.store
215    }
216
217    fn extra(&self) -> &E {
218        &self.extra
219    }
220
221    fn base_key(&self) -> &BaseKey {
222        &self.base_key
223    }
224
225    fn base_key_mut(&mut self) -> &mut BaseKey {
226        &mut self.base_key
227    }
228}
229
230/// An implementation of [`crate::context::Context`] that stores all values in memory.
231pub type MemoryContext<E> = ViewContext<E, MemoryStore>;
232
233impl<E> MemoryContext<E> {
234    /// Creates a [`Context`] instance in memory for testing.
235    #[cfg(with_testing)]
236    pub fn new_for_testing(extra: E) -> Self {
237        Self {
238            store: MemoryStore::new_for_testing(),
239            base_key: BaseKey::default(),
240            extra,
241        }
242    }
243}
244
245impl DeletePrefixExpander for MemoryContext<()> {
246    type Error = crate::memory::MemoryStoreError;
247
248    async fn expand_delete_prefix(&self, key_prefix: &[u8]) -> Result<Vec<Vec<u8>>, Self::Error> {
249        self.store().find_keys_by_prefix(key_prefix).await
250    }
251}