1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#![no_std]

mod impls;

extern crate alloc;

use alloc::borrow::Cow;

/// Merkle root alias type
pub type MerkleRoot = [u8; 32];

/// Mappable type with `Key` and `Value`.
pub trait Mappable {
    /// The type of the value's key.
    type Key;
    /// The value type is used while setting the value to the storage. In most cases, it is the same
    /// as `Self::GetValue`, but it is without restriction and can be used for performance
    /// optimizations.
    ///
    /// # Example
    ///
    /// ```rust
    /// use core::marker::PhantomData;
    /// use fuel_storage::Mappable;
    /// pub struct Contract<'a>(PhantomData<&'a ()>);
    ///
    /// impl<'a> Mappable for Contract<'a> {
    ///     type Key = &'a [u8; 32];
    ///     /// It is optimized to use slice instead of vector.
    ///     type SetValue = [u8];
    ///     type GetValue = Vec<u8>;
    /// }
    /// ```
    type SetValue: ?Sized;
    /// The value type is used while getting the value from the storage.
    type GetValue: Clone;
}

/// Base read storage trait for Fuel infrastructure.
///
/// Generic should implement [`Mappable`] trait with all storage type information.
pub trait StorageInspect<Type: Mappable> {
    type Error;

    /// Retrieve `Cow<Value>` such as `Key->Value`.
    fn get(&self, key: &Type::Key) -> Result<Option<Cow<Type::GetValue>>, Self::Error>;

    /// Return `true` if there is a `Key` mapping to a value in the storage.
    fn contains_key(&self, key: &Type::Key) -> Result<bool, Self::Error>;
}

/// Base storage trait for Fuel infrastructure.
///
/// Generic should implement [`Mappable`] trait with all storage type information.
pub trait StorageMutate<Type: Mappable>: StorageInspect<Type> {
    /// Append `Key->Value` mapping to the storage.
    ///
    /// If `Key` was already mappped to a value, return the replaced value as `Ok(Some(Value))`. Return
    /// `Ok(None)` otherwise.
    fn insert(
        &mut self,
        key: &Type::Key,
        value: &Type::SetValue,
    ) -> Result<Option<Type::GetValue>, Self::Error>;

    /// Remove `Key->Value` mapping from the storage.
    ///
    /// Return `Ok(Some(Value))` if the value was present. If the key wasn't found, return
    /// `Ok(None)`.
    fn remove(&mut self, key: &Type::Key) -> Result<Option<Type::GetValue>, Self::Error>;
}

/// Returns the merkle root for the `StorageType` per merkle `Key`. The type should implement the
/// `StorageMutate` for the `StorageType`. Per one storage, it is possible to have several merkle trees
/// under different `Key`.
pub trait MerkleRootStorage<Key, StorageType>: StorageMutate<StorageType>
where
    StorageType: Mappable,
{
    /// Return the merkle root of the stored `Type` in the storage.
    ///
    /// The cryptographic primitive is an arbitrary choice of the implementor and this trait won't
    /// impose any restrictions to that.
    fn root(&mut self, key: &Key) -> Result<MerkleRoot, Self::Error>;
}

/// The wrapper around the storage that supports only methods from `StorageInspect`.
pub struct StorageRef<'a, T: 'a + ?Sized, Type: Mappable>(&'a T, core::marker::PhantomData<Type>);

/// Helper trait for `StorageInspect` to provide user-friendly API to retrieve storage as reference.
///
/// # Example
///
/// ```rust
/// use fuel_storage::{Mappable, StorageInspect, StorageAsRef};
///
/// pub struct Contracts;
///
/// impl Mappable for Contracts {
///     type Key = [u8; 32];
///     type SetValue = [u8];
///     type GetValue = Vec<u8>;
/// }
///
/// pub struct Balances;
///
/// impl Mappable for Balances {
///     type Key = u128;
///     type SetValue = u64;
///     type GetValue = u64;
/// }
///
/// pub trait Logic: StorageInspect<Contracts> + StorageInspect<Balances> {
///     fn run(&self) {
///         // You can specify which storage do you want to call with `storage::<Type>()`
///         let _ = self.storage::<Contracts>().get(&[0; 32]);
///         let _ = self.storage::<Balances>().get(&123);
///     }
/// }
/// ```
pub trait StorageAsRef {
    #[inline(always)]
    fn storage<Type>(&self) -> StorageRef<Self, Type>
    where
        Type: Mappable,
    {
        StorageRef(self, Default::default())
    }
}

impl<'a, T> StorageAsRef for T {}

/// The wrapper around the storage that supports methods from `StorageInspect` and `StorageMutate`.
pub struct StorageMut<'a, T: 'a + ?Sized, Type: Mappable>(
    &'a mut T,
    core::marker::PhantomData<Type>,
);

/// Helper trait for `StorageMutate` to provide user-friendly API to retrieve storage as mutable
/// reference.
///
/// # Example
///
/// ```rust
/// use fuel_storage::{Mappable, StorageMutate, StorageInspect, StorageAsMut};
///
/// pub struct Contracts;
///
/// impl Mappable for Contracts {
///     type Key = [u8; 32];
///     type SetValue = [u8];
///     type GetValue = Vec<u8>;
/// }
///
/// pub struct Balances;
///
/// impl Mappable for Balances {
///     type Key = u128;
///     type SetValue = u64;
///     type GetValue = u64;
/// }
///
/// pub trait Logic: StorageInspect<Contracts> + StorageMutate<Balances> {
///     fn run(&mut self) {
///         let mut self_ = self;
///         // You can specify which storage do you want to call with `storage::<Type>()`
///         let _ = self_.storage::<Balances>().insert(&123, &321);
///         let _ = self_.storage::<Contracts>().get(&[0; 32]);
///     }
/// }
/// ```
pub trait StorageAsMut {
    #[inline(always)]
    fn storage<Type>(&mut self) -> StorageMut<Self, Type>
    where
        Type: Mappable,
    {
        StorageMut(self, Default::default())
    }
}

impl<'a, T> StorageAsMut for T {}