raw_cell.rs 3.42 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
use crate::{
18
	memory::vec::Vec,
19
20
21
	storage::{
		Key,
		NonCloneMarker,
22
		Allocator,
23
24
25
26
	},
	env::{Env, ContractEnv},
};

27
use parity_codec::{Encode, Decode};
28

29
30
31
32
33
34
35
36
37
/// A raw cell.
///
/// Provides uninterpreted and unformatted access to the associated contract storage slot.
///
/// # Guarantees
///
/// - `Owned`
///
/// Read more about kinds of guarantees and their effect [here](../index.html#guarantees).
38
#[derive(Debug, PartialEq, Eq, Hash, Encode, Decode)]
39
40
41
42
43
44
45
46
47
48
pub struct RawCell {
	/// The key to the associated constract storage slot.
	key: Key,
	/// Marker that prevents this type from being `Copy` or `Clone` by accident.
	non_clone: NonCloneMarker<()>,
}

impl RawCell {
	/// Creates a new raw cell for the given key.
	///
49
	/// # Safety
50
51
52
	///
	/// This is unsafe since it does not check if the associated
	/// contract storage does not alias with other accesses.
53
	unsafe fn new_unchecked(key: Key) -> Self {
54
55
56
57
58
		Self{
			key: key,
			non_clone: NonCloneMarker::default()
		}
	}
59
60
61
62
63
64
65
66
67
68
69

	/// Allocates a new raw 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
	{
70
		Self::new_unchecked(alloc.alloc(1))
71
	}
72
73
74
}

impl RawCell {
75
	/// Loads the bytes stored in the cell if not empty.
76
	pub fn load(&self) -> Option<Vec<u8>> {
77
		unsafe { ContractEnv::load(self.key) }
78
79
	}

80
	/// Stores the given bytes into the cell.
81
	pub fn store(&mut self, bytes: &[u8]) {
82
		unsafe { ContractEnv::store(self.key, bytes) }
83
84
	}

85
	/// Removes the bytes stored in the cell.
86
	pub fn clear(&mut self) {
87
		unsafe { ContractEnv::clear(self.key) }
88
89
90
91
92
93
94
	}
}

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

95
96
97
98
	use crate::{
		test_utils::run_test,
		env::TestEnv,
	};
99
100
101

	#[test]
	fn simple() {
102
103
104
105
106
107
108
109
110
111
		run_test(|| {
			let mut cell = unsafe {
				RawCell::new_unchecked(Key([0x42; 32]))
			};
			assert_eq!(cell.load(), None);
			cell.store(b"Hello, World!");
			assert_eq!(cell.load(), Some(b"Hello, World!".to_vec()));
			cell.clear();
			assert_eq!(cell.load(), None);
		})
112
113
114
115
	}

	#[test]
	fn count_reads() {
116
117
118
119
120
121
122
123
124
125
126
		run_test(|| {
			let cell = unsafe {
				RawCell::new_unchecked(Key([0x42; 32]))
			};
			assert_eq!(TestEnv::total_reads(), 0);
			cell.load();
			assert_eq!(TestEnv::total_reads(), 1);
			cell.load();
			cell.load();
			assert_eq!(TestEnv::total_reads(), 3);
		})
127
128
129
130
	}

	#[test]
	fn count_writes() {
131
132
133
134
135
136
137
138
139
140
141
		run_test(|| {
			let mut cell = unsafe {
				RawCell::new_unchecked(Key([0x42; 32]))
			};
			assert_eq!(TestEnv::total_writes(), 0);
			cell.store(b"a");
			assert_eq!(TestEnv::total_writes(), 1);
			cell.store(b"b");
			cell.store(b"c");
			assert_eq!(TestEnv::total_writes(), 3);
		})
142
143
	}
}