cosmwasm_storage/
prefixed_storage.rs

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