1mod mapping;
22mod vec;
23
24#[doc(inline)]
25pub use self::mapping::Mapping;
26pub use self::vec::StorageVec;
27
28use crate::traits::{
29 AutoKey,
30 StorableHint,
31 StorageKey,
32};
33use core::marker::PhantomData;
34use ink_primitives::Key;
35use ink_storage_traits::Storable;
36use scale::{
37 Error,
38 Input,
39 Output,
40};
41
42#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
99pub struct Lazy<V, KeyType: StorageKey = AutoKey> {
100 _marker: PhantomData<fn() -> (V, KeyType)>,
101}
102
103impl<V, KeyType> Default for Lazy<V, KeyType>
105where
106 KeyType: StorageKey,
107{
108 fn default() -> Self {
109 Self::new()
110 }
111}
112
113impl<V, KeyType> Lazy<V, KeyType>
114where
115 KeyType: StorageKey,
116{
117 pub const fn new() -> Self {
119 Self {
120 _marker: PhantomData,
121 }
122 }
123}
124
125impl<V, KeyType> core::fmt::Debug for Lazy<V, KeyType>
126where
127 KeyType: StorageKey,
128{
129 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
130 f.debug_struct("Lazy").field("key", &KeyType::KEY).finish()
131 }
132}
133
134impl<V, KeyType> Lazy<V, KeyType>
135where
136 V: Storable,
137 KeyType: StorageKey,
138{
139 pub fn get(&self) -> Option<V> {
145 match ink_env::get_contract_storage::<Key, V>(&KeyType::KEY) {
146 Ok(Some(value)) => Some(value),
147 _ => None,
148 }
149 }
150
151 pub fn try_get(&self) -> Option<ink_env::Result<V>> {
161 let key_size = <Key as Storable>::encoded_size(&KeyType::KEY);
162
163 if key_size >= ink_env::BUFFER_SIZE {
164 return Some(Err(ink_env::Error::BufferTooSmall));
165 }
166
167 let value_size: usize = ink_env::contains_contract_storage(&KeyType::KEY)?
168 .try_into()
169 .expect("targets of less than 32bit pointer size are not supported; qed");
170
171 if key_size.saturating_add(value_size) > ink_env::BUFFER_SIZE {
172 return Some(Err(ink_env::Error::BufferTooSmall));
173 }
174
175 self.get().map(Ok)
176 }
177
178 pub fn set(&mut self, value: &V) {
184 ink_env::set_contract_storage::<Key, V>(&KeyType::KEY, value);
185 }
186
187 pub fn try_set(&mut self, value: &V) -> ink_env::Result<()> {
192 let key_size = <Key as Storable>::encoded_size(&KeyType::KEY);
193 let value_size = <V as Storable>::encoded_size(value);
194
195 if key_size.saturating_add(value_size) > ink_env::BUFFER_SIZE {
196 return Err(ink_env::Error::BufferTooSmall);
197 };
198
199 self.set(value);
200
201 Ok(())
202 }
203}
204
205impl<V, KeyType> Lazy<V, KeyType>
206where
207 V: Storable + Default,
208 KeyType: StorageKey,
209{
210 pub fn get_or_default(&self) -> V {
214 match ink_env::get_contract_storage::<Key, V>(&KeyType::KEY) {
215 Ok(Some(value)) => value,
216 _ => Default::default(),
217 }
218 }
219}
220
221impl<V, KeyType> Storable for Lazy<V, KeyType>
222where
223 KeyType: StorageKey,
224{
225 #[inline(always)]
226 fn encode<T: Output + ?Sized>(&self, _dest: &mut T) {}
227
228 #[inline(always)]
229 fn decode<I: Input>(_input: &mut I) -> Result<Self, Error> {
230 Ok(Default::default())
231 }
232
233 #[inline(always)]
234 fn encoded_size(&self) -> usize {
235 0
236 }
237}
238
239impl<V, Key, InnerKey> StorableHint<Key> for Lazy<V, InnerKey>
240where
241 Key: StorageKey,
242 InnerKey: StorageKey,
243 V: StorableHint<Key>,
244{
245 type Type = Lazy<V::Type, Key>;
246 type PreferredKey = InnerKey;
247}
248
249impl<V, KeyType> StorageKey for Lazy<V, KeyType>
250where
251 KeyType: StorageKey,
252{
253 const KEY: Key = KeyType::KEY;
254}
255
256#[cfg(feature = "std")]
257const _: () = {
258 use crate::traits::StorageLayout;
259 use ink_metadata::layout::{
260 Layout,
261 LayoutKey,
262 RootLayout,
263 };
264
265 impl<V, KeyType> StorageLayout for Lazy<V, KeyType>
266 where
267 V: StorageLayout + scale_info::TypeInfo + 'static,
268 KeyType: StorageKey + scale_info::TypeInfo + 'static,
269 {
270 fn layout(_: &Key) -> Layout {
271 Layout::Root(RootLayout::new(
272 LayoutKey::from(&KeyType::KEY),
273 <V as StorageLayout>::layout(&KeyType::KEY),
274 scale_info::meta_type::<Self>(),
275 ))
276 }
277 }
278};
279
280#[cfg(test)]
281mod tests {
282 use super::*;
283 use crate::traits::ManualKey;
284
285 #[test]
286 fn set_and_get_work() {
287 ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
288 let mut storage: Lazy<u8> = Lazy::new();
289 storage.set(&2);
290 assert_eq!(storage.get(), Some(2));
291
292 Ok(())
293 })
294 .unwrap()
295 }
296
297 #[test]
298 fn set_and_get_work_for_two_lazy_with_same_manual_key() {
299 ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
300 let mut storage: Lazy<u8, ManualKey<123>> = Lazy::new();
301 storage.set(&2);
302
303 let storage2: Lazy<u8, ManualKey<123>> = Lazy::new();
304 assert_eq!(storage2.get(), Some(2));
305
306 Ok(())
307 })
308 .unwrap()
309 }
310
311 #[test]
312 fn gets_or_default_if_no_key_set() {
313 ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
314 let storage: Lazy<u8> = Lazy::new();
315 assert_eq!(storage.get_or_default(), 0);
316
317 Ok(())
318 })
319 .unwrap()
320 }
321
322 #[test]
323 fn gets_returns_none_if_no_value_was_set() {
324 ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
325 let storage: Lazy<u8> = Lazy::new();
326 assert_eq!(storage.get(), None);
327
328 Ok(())
329 })
330 .unwrap()
331 }
332
333 #[test]
334 fn fallible_storage_works_for_fitting_data() {
335 ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
336 const KEY_SIZE: usize = 4;
338 const VALUE_SIZE: usize = ink_env::BUFFER_SIZE - KEY_SIZE;
339
340 let mut storage: Lazy<[u8; VALUE_SIZE]> = Lazy::new();
341
342 let value = [0u8; VALUE_SIZE];
343 assert_eq!(storage.try_set(&value), Ok(()));
344 assert_eq!(storage.try_get(), Some(Ok(value)));
345
346 Ok(())
347 })
348 .unwrap()
349 }
350
351 #[test]
352 fn fallible_storage_fails_gracefully_for_overgrown_data() {
353 ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
354 const KEY_SIZE: usize = 4;
356 const VALUE_SIZE: usize = ink_env::BUFFER_SIZE - KEY_SIZE + 1;
357
358 let mut storage: Lazy<[u8; VALUE_SIZE]> = Lazy::new();
359
360 let value = [0u8; VALUE_SIZE];
361 assert_eq!(storage.try_get(), None);
362 assert_eq!(storage.try_set(&value), Err(ink_env::Error::BufferTooSmall));
363
364 ink_env::set_contract_storage(&storage.key(), &value);
367 assert_eq!(storage.try_get(), Some(Err(ink_env::Error::BufferTooSmall)));
368
369 Ok(())
370 })
371 .unwrap()
372 }
373}