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_key<I: Serialize>(&self, index: &I) -> Result<Vec<u8>, bcs::Error> {
54        let mut key = self.bytes.clone();
55        bcs::serialize_into(&mut key, index)?;
56        assert!(
57            key.len() > self.bytes.len(),
58            "Empty indices are not allowed"
59        );
60        Ok(key)
61    }
62
63    /// Obtains the `Vec<u8>` key from the key by serialization and using the `base_key`.
64    pub fn derive_tag_key<I: Serialize>(&self, tag: u8, index: &I) -> Result<Vec<u8>, bcs::Error> {
65        assert!(tag >= MIN_VIEW_TAG, "tag should be at least MIN_VIEW_TAG");
66        let mut key = self.base_tag(tag);
67        bcs::serialize_into(&mut key, index)?;
68        Ok(key)
69    }
70
71    /// Obtains the short `Vec<u8>` key from the key by serialization.
72    pub fn derive_short_key<I: Serialize + ?Sized>(index: &I) -> Result<Vec<u8>, bcs::Error> {
73        bcs::to_bytes(index)
74    }
75
76    /// Deserialize `bytes` into type `Item`.
77    pub fn deserialize_value<Item: DeserializeOwned>(bytes: &[u8]) -> Result<Item, bcs::Error> {
78        bcs::from_bytes(bytes)
79    }
80}
81
82/// The context in which a view is operated. Typically, this includes the client to
83/// connect to the database and the address of the current entry.
84#[cfg_attr(not(web), trait_variant::make(Send + Sync))]
85pub trait Context: Clone
86where
87    crate::ViewError: From<Self::Error>,
88{
89    /// The type of the key-value store used by this context.
90    type Store: ReadableKeyValueStore + WritableKeyValueStore + WithError<Error = Self::Error>;
91
92    /// User-provided data to be carried along.
93    type Extra: Clone + linera_base::util::traits::AutoTraits;
94
95    /// The type of errors that may be returned by operations on the `Store`, a
96    /// convenience alias for `<Self::Store as WithError>::Error`.
97    type Error: KeyValueStoreError;
98
99    /// Getter for the store.
100    fn store(&self) -> &Self::Store;
101
102    /// Getter for the user-provided data.
103    fn extra(&self) -> &Self::Extra;
104
105    /// Getter for the address of the base key.
106    fn base_key(&self) -> &BaseKey;
107
108    /// Mutable getter for the address of the base key.
109    fn base_key_mut(&mut self) -> &mut BaseKey;
110
111    /// Obtains a similar [`Context`] implementation with a different base key.
112    fn clone_with_base_key(&self, base_key: Vec<u8>) -> Self {
113        let mut context = self.clone();
114        context.base_key_mut().bytes = base_key;
115        context
116    }
117}
118
119/// A context which can't be used to read or write data, only used for caching views.
120#[derive(Debug, Default, Clone)]
121pub struct InactiveContext(pub BaseKey);
122
123impl Context for InactiveContext {
124    type Store = crate::store::inactive_store::InactiveStore;
125    type Extra = ();
126
127    type Error = crate::store::inactive_store::InactiveStoreError;
128
129    fn store(&self) -> &Self::Store {
130        &crate::store::inactive_store::InactiveStore
131    }
132
133    fn extra(&self) -> &Self::Extra {
134        &()
135    }
136
137    fn base_key(&self) -> &BaseKey {
138        &self.0
139    }
140
141    fn base_key_mut(&mut self) -> &mut BaseKey {
142        &mut self.0
143    }
144}
145
146/// Implementation of the [`Context`] trait on top of a DB client implementing
147/// [`crate::store::KeyValueStore`].
148#[derive(Debug, Default, Clone)]
149pub struct ViewContext<E, S> {
150    /// The DB client that is shared between views.
151    store: S,
152    /// The base key for the context.
153    base_key: BaseKey,
154    /// User-defined data attached to the view.
155    extra: E,
156}
157
158impl<E, S> ViewContext<E, S>
159where
160    S: ReadableKeyValueStore + WritableKeyValueStore,
161{
162    /// Creates a context suitable for a root view, using the given store. If the
163    /// journal's store is non-empty, it will be cleared first, before the context is
164    /// returned.
165    pub async fn create_root_context(store: S, extra: E) -> Result<Self, S::Error> {
166        store.clear_journal().await?;
167        Ok(Self::new_unchecked(store, Vec::new(), extra))
168    }
169}
170
171impl<E, S> ViewContext<E, S> {
172    /// Creates a context for the given base key, store, and an extra argument. NOTE: this
173    /// constructor doesn't check the journal of the store. In doubt, use
174    /// [`ViewContext::create_root_context`] instead.
175    pub fn new_unchecked(store: S, base_key: Vec<u8>, extra: E) -> Self {
176        Self {
177            store,
178            base_key: BaseKey { bytes: base_key },
179            extra,
180        }
181    }
182}
183
184impl<E, S> Context for ViewContext<E, S>
185where
186    E: Clone + linera_base::util::traits::AutoTraits,
187    S: ReadableKeyValueStore + WritableKeyValueStore + Clone,
188    S::Error: From<bcs::Error> + Send + Sync + std::error::Error + 'static,
189{
190    type Extra = E;
191    type Store = S;
192
193    type Error = S::Error;
194
195    fn store(&self) -> &Self::Store {
196        &self.store
197    }
198
199    fn extra(&self) -> &E {
200        &self.extra
201    }
202
203    fn base_key(&self) -> &BaseKey {
204        &self.base_key
205    }
206
207    fn base_key_mut(&mut self) -> &mut BaseKey {
208        &mut self.base_key
209    }
210}
211
212/// An implementation of [`crate::context::Context`] that stores all values in memory.
213pub type MemoryContext<E> = ViewContext<E, MemoryStore>;
214
215impl<E> MemoryContext<E> {
216    /// Creates a [`Context`] instance in memory for testing.
217    #[cfg(with_testing)]
218    pub fn new_for_testing(extra: E) -> Self {
219        Self {
220            store: MemoryStore::new_for_testing(),
221            base_key: BaseKey::default(),
222            extra,
223        }
224    }
225}
226
227impl DeletePrefixExpander for MemoryContext<()> {
228    type Error = crate::memory::MemoryStoreError;
229
230    async fn expand_delete_prefix(&self, key_prefix: &[u8]) -> Result<Vec<Vec<u8>>, Self::Error> {
231        self.store().find_keys_by_prefix(key_prefix).await
232    }
233}