clone_cw_multi_test/prefixed_storage/
mod.rs

1use cosmwasm_std::Storage;
2use cosmwasm_std::{Order, Record};
3use length_prefixed::to_length_prefixed_nested;
4use namespace_helpers::{get_with_prefix, range_with_prefix, remove_with_prefix, set_with_prefix};
5
6mod length_prefixed;
7mod namespace_helpers;
8
9pub use length_prefixed::{
10    contract_namespace, decode_length, get_full_contract_storage_namespace, to_length_prefixed,
11    CONTRACT_STORAGE_PREFIX,
12};
13
14/// An alias of PrefixedStorage::new for less verbose usage
15pub fn prefixed<'a>(storage: &'a mut dyn Storage, namespace: &[u8]) -> PrefixedStorage<'a> {
16    PrefixedStorage::new(storage, namespace)
17}
18
19/// An alias of ReadonlyPrefixedStorage::new for less verbose usage
20pub fn prefixed_read<'a>(
21    storage: &'a dyn Storage,
22    namespace: &[u8],
23) -> ReadonlyPrefixedStorage<'a> {
24    ReadonlyPrefixedStorage::new(storage, namespace)
25}
26
27pub struct PrefixedStorage<'a> {
28    storage: &'a mut dyn Storage,
29    prefix: Vec<u8>,
30}
31
32impl<'a> PrefixedStorage<'a> {
33    pub fn new(storage: &'a mut dyn Storage, namespace: &[u8]) -> Self {
34        PrefixedStorage {
35            storage,
36            prefix: to_length_prefixed(namespace),
37        }
38    }
39
40    // Nested namespaces as documented in
41    // https://github.com/webmaster128/key-namespacing#nesting
42    pub fn multilevel(storage: &'a mut dyn Storage, namespaces: &[&[u8]]) -> Self {
43        PrefixedStorage {
44            storage,
45            prefix: to_length_prefixed_nested(namespaces),
46        }
47    }
48}
49
50impl<'a> Storage for PrefixedStorage<'a> {
51    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
52        get_with_prefix(self.storage, &self.prefix, key)
53    }
54
55    fn set(&mut self, key: &[u8], value: &[u8]) {
56        set_with_prefix(self.storage, &self.prefix, key, value);
57    }
58
59    fn remove(&mut self, key: &[u8]) {
60        remove_with_prefix(self.storage, &self.prefix, key);
61    }
62
63    /// range allows iteration over a set of keys, either forwards or backwards
64    /// uses standard rust range notation, and eg db.range(b"foo"..b"bar") also works reverse
65    fn range<'b>(
66        &'b self,
67        start: Option<&[u8]>,
68        end: Option<&[u8]>,
69        order: Order,
70    ) -> Box<dyn Iterator<Item = Record> + 'b> {
71        range_with_prefix(self.storage, &self.prefix, start, end, order)
72    }
73}
74
75pub struct ReadonlyPrefixedStorage<'a> {
76    storage: &'a dyn Storage,
77    prefix: Vec<u8>,
78}
79
80impl<'a> ReadonlyPrefixedStorage<'a> {
81    pub fn new(storage: &'a dyn Storage, namespace: &[u8]) -> Self {
82        ReadonlyPrefixedStorage {
83            storage,
84            prefix: to_length_prefixed(namespace),
85        }
86    }
87
88    // Nested namespaces as documented in
89    // https://github.com/webmaster128/key-namespacing#nesting
90    pub fn multilevel(storage: &'a dyn Storage, namespaces: &[&[u8]]) -> Self {
91        ReadonlyPrefixedStorage {
92            storage,
93            prefix: to_length_prefixed_nested(namespaces),
94        }
95    }
96}
97
98impl<'a> Storage for ReadonlyPrefixedStorage<'a> {
99    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
100        get_with_prefix(self.storage, &self.prefix, key)
101    }
102
103    fn set(&mut self, _key: &[u8], _value: &[u8]) {
104        unimplemented!();
105    }
106
107    fn remove(&mut self, _key: &[u8]) {
108        unimplemented!();
109    }
110
111    /// range allows iteration over a set of keys, either forwards or backwards
112    fn range<'b>(
113        &'b self,
114        start: Option<&[u8]>,
115        end: Option<&[u8]>,
116        order: Order,
117    ) -> Box<dyn Iterator<Item = Record> + 'b> {
118        range_with_prefix(self.storage, &self.prefix, start, end, order)
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125    use cosmwasm_std::testing::MockStorage;
126
127    #[test]
128    fn prefixed_storage_set_and_get() {
129        let mut storage = MockStorage::new();
130
131        // set
132        let mut s1 = PrefixedStorage::new(&mut storage, b"foo");
133        s1.set(b"bar", b"gotcha");
134        assert_eq!(storage.get(b"\x00\x03foobar").unwrap(), b"gotcha".to_vec());
135
136        // get
137        let s2 = PrefixedStorage::new(&mut storage, b"foo");
138        assert_eq!(s2.get(b"bar"), Some(b"gotcha".to_vec()));
139        assert_eq!(s2.get(b"elsewhere"), None);
140    }
141
142    #[test]
143    fn prefixed_storage_multilevel_set_and_get() {
144        let mut storage = MockStorage::new();
145
146        // set
147        let mut bar = PrefixedStorage::multilevel(&mut storage, &[b"foo", b"bar"]);
148        bar.set(b"baz", b"winner");
149        assert_eq!(
150            storage.get(b"\x00\x03foo\x00\x03barbaz").unwrap(),
151            b"winner".to_vec()
152        );
153
154        // get
155        let bar = PrefixedStorage::multilevel(&mut storage, &[b"foo", b"bar"]);
156        assert_eq!(bar.get(b"baz"), Some(b"winner".to_vec()));
157        assert_eq!(bar.get(b"elsewhere"), None);
158    }
159
160    #[test]
161    fn readonly_prefixed_storage_get() {
162        let mut storage = MockStorage::new();
163        storage.set(b"\x00\x03foobar", b"gotcha");
164
165        // try readonly correctly
166        let s1 = ReadonlyPrefixedStorage::new(&storage, b"foo");
167        assert_eq!(s1.get(b"bar"), Some(b"gotcha".to_vec()));
168        assert_eq!(s1.get(b"elsewhere"), None);
169
170        // no collisions with other prefixes
171        let s2 = ReadonlyPrefixedStorage::new(&storage, b"fo");
172        assert_eq!(s2.get(b"obar"), None);
173    }
174
175    #[test]
176    fn readonly_prefixed_storage_multilevel_get() {
177        let mut storage = MockStorage::new();
178        storage.set(b"\x00\x03foo\x00\x03barbaz", b"winner");
179
180        let bar = ReadonlyPrefixedStorage::multilevel(&storage, &[b"foo", b"bar"]);
181        assert_eq!(bar.get(b"baz"), Some(b"winner".to_vec()));
182        assert_eq!(bar.get(b"elsewhere"), None);
183    }
184}