//! The module contains the [`StructuredStorage`] wrapper around the key-value storage //! that implements the storage traits for the tables with blueprint. use crate::{ blueprint::{ BlueprintInspect, BlueprintMutate, SupportsBatching, SupportsMerkle, }, codec::{ raw::Raw, Encode, Encoder, }, iter::{ BoxedIter, IterDirection, IterableStore, }, kv_store::{ BatchOperations, KVItem, KeyValueInspect, KeyValueMutate, StorageColumn, Value, WriteOperation, }, transactional::{ Changes, Modifiable, }, Error as StorageError, Mappable, MerkleRoot, MerkleRootStorage, Result as StorageResult, StorageBatchMutate, StorageInspect, StorageMutate, StorageRead, StorageSize, StorageWrite, }; use std::{ borrow::Cow, ops::Deref, }; pub mod balances; pub mod blocks; pub mod coins; pub mod contracts; pub mod merkle_data; pub mod messages; pub mod sealed_block; pub mod state; pub mod transactions; pub mod upgrades; /// The table can implement this trait to indicate that it has a blueprint. /// It inherits the default implementation of the storage traits through the [`StructuredStorage`] /// for the table. pub trait TableWithBlueprint: Mappable + Sized { /// The type of the blueprint used by the table. type Blueprint; /// The column type used by the table. type Column: StorageColumn; /// The column occupied by the table. fn column() -> Self::Column; } /// The wrapper around the key-value storage that implements the storage traits for the tables /// with blueprint. #[derive(Default, Debug, Clone)] pub struct StructuredStorage { pub(crate) inner: S, } impl StructuredStorage { /// Creates a new instance of the structured storage. pub fn new(storage: S) -> Self { Self { inner: storage } } } impl AsRef for StructuredStorage { fn as_ref(&self) -> &S { &self.inner } } impl AsMut for StructuredStorage { fn as_mut(&mut self) -> &mut S { &mut self.inner } } impl KeyValueInspect for StructuredStorage where S: KeyValueInspect, { type Column = S::Column; fn exists(&self, key: &[u8], column: Self::Column) -> StorageResult { self.inner.exists(key, column) } fn size_of_value( &self, key: &[u8], column: Self::Column, ) -> StorageResult> { self.inner.size_of_value(key, column) } fn get(&self, key: &[u8], column: Self::Column) -> StorageResult> { self.inner.get(key, column) } fn read( &self, key: &[u8], column: Self::Column, buf: &mut [u8], ) -> StorageResult> { self.inner.read(key, column, buf) } } impl KeyValueMutate for StructuredStorage where S: KeyValueMutate, { fn put( &mut self, key: &[u8], column: Self::Column, value: Value, ) -> StorageResult<()> { self.inner.put(key, column, value) } fn replace( &mut self, key: &[u8], column: Self::Column, value: Value, ) -> StorageResult> { self.inner.replace(key, column, value) } fn write( &mut self, key: &[u8], column: Self::Column, buf: &[u8], ) -> StorageResult { self.inner.write(key, column, buf) } fn take(&mut self, key: &[u8], column: Self::Column) -> StorageResult> { self.inner.take(key, column) } fn delete(&mut self, key: &[u8], column: Self::Column) -> StorageResult<()> { self.inner.delete(key, column) } } impl BatchOperations for StructuredStorage where S: BatchOperations, { fn batch_write(&mut self, column: Self::Column, entries: I) -> StorageResult<()> where I: Iterator, WriteOperation)>, { self.inner.batch_write(column, entries) } } impl IterableStore for StructuredStorage where S: IterableStore, { fn iter_store( &self, column: Self::Column, prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, ) -> BoxedIter { self.inner.iter_store(column, prefix, start, direction) } } impl Modifiable for StructuredStorage where S: Modifiable, { fn commit_changes(&mut self, changes: Changes) -> StorageResult<()> { self.inner.commit_changes(changes) } } impl StorageInspect for StructuredStorage where S: KeyValueInspect, M: TableWithBlueprint, M::Blueprint: BlueprintInspect>, { type Error = StorageError; fn get(&self, key: &M::Key) -> Result>, Self::Error> { ::Blueprint::get(self, key, M::column()) .map(|value| value.map(Cow::Owned)) } fn contains_key(&self, key: &M::Key) -> Result { ::Blueprint::exists(self, key, M::column()) } } impl StorageMutate for StructuredStorage where S: KeyValueMutate, M: TableWithBlueprint, M::Blueprint: BlueprintMutate>, { fn insert( &mut self, key: &M::Key, value: &M::Value, ) -> Result, Self::Error> { ::Blueprint::replace(self, key, M::column(), value) } fn remove(&mut self, key: &M::Key) -> Result, Self::Error> { ::Blueprint::take(self, key, M::column()) } } impl StorageSize for StructuredStorage where S: KeyValueInspect, M: TableWithBlueprint, M::Blueprint: BlueprintInspect>, { fn size_of_value(&self, key: &M::Key) -> Result, Self::Error> { ::Blueprint::size_of_value(self, key, M::column()) } } impl StorageBatchMutate for StructuredStorage where S: BatchOperations, M: TableWithBlueprint, M::Blueprint: SupportsBatching>, { fn init_storage<'a, Iter>(&mut self, set: Iter) -> Result<(), Self::Error> where Iter: 'a + Iterator, M::Key: 'a, M::Value: 'a, { ::Blueprint::init(self, M::column(), set) } fn insert_batch<'a, Iter>(&mut self, set: Iter) -> Result<(), Self::Error> where Iter: 'a + Iterator, M::Key: 'a, M::Value: 'a, { ::Blueprint::insert(self, M::column(), set) } fn remove_batch<'a, Iter>(&mut self, set: Iter) -> Result<(), Self::Error> where Iter: 'a + Iterator, M::Key: 'a, { ::Blueprint::remove(self, M::column(), set) } } impl MerkleRootStorage for StructuredStorage where S: KeyValueInspect, M: TableWithBlueprint, M::Blueprint: SupportsMerkle>, { fn root(&self, key: &Key) -> Result { ::Blueprint::root(self, key) } } impl StorageRead for StructuredStorage where S: KeyValueInspect, M: Mappable + TableWithBlueprint, M::Blueprint: BlueprintInspect, ValueCodec = Raw>, { fn read( &self, key: &::Key, buf: &mut [u8], ) -> Result, Self::Error> { let key_encoder = >>::KeyCodec::encode( key, ); let key_bytes = key_encoder.as_bytes(); self.inner .read(key_bytes.as_ref(), ::column(), buf) } fn read_alloc( &self, key: &::Key, ) -> Result>, Self::Error> { let key_encoder = >>::KeyCodec::encode( key, ); let key_bytes = key_encoder.as_bytes(); self.inner .get(key_bytes.as_ref(), ::column()) // TODO: Return `Value` instead of cloned `Vec`. .map(|value| value.map(|value| value.deref().clone())) } } impl StorageWrite for StructuredStorage where S: KeyValueMutate, M: TableWithBlueprint, M::Blueprint: BlueprintMutate, ValueCodec = Raw>, // TODO: Add new methods to the `Blueprint` that allows work with bytes directly // without deserialization into `OwnedValue`. M::OwnedValue: Into>, { fn write(&mut self, key: &M::Key, buf: &[u8]) -> Result { ::Blueprint::put(self, key, M::column(), buf) .map(|_| buf.len()) } fn replace( &mut self, key: &M::Key, buf: &[u8], ) -> Result<(usize, Option>), Self::Error> { let bytes_written = buf.len(); let prev = ::Blueprint::replace(self, key, M::column(), buf)? .map(|prev| prev.into()); let result = (bytes_written, prev); Ok(result) } fn take(&mut self, key: &M::Key) -> Result>, Self::Error> { let take = ::Blueprint::take(self, key, M::column())? .map(|value| value.into()); Ok(take) } } /// The module that provides helper macros for testing the structured storage. #[cfg(feature = "test-helpers")] pub mod test { use crate as fuel_core_storage; use crate::kv_store::{ KeyValueInspect, StorageColumn, }; use fuel_core_storage::{ kv_store::Value, Result as StorageResult, }; use std::collections::HashMap; type Storage = HashMap<(u32, Vec), Value>; /// The in-memory storage for testing purposes. #[derive(Clone, Debug, PartialEq, Eq)] pub struct InMemoryStorage { pub(crate) storage: Storage, _marker: core::marker::PhantomData, } impl InMemoryStorage { /// Returns the inner storage. pub fn storage(&self) -> &Storage { &self.storage } } impl Default for InMemoryStorage { fn default() -> Self { Self { storage: Default::default(), _marker: Default::default(), } } } impl KeyValueInspect for InMemoryStorage where Column: StorageColumn, { type Column = Column; fn get(&self, key: &[u8], column: Self::Column) -> StorageResult> { let value = self.storage.get(&(column.id(), key.to_vec())).cloned(); Ok(value) } } }