Skip to main content

linera_views/
context.rs

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