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