entry.rs 9.33 KB
Newer Older
1
// Copyright 2018-2021 Parity Technologies (UK) Ltd.
2
3
4
5
6
7
8
9
10
11
12
13
14
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

15
use crate::traits::{
16
17
18
19
20
21
    clear_packed_root,
    clear_spread_root_opt,
    pull_packed_root_opt,
    pull_spread_root_opt,
    push_packed_root_opt,
    push_spread_root_opt,
22
    ExtKeyPtr,
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    KeyPtr,
    PackedLayout,
    SpreadLayout,
};
use core::{
    cell::Cell,
    fmt,
    fmt::Debug,
};
use ink_prelude::vec::Vec;
use ink_primitives::Key;

/// The entry of a single cached value of a lazy storage data structure.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
37
pub struct StorageEntry<T> {
38
39
40
41
42
43
44
45
46
    /// The value or `None` if the value has been removed.
    value: Option<T>,
    /// This is [`EntryState::Mutated`] if the value has been mutated and is in
    /// need to be synchronized with the contract storage. If it is
    /// [`EntryState::Preserved`] the value from the contract storage has been
    /// preserved and does not need to be synchronized.
    state: Cell<EntryState>,
}

47
impl<T> Debug for StorageEntry<T>
48
49
50
51
52
53
54
55
56
57
58
59
60
where
    T: Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Entry")
            .field("value", &self.value)
            .field("state", &self.state.get())
            .finish()
    }
}

#[test]
fn debug_impl_works() {
61
    let e1 = <StorageEntry<i32>>::new(None, EntryState::Preserved);
62
63
64
65
    assert_eq!(
        format!("{:?}", &e1),
        "Entry { value: None, state: Preserved }",
    );
66
    let e2 = StorageEntry::new(Some(42), EntryState::Mutated);
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
    assert_eq!(
        format!("{:?}", &e2),
        "Entry { value: Some(42), state: Mutated }",
    );
}

/// The state of the entry.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum EntryState {
    /// The entry's value must be synchronized with the contract storage.
    Mutated,
    /// The entry's value preserved the value from the contract storage.
    Preserved,
}

impl EntryState {
    /// Returns `true` if the entry state is mutated.
    pub fn is_mutated(self) -> bool {
        match self {
            EntryState::Mutated => true,
            EntryState::Preserved => false,
        }
    }

    /// Returns `true` if the entry state is preserved.
    pub fn is_preserved(self) -> bool {
        !self.is_mutated()
    }
}

97
impl<T> SpreadLayout for StorageEntry<T>
98
99
100
101
102
103
where
    T: SpreadLayout,
{
    const FOOTPRINT: u64 = <T as SpreadLayout>::FOOTPRINT;

    fn pull_spread(ptr: &mut KeyPtr) -> Self {
104
        let root_key = ExtKeyPtr::next_for::<Self>(ptr);
Hero Bird's avatar
Hero Bird committed
105
        Self::pull_spread_root(root_key)
106
107
108
    }

    fn push_spread(&self, ptr: &mut KeyPtr) {
Hero Bird's avatar
Hero Bird committed
109
110
        let root_key = ExtKeyPtr::next_for::<Self>(ptr);
        self.push_spread_root(root_key)
111
112
113
    }

    fn clear_spread(&self, ptr: &mut KeyPtr) {
114
        let root_key = ExtKeyPtr::next_for::<Self>(ptr);
Hero Bird's avatar
Hero Bird committed
115
        self.clear_spread_root(root_key)
116
117
118
    }
}

119
impl<T> scale::Encode for StorageEntry<T>
120
121
122
123
124
125
126
127
128
where
    T: scale::Encode,
{
    #[inline]
    fn size_hint(&self) -> usize {
        <Option<T> as scale::Encode>::size_hint(&self.value)
    }

    #[inline]
129
    fn encode_to<O: scale::Output + ?Sized>(&self, dest: &mut O) {
130
131
132
133
134
135
136
137
138
139
140
141
142
143
        <Option<T> as scale::Encode>::encode_to(&self.value, dest)
    }

    #[inline]
    fn encode(&self) -> Vec<u8> {
        <Option<T> as scale::Encode>::encode(&self.value)
    }

    #[inline]
    fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
        <Option<T> as scale::Encode>::using_encoded(&self.value, f)
    }
}

144
impl<T> scale::Decode for StorageEntry<T>
145
146
147
148
149
150
151
152
153
154
155
where
    T: scale::Decode,
{
    fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
        Ok(Self::new(
            <Option<T> as scale::Decode>::decode(input)?,
            EntryState::Preserved,
        ))
    }
}

156
impl<T> PackedLayout for StorageEntry<T>
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
where
    T: PackedLayout,
{
    #[inline]
    fn pull_packed(&mut self, at: &Key) {
        PackedLayout::pull_packed(&mut self.value, at)
    }

    #[inline]
    fn push_packed(&self, at: &Key) {
        PackedLayout::push_packed(&self.value, at)
    }

    #[inline]
    fn clear_packed(&self, at: &Key) {
        PackedLayout::clear_packed(&self.value, at)
    }
}

Hero Bird's avatar
Hero Bird committed
176
177
178
179
impl<T> StorageEntry<T>
where
    T: SpreadLayout,
{
180
181
    /// Pulls the entity from the underlying associated storage as a `SpreadLayout`
    /// storage layout representation.
Hero Bird's avatar
Hero Bird committed
182
183
184
185
    ///
    /// # Note
    ///
    /// Mainly used by lazy storage abstractions that only allow operating on
186
    /// packed storage entities such as [`LazyCell`][`crate::lazy::LazyCell`].
Hero Bird's avatar
Hero Bird committed
187
    pub fn pull_spread_root(root_key: &Key) -> Self {
188
        Self::new(pull_spread_root_opt::<T>(root_key), EntryState::Preserved)
Hero Bird's avatar
Hero Bird committed
189
190
    }

191
192
    /// Pushes the underlying associated data to the contract storage using
    /// the `SpreadLayout` storage layout.
Hero Bird's avatar
Hero Bird committed
193
194
195
196
    ///
    /// # Note
    ///
    /// Mainly used by lazy storage abstractions that only allow operating on
197
    /// packed storage entities such as [`LazyCell`][`crate::lazy::LazyCell`].
Hero Bird's avatar
Hero Bird committed
198
199
200
    pub fn push_spread_root(&self, root_key: &Key) {
        let old_state = self.replace_state(EntryState::Preserved);
        if old_state.is_mutated() {
201
            push_spread_root_opt::<T>(self.value().into(), root_key);
Hero Bird's avatar
Hero Bird committed
202
203
204
        }
    }

205
    /// Clears the underlying associated storage as `SpreadLayout` storage layout representation.
Hero Bird's avatar
Hero Bird committed
206
207
208
209
    ///
    /// # Note
    ///
    /// Mainly used by lazy storage abstractions that only allow operating on
210
    /// packed storage entities such as [`LazyCell`][`crate::lazy::LazyCell`].
Hero Bird's avatar
Hero Bird committed
211
    pub fn clear_spread_root(&self, root_key: &Key) {
212
        clear_spread_root_opt::<T, _>(root_key, || self.value().into());
Hero Bird's avatar
Hero Bird committed
213
214
215
    }
}

216
impl<T> StorageEntry<T>
217
218
219
220
221
222
223
224
where
    T: PackedLayout,
{
    /// Pulls the entity from the underlying associated storage as packed representation.
    ///
    /// # Note
    ///
    /// Mainly used by lazy storage abstractions that only allow operating on
225
226
    /// packed storage entities such as [`LazyIndexMap`][`crate::lazy::LazyIndexMap`] or
    /// [`LazyArray`][`crate::lazy::LazyArray`].
227
228
229
230
231
232
233
234
235
    pub fn pull_packed_root(root_key: &Key) -> Self {
        Self::new(pull_packed_root_opt::<T>(root_key), EntryState::Preserved)
    }

    /// Pushes the underlying associated storage as packed representation.
    ///
    /// # Note
    ///
    /// Mainly used by lazy storage abstractions that only allow operating on
236
237
    /// packed storage entities such as [`LazyIndexMap`][`crate::lazy::LazyIndexMap`]
    /// or [`LazyArray`][`crate::lazy::LazyArray`].
238
239
240
    pub fn push_packed_root(&self, root_key: &Key) {
        let old_state = self.replace_state(EntryState::Preserved);
        if old_state.is_mutated() {
241
            push_packed_root_opt::<T>(self.value().into(), root_key);
242
243
244
245
246
247
248
249
        }
    }

    /// Clears the underlying associated storage as packed representation.
    ///
    /// # Note
    ///
    /// Mainly used by lazy storage abstractions that only allow operating on
250
251
    /// packed storage entities such as [`LazyIndexMap`][`crate::lazy::LazyIndexMap`]
    /// or [`LazyArray`][`crate::lazy::LazyArray`].
252
    pub fn clear_packed_root(&self, root_key: &Key) {
253
        clear_packed_root::<Option<T>>(self.value(), root_key);
254
255
256
    }
}

257
impl<T> StorageEntry<T> {
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
    /// Creates a new entry with the value and state.
    pub fn new(value: Option<T>, state: EntryState) -> Self {
        Self {
            value,
            state: Cell::new(state),
        }
    }

    /// Replaces the current entry state with the new state and returns it.
    pub fn replace_state(&self, new_state: EntryState) -> EntryState {
        // The implementation of `Cell::set` uses `Cell::replace` so instead
        // of offering both APIs we simply opted to offer just the more general
        // replace API for `Entry`.
        self.state.replace(new_state)
    }

    /// Returns a shared reference to the value of the entry.
    pub fn value(&self) -> &Option<T> {
        &self.value
    }

    /// Returns an exclusive reference to the entry value.
    ///
    /// # Note
    ///
    /// This changes the `mutate` state of the entry if the entry was occupied
    /// since the caller could potentially change the returned value.
    pub fn value_mut(&mut self) -> &mut Option<T> {
        if self.value.is_some() {
            self.state.set(EntryState::Mutated);
        }
        &mut self.value
    }

    /// Converts the entry into its value.
    pub fn into_value(self) -> Option<T> {
        self.value
    }

    /// Puts the new value into the entry and returns the old value.
    ///
    /// # Note
    ///
    /// This changes the `mutate` state of the entry to `true` as long as at
    /// least one of `old_value` and `new_value` is `Some`.
    pub fn put(&mut self, new_value: Option<T>) -> Option<T> {
        let new_value_is_some = new_value.is_some();
        let old_value = core::mem::replace(&mut self.value, new_value);
        if old_value.is_some() || new_value_is_some {
            self.state.set(EntryState::Mutated);
        }
        old_value
    }
}