typed_cell.rs 3.56 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
// This file is part of pDSL.
//
// pDSL is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pDSL is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pDSL.  If not, see <http://www.gnu.org/licenses/>.

17
18
19
20
use crate::{
	storage::{
		NonCloneMarker,
		cell::RawCell,
21
		Allocator,
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
	},
};

/// A typed cell.
///
/// Provides interpreted access to the associated contract storage slot.
///
/// # Guarantees
///
/// - `Owned`
/// - `Typed`
///
/// Read more about kinds of guarantees and their effect [here](../index.html#guarantees).
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct TypedCell<T> {
	/// The associated raw cell.
	cell: RawCell,
	/// Marker that prevents this type from being `Copy` or `Clone` by accident.
	non_clone: NonCloneMarker<T>,
}

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
impl<T> parity_codec::Encode for TypedCell<T> {
	fn encode_to<W: parity_codec::Output>(&self, dest: &mut W) {
		self.cell.encode_to(dest)
	}
}

impl<T> parity_codec::Decode for TypedCell<T> {
	fn decode<I: parity_codec::Input>(input: &mut I) -> Option<Self> {
		RawCell::decode(input)
			.map(|raw_cell| Self{
				cell: raw_cell,
				non_clone: NonCloneMarker::default()
			})
	}
}

59
impl<T> TypedCell<T> {
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
	/// Allocates a new typed cell using the given storage allocator.
	///
	/// # Safety
	///
	/// The is unsafe because it does not check if the associated storage
	/// does not alias with storage allocated by other storage allocators.
	pub unsafe fn new_using_alloc<A>(alloc: &mut A) -> Self
	where
		A: Allocator
	{
		Self{
			cell: RawCell::new_using_alloc(alloc),
			non_clone: Default::default(),
		}
	}

76
77
78
79
	/// Removes the value stored in the cell.
	pub fn clear(&mut self) {
		self.cell.clear()
	}
80
81
82
83
84
85
}

impl<T> TypedCell<T>
where
	T: parity_codec::Decode
{
86
	/// Loads the value stored in the cell if any.
87
88
89
90
91
92
93
94
95
	pub fn load(&self) -> Option<T> {
		self.cell.load().and_then(|bytes| T::decode(&mut &bytes[..]))
	}
}

impl<T> TypedCell<T>
where
	T: parity_codec::Encode
{
96
	/// Stores the value into the cell.
97
98
99
100
101
102
103
104
	pub fn store(&mut self, val: &T) {
		self.cell.store(&T::encode(&val))
	}
}

#[cfg(all(test, feature = "test-env"))]
mod tests {
	use super::*;
105
	use crate::storage::Key;
106

107
108
109
110
	use crate::{
		test_utils::run_test,
		env::TestEnv,
	};
111

112
113
114
115
116
117
118
119
120
	fn dummy_cell() -> TypedCell<i32> {
		unsafe {
			let mut alloc = crate::storage::alloc::ForwardAlloc::from_raw_parts(
				Key([0x0; 32])
			);
			TypedCell::new_using_alloc(&mut alloc)
		}
	}

121
122
	#[test]
	fn simple() {
123
		run_test(|| {
124
			let mut cell = dummy_cell();
125
126
127
128
129
130
			assert_eq!(cell.load(), None);
			cell.store(&5);
			assert_eq!(cell.load(), Some(5));
			cell.clear();
			assert_eq!(cell.load(), None);
		})
131
132
133
134
	}

	#[test]
	fn count_reads() {
135
		run_test(|| {
136
			let mut cell = dummy_cell();
137
138
139
140
141
142
143
			assert_eq!(TestEnv::total_reads(), 0);
			cell.load();
			assert_eq!(TestEnv::total_reads(), 1);
			cell.load();
			cell.load();
			assert_eq!(TestEnv::total_reads(), 3);
		})
144
145
146
147
	}

	#[test]
	fn count_writes() {
148
		run_test(|| {
149
			let mut cell = dummy_cell();
150
151
152
153
154
155
156
			assert_eq!(TestEnv::total_writes(), 0);
			cell.store(&1);
			assert_eq!(TestEnv::total_writes(), 1);
			cell.store(&2);
			cell.store(&3);
			assert_eq!(TestEnv::total_writes(), 3);
		})
157
158
	}
}