Skip to main content

fuel_storage/
lib.rs

1#![no_std]
2#![deny(
3    clippy::arithmetic_side_effects,
4    clippy::cast_sign_loss,
5    clippy::cast_possible_truncation,
6    clippy::cast_possible_wrap,
7    clippy::string_slice
8)]
9#![deny(unsafe_code)]
10#![deny(unused_crate_dependencies)]
11
12mod impls;
13
14extern crate alloc;
15
16use core::borrow::Borrow;
17
18use alloc::{
19    borrow::{
20        Cow,
21        ToOwned,
22    },
23    vec::Vec,
24};
25
26/// Merkle root alias type
27pub type MerkleRoot = [u8; 32];
28
29/// Mappable type with `Key` and `Value`.
30///
31/// # Example
32///
33/// ```rust
34/// use fuel_storage::Mappable;
35/// pub struct Contract;
36///
37/// impl Mappable for Contract {
38///     /// The `[u8; 32]` is a primitive type, so we can't optimize it more.
39///     type Key = Self::OwnedKey;
40///     type OwnedKey = [u8; 32];
41///     /// It is optimized to use slice instead of vector.
42///     type Value = [u8];
43///     type OwnedValue = Vec<u8>;
44/// }
45/// ```
46pub trait Mappable {
47    /// The key type is used during interaction with the storage. In most cases, it is the
48    /// same as `Self::OwnedKey`.
49    type Key: ?Sized + ToOwned;
50    /// The owned type of the `Key` retrieving from the storage.
51    type OwnedKey: From<<Self::Key as ToOwned>::Owned> + Borrow<Self::Key> + Clone;
52    /// The value type is used while setting the value to the storage. In most cases, it
53    /// is the same as `Self::OwnedValue`, but it is without restriction and can be
54    /// used for performance optimizations.
55    type Value: ?Sized + ToOwned;
56    /// The owned type of the `Value` retrieving from the storage.
57    type OwnedValue: From<<Self::Value as ToOwned>::Owned> + Borrow<Self::Value> + Clone;
58}
59
60/// Base read storage trait for Fuel infrastructure.
61///
62/// Generic should implement [`Mappable`] trait with all storage type information.
63pub trait StorageInspect<Type: Mappable> {
64    type Error;
65
66    /// Retrieve `Cow<Value>` such as `Key->Value`.
67    fn get(
68        &self,
69        key: &Type::Key,
70    ) -> Result<Option<Cow<'_, Type::OwnedValue>>, Self::Error>;
71
72    /// Return `true` if there is a `Key` mapping to a value in the storage.
73    fn contains_key(&self, key: &Type::Key) -> Result<bool, Self::Error>;
74}
75
76/// Base storage trait for Fuel infrastructure.
77///
78/// Generic should implement [`Mappable`] trait with all storage type information.
79pub trait StorageMutate<Type: Mappable>: StorageInspect<Type> {
80    /// Append `Key->Value` mapping to the storage.
81    fn insert(
82        &mut self,
83        key: &Type::Key,
84        value: &Type::Value,
85    ) -> Result<(), Self::Error> {
86        self.replace(key, value).map(|_| ())
87    }
88
89    /// Append `Key->Value` mapping to the storage.
90    ///
91    /// If `Key` was already mappped to a value, return the replaced value as
92    /// `Ok(Some(Value))`. Return `Ok(None)` otherwise.
93    fn replace(
94        &mut self,
95        key: &Type::Key,
96        value: &Type::Value,
97    ) -> Result<Option<Type::OwnedValue>, Self::Error>;
98
99    /// Remove `Key->Value` mapping from the storage.
100    fn remove(&mut self, key: &Type::Key) -> Result<(), Self::Error> {
101        self.take(key).map(|_| ())
102    }
103
104    /// Remove `Key->Value` mapping from the storage.
105    ///
106    /// Return `Ok(Some(Value))` if the value was present. If the key wasn't found, return
107    /// `Ok(None)`.
108    fn take(&mut self, key: &Type::Key) -> Result<Option<Type::OwnedValue>, Self::Error>;
109}
110
111/// Base storage trait for Fuel infrastructure.
112///
113/// Allows checking the size of the value stored at a given key.
114/// Checking the size of a value is a cheap operation and should not require
115/// copying the value into a buffer.
116pub trait StorageSize<Type: Mappable>: StorageInspect<Type> {
117    /// Return the number of bytes stored at this key.
118    fn size_of_value(&self, key: &Type::Key) -> Result<Option<usize>, Self::Error>;
119}
120
121/// Errors that can occur when reading from storage using `StorageRead` methods
122/// that write the result to a slice.
123#[derive(Debug, Clone, Copy, PartialEq, Eq)]
124#[must_use]
125pub enum StorageReadError {
126    /// The requested key was not found in storage.
127    KeyNotFound,
128    /// Attempted to read past the end of the stored value.
129    OutOfBounds,
130}
131
132/// Base storage trait for Fuel infrastructure.
133///
134/// Allows reading the raw bytes of the value stored at a given key
135/// into a provided buffer.
136///
137/// This trait should skip any deserialization and simply copy the raw bytes.
138pub trait StorageRead<Type: Mappable>: StorageInspect<Type> + StorageSize<Type> {
139    /// Read the value stored at the given key into the provided buffer if the value
140    /// exists. Errors if the buffer cannot be filled completely, or if attempting
141    /// to read past the end of the value.
142    ///
143    /// Does not perform any deserialization.
144    ///
145    /// Returns `Ok(Ok(length))` if the value does exist, where
146    /// the `length` is the total length of the value stored at the key.
147    ///
148    /// Note that inner error `Ok(Err(_))` is used to communicate errors that the
149    /// called should be able to handle, not ones caused by underlying IO.
150    fn read_exact(
151        &self,
152        key: &Type::Key,
153        offset: usize,
154        buf: &mut [u8],
155    ) -> Result<Result<usize, StorageReadError>, Self::Error>;
156
157    /// Read the value stored at the given key into the provided buffer if the value
158    /// exists. If the buffer cannot be filled completely, the remaining bytes
159    /// are filled with zeros.
160    ///
161    /// Does not perform any deserialization.
162    ///
163    /// Returns `Ok(Ok(length))` if the value does exist, where
164    /// the `length` is the total length of the value stored at the key.
165    ///
166    /// Note that inner error `Ok(Err(_))` is used to communicate errors that the
167    /// called should be able to handle, not ones caused by underlying IO.
168    fn read_zerofill(
169        &self,
170        key: &Type::Key,
171        offset: usize,
172        buf: &mut [u8],
173    ) -> Result<Result<usize, StorageReadError>, Self::Error>;
174
175    /// Same as `read` but allocates a new buffer and returns it.
176    ///
177    /// Checks the size of the value and allocates a buffer of that size.
178    fn read_alloc(&self, key: &Type::Key) -> Result<Option<Vec<u8>>, Self::Error>;
179}
180
181/// Base storage trait for Fuel infrastructure.
182///
183/// Allows writing the raw bytes of the value stored to a given key
184/// from a provided buffer.
185///
186/// This trait should skip any serialization and simply copy the raw bytes
187/// to the storage.
188pub trait StorageWrite<Type: Mappable>: StorageMutate<Type> {
189    /// Write the bytes to the given key from the provided buffer.
190    ///
191    /// Does not perform any serialization.
192    fn write_bytes(&mut self, key: &Type::Key, buf: &[u8]) -> Result<(), Self::Error>;
193
194    /// Write the bytes to the given key from the provided buffer and
195    /// return the previous bytes if it existed.
196    ///
197    /// Does not perform any serialization.
198    ///
199    /// Returns the previous value if it existed.
200    fn replace_bytes(
201        &mut self,
202        key: &Type::Key,
203        buf: &[u8],
204    ) -> Result<Option<Vec<u8>>, Self::Error>;
205
206    /// Removes a bytes from the storage and returning it without deserializing it.
207    fn take_bytes(&mut self, key: &Type::Key) -> Result<Option<Vec<u8>>, Self::Error>;
208}
209
210/// Returns the merkle root for the `StorageType` per merkle `Key`. Per one storage, it is
211/// possible to have several merkle trees under different `Key`.
212pub trait MerkleRootStorage<Key, StorageType>: StorageInspect<StorageType>
213where
214    StorageType: Mappable,
215{
216    /// Return the merkle root of the stored `Type` in the storage.
217    ///
218    /// The cryptographic primitive is an arbitrary choice of the implementor and this
219    /// trait won't impose any restrictions to that.
220    fn root(&self, key: &Key) -> Result<MerkleRoot, Self::Error>;
221}
222
223/// The wrapper around the storage that supports only methods from `StorageInspect`.
224pub struct StorageRef<'a, T: 'a + ?Sized, Type: Mappable>(
225    &'a T,
226    core::marker::PhantomData<Type>,
227);
228
229/// Helper trait for `StorageInspect` to provide user-friendly API to retrieve storage as
230/// reference.
231///
232/// # Example
233///
234/// ```rust
235/// use fuel_storage::{Mappable, StorageInspect, StorageAsRef};
236///
237/// pub struct Contracts;
238///
239/// impl Mappable for Contracts {
240///     type Key = Self::OwnedKey;
241///     type OwnedKey = [u8; 32];
242///     type Value = [u8];
243///     type OwnedValue = Vec<u8>;
244/// }
245///
246/// pub struct Balances;
247///
248/// impl Mappable for Balances {
249///     type Key = Self::OwnedKey;
250///     type OwnedKey = u128;
251///     type Value = Self::OwnedValue;
252///     type OwnedValue = u64;
253/// }
254///
255/// pub trait Logic: StorageInspect<Contracts> + StorageInspect<Balances> {
256///     fn run(&self) {
257///         // You can specify which storage do you want to call with `storage::<Type>()`
258///         let _ = self.storage::<Contracts>().get(&[0; 32]);
259///         let _ = self.storage::<Balances>().get(&123);
260///     }
261/// }
262/// ```
263pub trait StorageAsRef {
264    #[inline(always)]
265    fn storage<Type>(&self) -> StorageRef<'_, Self, Type>
266    where
267        Type: Mappable,
268    {
269        self.storage_as_ref()
270    }
271
272    #[inline(always)]
273    fn storage_as_ref<Type>(&self) -> StorageRef<'_, Self, Type>
274    where
275        Type: Mappable,
276    {
277        StorageRef(self, Default::default())
278    }
279}
280
281impl<T> StorageAsRef for T {}
282
283/// The wrapper around the storage that supports methods from `StorageInspect` and
284/// `StorageMutate`.
285pub struct StorageMut<'a, T: 'a + ?Sized, Type: Mappable>(
286    &'a mut T,
287    core::marker::PhantomData<Type>,
288);
289
290/// Helper trait for `StorageMutate` to provide user-friendly API to retrieve storage as
291/// mutable reference.
292///
293/// # Example
294///
295/// ```rust
296/// use fuel_storage::{Mappable, StorageMutate, StorageInspect, StorageAsMut};
297///
298/// pub struct Contracts;
299///
300/// impl Mappable for Contracts {
301///     type Key = Self::OwnedKey;
302///     type OwnedKey = [u8; 32];
303///     type Value = [u8];
304///     type OwnedValue = Vec<u8>;
305/// }
306///
307/// pub struct Balances;
308///
309/// impl Mappable for Balances {
310///     type Key = Self::OwnedKey;
311///     type OwnedKey = u128;
312///     type Value = Self::OwnedValue;
313///     type OwnedValue = u64;
314/// }
315///
316/// pub trait Logic: StorageInspect<Contracts> + StorageMutate<Balances> {
317///     fn run(&mut self) {
318///         let mut self_ = self;
319///         // You can specify which storage do you want to call with `storage::<Type>()`
320///         let _ = self_.storage::<Balances>().insert(&123, &321);
321///         let _ = self_.storage::<Contracts>().get(&[0; 32]);
322///     }
323/// }
324/// ```
325pub trait StorageAsMut {
326    #[inline(always)]
327    fn storage<Type>(&mut self) -> StorageMut<'_, Self, Type>
328    where
329        Type: Mappable,
330    {
331        self.storage_as_mut()
332    }
333
334    #[inline(always)]
335    fn storage_as_mut<Type>(&mut self) -> StorageMut<'_, Self, Type>
336    where
337        Type: Mappable,
338    {
339        StorageMut(self, Default::default())
340    }
341}
342
343impl<T> StorageAsMut for T {}