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