icarus_canister/
easy_storage.rs1use crate::memory::get_memory;
4use crate::result::{IcarusError, IcarusResult};
5use ic_stable_structures::memory_manager::VirtualMemory;
6use ic_stable_structures::DefaultMemoryImpl;
7use ic_stable_structures::{StableBTreeMap, StableCell, Storable};
8use std::cell::RefCell;
9
10type Memory = VirtualMemory<DefaultMemoryImpl>;
11
12#[macro_export]
32macro_rules! icarus_storage {
33 (
34 $($name:ident: Map<$key:ty, $value:ty> = $id:expr;)*
35 $($counter:ident: Cell<$ctype:ty> = $cid:expr;)*
36 ) => {
37 thread_local! {
38 $(
39 static $name: $crate::easy_storage::StorageMap<$key, $value> =
40 $crate::easy_storage::StorageMap::new($id);
41 )*
42 $(
43 static $counter: $crate::easy_storage::CounterCell =
44 $crate::easy_storage::CounterCell::new($cid);
45 )*
46 }
47
48 $(
50 #[allow(non_camel_case_types)]
51 pub struct $name;
52
53 impl $name {
54 pub fn insert(key: $key, value: $value) -> $crate::result::IcarusResult<Option<$value>> {
55 $name.with(|s| s.insert(key, value))
56 }
57
58 pub fn get(key: &$key) -> Option<$value> {
59 $name.with(|s| s.get(key))
60 }
61
62 pub fn remove(key: &$key) -> Option<$value> {
63 $name.with(|s| s.remove(key))
64 }
65
66 pub fn contains(key: &$key) -> bool {
67 $name.with(|s| s.contains(key))
68 }
69
70 pub fn len() -> u64 {
71 $name.with(|s| s.len())
72 }
73
74 pub fn is_empty() -> bool {
75 $name.with(|s| s.is_empty())
76 }
77
78 pub fn clear() {
79 $name.with(|s| s.clear())
80 }
81
82 pub fn iter<F>(f: F)
83 where
84 F: FnMut(&$key, &$value)
85 {
86 $name.with(|s| s.iter(f))
87 }
88
89 pub fn values() -> Vec<$value> {
90 $name.with(|s| s.values())
91 }
92 }
93 )*
94
95 $(
96 #[allow(non_camel_case_types)]
97 pub struct $counter;
98
99 impl $counter {
100 pub fn get() -> $ctype {
101 $counter.with(|c| c.get())
102 }
103
104 pub fn set(value: $ctype) -> $crate::result::IcarusResult<()> {
105 $counter.with(|c| c.set(value))
106 }
107
108 pub fn increment() -> $ctype {
109 $counter.with(|c| c.increment())
110 }
111
112 pub fn decrement() -> $ctype {
113 $counter.with(|c| c.decrement())
114 }
115 }
116 )*
117 };
118}
119
120pub struct StorageMap<K, V>
122where
123 K: Storable + Ord + Clone,
124 V: Storable + Clone,
125{
126 inner: RefCell<StableBTreeMap<K, V, Memory>>,
127}
128
129impl<K, V> StorageMap<K, V>
130where
131 K: Storable + Ord + Clone,
132 V: Storable + Clone,
133{
134 pub fn new(memory_id: u8) -> Self {
135 Self {
136 inner: RefCell::new(StableBTreeMap::init(get_memory(memory_id))),
137 }
138 }
139
140 pub fn insert(&self, key: K, value: V) -> IcarusResult<Option<V>> {
141 Ok(self.inner.borrow_mut().insert(key, value))
142 }
143
144 pub fn get(&self, key: &K) -> Option<V> {
145 self.inner.borrow().get(key)
146 }
147
148 pub fn remove(&self, key: &K) -> Option<V> {
149 self.inner.borrow_mut().remove(key)
150 }
151
152 pub fn contains(&self, key: &K) -> bool {
153 self.inner.borrow().contains_key(key)
154 }
155
156 pub fn len(&self) -> u64 {
157 self.inner.borrow().len()
158 }
159
160 pub fn is_empty(&self) -> bool {
161 self.inner.borrow().is_empty()
162 }
163
164 pub fn clear(&self) {
165 self.inner.borrow_mut().clear_new()
166 }
167
168 pub fn iter<F>(&self, mut f: F)
169 where
170 F: FnMut(&K, &V),
171 {
172 for (k, v) in self.inner.borrow().iter() {
173 f(&k, &v);
174 }
175 }
176
177 pub fn values(&self) -> Vec<V> {
178 self.inner.borrow().iter().map(|(_, v)| v).collect()
179 }
180
181 pub fn get_or_insert<F>(&self, key: K, f: F) -> V
182 where
183 F: FnOnce() -> V,
184 {
185 if let Some(v) = self.get(&key) {
186 v
187 } else {
188 let value = f();
189 self.inner.borrow_mut().insert(key, value.clone());
190 value
191 }
192 }
193}
194
195pub struct StorageCell<T>
197where
198 T: Storable + Default + Clone,
199{
200 inner: RefCell<StableCell<T, Memory>>,
201}
202
203impl<T> StorageCell<T>
204where
205 T: Storable + Default + Clone,
206{
207 pub fn new(memory_id: u8) -> Self {
208 Self {
209 inner: RefCell::new(
210 StableCell::init(get_memory(memory_id), T::default())
211 .expect("Failed to init storage cell"),
212 ),
213 }
214 }
215
216 pub fn get(&self) -> T {
217 self.inner.borrow().get().clone()
218 }
219
220 pub fn set(&self, value: T) -> IcarusResult<()> {
221 self.inner
222 .borrow_mut()
223 .set(value)
224 .map(|_| ())
225 .map_err(|_| IcarusError::storage("Failed to set value"))
226 }
227}
228
229pub struct CounterCell {
231 inner: RefCell<StableCell<u64, Memory>>,
232}
233
234impl CounterCell {
235 pub fn new(memory_id: u8) -> Self {
236 Self {
237 inner: RefCell::new(
238 StableCell::init(get_memory(memory_id), 0u64).expect("Failed to init counter cell"),
239 ),
240 }
241 }
242
243 pub fn get(&self) -> u64 {
244 *self.inner.borrow().get()
245 }
246
247 pub fn set(&self, value: u64) -> IcarusResult<()> {
248 self.inner
249 .borrow_mut()
250 .set(value)
251 .map(|_| ())
252 .map_err(|_| IcarusError::storage("Failed to set counter value"))
253 }
254
255 pub fn increment(&self) -> u64 {
256 let current = self.get();
257 let next = current + 1;
258 let _ = self.set(next);
259 next
260 }
261
262 pub fn decrement(&self) -> u64 {
263 let current = self.get();
264 let next = current.saturating_sub(1);
265 let _ = self.set(next);
266 next
267 }
268}