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