1use crate::{
21 storage::{
22 generator::StorageMap as _,
23 types::{
24 OptionQuery, QueryKindTrait, StorageEntryMetadataBuilder, StorageMap, StorageValue,
25 ValueQuery,
26 },
27 StorageAppend, StorageDecodeLength, StorageTryAppend,
28 },
29 traits::{Get, GetDefault, StorageInfo, StorageInfoTrait, StorageInstance},
30 Never,
31};
32use alloc::{vec, vec::Vec};
33use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen, Ref};
34use sp_io::MultiRemovalResults;
35use sp_metadata_ir::StorageEntryMetadataIR;
36use sp_runtime::traits::Saturating;
37
38#[doc = docify::embed!("src/storage/types/counted_map.rs", test_simple_count_works)]
95pub struct CountedStorageMap<
96 Prefix,
97 Hasher,
98 Key,
99 Value,
100 QueryKind = OptionQuery,
101 OnEmpty = GetDefault,
102 MaxValues = GetDefault,
103>(core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues)>);
104
105pub trait CountedStorageMapInstance: StorageInstance {
107 type CounterPrefix: StorageInstance;
109}
110
111trait MapWrapper {
113 type Map;
114}
115
116impl<P: CountedStorageMapInstance, H, K, V, Q, O, M> MapWrapper
117 for CountedStorageMap<P, H, K, V, Q, O, M>
118{
119 type Map = StorageMap<P, H, K, V, Q, O, M>;
120}
121
122pub type Counter = u32;
124
125type CounterFor<P> =
126 StorageValue<<P as CountedStorageMapInstance>::CounterPrefix, Counter, ValueQuery>;
127
128pub struct OnRemovalCounterUpdate<Prefix>(core::marker::PhantomData<Prefix>);
131
132impl<Prefix: CountedStorageMapInstance> crate::storage::PrefixIteratorOnRemoval
133 for OnRemovalCounterUpdate<Prefix>
134{
135 fn on_removal(_key: &[u8], _value: &[u8]) {
136 CounterFor::<Prefix>::mutate(|value| value.saturating_dec());
137 }
138}
139
140impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
141 CountedStorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
142where
143 Prefix: CountedStorageMapInstance,
144 Hasher: crate::hash::StorageHasher,
145 Key: FullCodec,
146 Value: FullCodec,
147 QueryKind: QueryKindTrait<Value, OnEmpty>,
148 OnEmpty: Get<QueryKind::Query> + 'static,
149 MaxValues: Get<Option<u32>>,
150{
151 pub fn counter_storage_final_key() -> [u8; 32] {
153 CounterFor::<Prefix>::hashed_key()
154 }
155
156 pub fn map_storage_final_prefix() -> Vec<u8> {
158 use crate::storage::generator::StorageMap;
159 <Self as MapWrapper>::Map::prefix_hash().to_vec()
160 }
161
162 pub fn hashed_key_for<KeyArg: EncodeLike<Key>>(key: KeyArg) -> Vec<u8> {
164 <Self as MapWrapper>::Map::hashed_key_for(key)
165 }
166
167 pub fn contains_key<KeyArg: EncodeLike<Key>>(key: KeyArg) -> bool {
169 <Self as MapWrapper>::Map::contains_key(key)
170 }
171
172 pub fn get<KeyArg: EncodeLike<Key>>(key: KeyArg) -> QueryKind::Query {
174 <Self as MapWrapper>::Map::get(key)
175 }
176
177 pub fn try_get<KeyArg: EncodeLike<Key>>(key: KeyArg) -> Result<Value, ()> {
181 <Self as MapWrapper>::Map::try_get(key)
182 }
183
184 pub fn set<KeyArg: EncodeLike<Key>>(key: KeyArg, q: QueryKind::Query) {
186 match QueryKind::from_query_to_optional_value(q) {
187 Some(v) => Self::insert(key, v),
188 None => Self::remove(key),
189 }
190 }
191
192 pub fn swap<KeyArg1: EncodeLike<Key>, KeyArg2: EncodeLike<Key>>(key1: KeyArg1, key2: KeyArg2) {
194 <Self as MapWrapper>::Map::swap(key1, key2)
195 }
196
197 pub fn insert<KeyArg: EncodeLike<Key>, ValArg: EncodeLike<Value>>(key: KeyArg, val: ValArg) {
199 if !<Self as MapWrapper>::Map::contains_key(Ref::from(&key)) {
200 CounterFor::<Prefix>::mutate(|value| value.saturating_inc());
201 }
202 <Self as MapWrapper>::Map::insert(key, val)
203 }
204
205 pub fn remove<KeyArg: EncodeLike<Key>>(key: KeyArg) {
207 if <Self as MapWrapper>::Map::contains_key(Ref::from(&key)) {
208 CounterFor::<Prefix>::mutate(|value| value.saturating_dec());
209 }
210 <Self as MapWrapper>::Map::remove(key)
211 }
212
213 pub fn mutate<KeyArg: EncodeLike<Key>, R, F: FnOnce(&mut QueryKind::Query) -> R>(
215 key: KeyArg,
216 f: F,
217 ) -> R {
218 Self::try_mutate(key, |v| Ok::<R, Never>(f(v)))
219 .expect("`Never` can not be constructed; qed")
220 }
221
222 pub fn try_mutate<KeyArg, R, E, F>(key: KeyArg, f: F) -> Result<R, E>
224 where
225 KeyArg: EncodeLike<Key>,
226 F: FnOnce(&mut QueryKind::Query) -> Result<R, E>,
227 {
228 Self::try_mutate_exists(key, |option_value_ref| {
229 let option_value = core::mem::replace(option_value_ref, None);
230 let mut query = <Self as MapWrapper>::Map::from_optional_value_to_query(option_value);
231 let res = f(&mut query);
232 let option_value = <Self as MapWrapper>::Map::from_query_to_optional_value(query);
233 let _ = core::mem::replace(option_value_ref, option_value);
234 res
235 })
236 }
237
238 pub fn mutate_exists<KeyArg: EncodeLike<Key>, R, F: FnOnce(&mut Option<Value>) -> R>(
240 key: KeyArg,
241 f: F,
242 ) -> R {
243 Self::try_mutate_exists(key, |v| Ok::<R, Never>(f(v)))
244 .expect("`Never` can not be constructed; qed")
245 }
246
247 pub fn try_mutate_exists<KeyArg, R, E, F>(key: KeyArg, f: F) -> Result<R, E>
251 where
252 KeyArg: EncodeLike<Key>,
253 F: FnOnce(&mut Option<Value>) -> Result<R, E>,
254 {
255 <Self as MapWrapper>::Map::try_mutate_exists(key, |option_value| {
256 let existed = option_value.is_some();
257 let res = f(option_value);
258 let exist = option_value.is_some();
259
260 if res.is_ok() {
261 if existed && !exist {
262 CounterFor::<Prefix>::mutate(|value| value.saturating_dec());
264 } else if !existed && exist {
265 CounterFor::<Prefix>::mutate(|value| value.saturating_inc());
267 }
268 }
269 res
270 })
271 }
272
273 pub fn take<KeyArg: EncodeLike<Key>>(key: KeyArg) -> QueryKind::Query {
275 let removed_value = <Self as MapWrapper>::Map::mutate_exists(key, |value| value.take());
276 if removed_value.is_some() {
277 CounterFor::<Prefix>::mutate(|value| value.saturating_dec());
278 }
279 <Self as MapWrapper>::Map::from_optional_value_to_query(removed_value)
280 }
281
282 pub fn append<Item, EncodeLikeItem, EncodeLikeKey>(key: EncodeLikeKey, item: EncodeLikeItem)
291 where
292 EncodeLikeKey: EncodeLike<Key>,
293 Item: Encode,
294 EncodeLikeItem: EncodeLike<Item>,
295 Value: StorageAppend<Item>,
296 {
297 if !<Self as MapWrapper>::Map::contains_key(Ref::from(&key)) {
298 CounterFor::<Prefix>::mutate(|value| value.saturating_inc());
299 }
300 <Self as MapWrapper>::Map::append(key, item)
301 }
302
303 pub fn decode_len<KeyArg: EncodeLike<Key>>(key: KeyArg) -> Option<usize>
316 where
317 Value: StorageDecodeLength,
318 {
319 <Self as MapWrapper>::Map::decode_len(key)
320 }
321
322 pub fn migrate_key<OldHasher: crate::hash::StorageHasher, KeyArg: EncodeLike<Key>>(
326 key: KeyArg,
327 ) -> Option<Value> {
328 <Self as MapWrapper>::Map::migrate_key::<OldHasher, _>(key)
329 }
330
331 #[deprecated = "Use `clear` instead"]
333 pub fn remove_all() {
334 #[allow(deprecated)]
335 <Self as MapWrapper>::Map::remove_all(None);
336 CounterFor::<Prefix>::kill();
337 }
338
339 pub fn clear(limit: u32, maybe_cursor: Option<&[u8]>) -> MultiRemovalResults {
363 let result = <Self as MapWrapper>::Map::clear(limit, maybe_cursor);
364 match result.maybe_cursor {
365 None => CounterFor::<Prefix>::kill(),
366 Some(_) => CounterFor::<Prefix>::mutate(|x| x.saturating_reduce(result.unique)),
367 }
368 result
369 }
370
371 pub fn iter_values() -> crate::storage::PrefixIterator<Value, OnRemovalCounterUpdate<Prefix>> {
375 <Self as MapWrapper>::Map::iter_values().convert_on_removal()
376 }
377
378 pub fn translate_values<OldValue: Decode, F: FnMut(OldValue) -> Option<Value>>(mut f: F) {
393 <Self as MapWrapper>::Map::translate_values(|old_value| {
394 let res = f(old_value);
395 if res.is_none() {
396 CounterFor::<Prefix>::mutate(|value| value.saturating_dec());
397 }
398 res
399 })
400 }
401
402 pub fn try_append<KArg, Item, EncodeLikeItem>(key: KArg, item: EncodeLikeItem) -> Result<(), ()>
406 where
407 KArg: EncodeLike<Key>,
408 Item: Encode,
409 EncodeLikeItem: EncodeLike<Item>,
410 Value: StorageTryAppend<Item>,
411 {
412 let bound = Value::bound();
413 let current = <Self as MapWrapper>::Map::decode_len(Ref::from(&key)).unwrap_or_default();
414 if current < bound {
415 CounterFor::<Prefix>::mutate(|value| value.saturating_inc());
416 let key = <Self as MapWrapper>::Map::hashed_key_for(key);
417 sp_io::storage::append(&key, item.encode());
418 Ok(())
419 } else {
420 Err(())
421 }
422 }
423
424 pub fn initialize_counter() -> Counter {
431 let count = Self::iter_values().count() as Counter;
432 CounterFor::<Prefix>::set(count);
433 count
434 }
435
436 pub fn count() -> Counter {
438 CounterFor::<Prefix>::get()
439 }
440}
441
442impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
443 CountedStorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
444where
445 Prefix: CountedStorageMapInstance,
446 Hasher: crate::hash::StorageHasher + crate::ReversibleStorageHasher,
447 Key: FullCodec,
448 Value: FullCodec,
449 QueryKind: QueryKindTrait<Value, OnEmpty>,
450 OnEmpty: Get<QueryKind::Query> + 'static,
451 MaxValues: Get<Option<u32>>,
452{
453 pub fn iter() -> crate::storage::PrefixIterator<(Key, Value), OnRemovalCounterUpdate<Prefix>> {
457 <Self as MapWrapper>::Map::iter().convert_on_removal()
458 }
459
460 pub fn drain() -> crate::storage::PrefixIterator<(Key, Value), OnRemovalCounterUpdate<Prefix>> {
464 <Self as MapWrapper>::Map::drain().convert_on_removal()
465 }
466
467 pub fn translate<O: Decode, F: FnMut(Key, O) -> Option<Value>>(mut f: F) {
473 <Self as MapWrapper>::Map::translate(|key, old_value| {
474 let res = f(key, old_value);
475 if res.is_none() {
476 CounterFor::<Prefix>::mutate(|value| value.saturating_dec());
477 }
478 res
479 })
480 }
481
482 pub fn iter_from(
487 starting_raw_key: Vec<u8>,
488 ) -> crate::storage::PrefixIterator<(Key, Value), OnRemovalCounterUpdate<Prefix>> {
489 <Self as MapWrapper>::Map::iter_from(starting_raw_key).convert_on_removal()
490 }
491
492 pub fn iter_keys() -> crate::storage::KeyPrefixIterator<Key> {
496 <Self as MapWrapper>::Map::iter_keys()
497 }
498}
499
500impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues> StorageEntryMetadataBuilder
501 for CountedStorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
502where
503 Prefix: CountedStorageMapInstance,
504 Hasher: crate::hash::StorageHasher,
505 Key: FullCodec + scale_info::StaticTypeInfo,
506 Value: FullCodec + scale_info::StaticTypeInfo,
507 QueryKind: QueryKindTrait<Value, OnEmpty>,
508 OnEmpty: Get<QueryKind::Query> + 'static,
509 MaxValues: Get<Option<u32>>,
510{
511 fn build_metadata(
512 deprecation_status: sp_metadata_ir::ItemDeprecationInfoIR,
513 docs: Vec<&'static str>,
514 entries: &mut Vec<StorageEntryMetadataIR>,
515 ) {
516 <Self as MapWrapper>::Map::build_metadata(deprecation_status.clone(), docs, entries);
517 CounterFor::<Prefix>::build_metadata(
518 deprecation_status,
519 if cfg!(feature = "no-metadata-docs") {
520 vec![]
521 } else {
522 vec!["Counter for the related counted storage map"]
523 },
524 entries,
525 );
526 }
527}
528
529impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues> crate::traits::StorageInfoTrait
530 for CountedStorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
531where
532 Prefix: CountedStorageMapInstance,
533 Hasher: crate::hash::StorageHasher,
534 Key: FullCodec + MaxEncodedLen,
535 Value: FullCodec + MaxEncodedLen,
536 QueryKind: QueryKindTrait<Value, OnEmpty>,
537 OnEmpty: Get<QueryKind::Query> + 'static,
538 MaxValues: Get<Option<u32>>,
539{
540 fn storage_info() -> Vec<StorageInfo> {
541 [<Self as MapWrapper>::Map::storage_info(), CounterFor::<Prefix>::storage_info()].concat()
542 }
543}
544
545impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
547 crate::traits::PartialStorageInfoTrait
548 for CountedStorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
549where
550 Prefix: CountedStorageMapInstance,
551 Hasher: crate::hash::StorageHasher,
552 Key: FullCodec,
553 Value: FullCodec,
554 QueryKind: QueryKindTrait<Value, OnEmpty>,
555 OnEmpty: Get<QueryKind::Query> + 'static,
556 MaxValues: Get<Option<u32>>,
557{
558 fn partial_storage_info() -> Vec<StorageInfo> {
559 [<Self as MapWrapper>::Map::partial_storage_info(), CounterFor::<Prefix>::storage_info()]
560 .concat()
561 }
562}
563
564#[cfg(test)]
565mod test {
566 use super::*;
567 use crate::{
568 hash::*,
569 storage::{bounded_vec::BoundedVec, types::ValueQuery},
570 traits::ConstU32,
571 };
572 use sp_io::{hashing::twox_128, TestExternalities};
573 use sp_metadata_ir::{StorageEntryModifierIR, StorageEntryTypeIR, StorageHasherIR};
574
575 struct Prefix;
576 impl StorageInstance for Prefix {
577 fn pallet_prefix() -> &'static str {
578 "test"
579 }
580 const STORAGE_PREFIX: &'static str = "foo";
581 }
582
583 struct CounterPrefix;
584 impl StorageInstance for CounterPrefix {
585 fn pallet_prefix() -> &'static str {
586 "test"
587 }
588 const STORAGE_PREFIX: &'static str = "counter_for_foo";
589 }
590 impl CountedStorageMapInstance for Prefix {
591 type CounterPrefix = CounterPrefix;
592 }
593
594 struct ADefault;
595 impl crate::traits::Get<u32> for ADefault {
596 fn get() -> u32 {
597 97
598 }
599 }
600 #[crate::storage_alias]
601 type ExampleCountedMap = CountedStorageMap<Prefix, Twox64Concat, u16, u32>;
602
603 #[test]
604 fn storage_alias_works() {
605 TestExternalities::default().execute_with(|| {
606 assert_eq!(ExampleCountedMap::count(), 0);
607 ExampleCountedMap::insert(3, 10);
608 })
609 }
610
611 #[test]
612 fn test_value_query() {
613 type A = CountedStorageMap<Prefix, Twox64Concat, u16, u32, ValueQuery, ADefault>;
614
615 TestExternalities::default().execute_with(|| {
616 let mut k: Vec<u8> = vec![];
617 k.extend(&twox_128(b"test"));
618 k.extend(&twox_128(b"foo"));
619 k.extend(&3u16.twox_64_concat());
620 assert_eq!(A::hashed_key_for(3).to_vec(), k);
621
622 assert_eq!(A::contains_key(3), false);
623 assert_eq!(A::get(3), ADefault::get());
624 assert_eq!(A::try_get(3), Err(()));
625 assert_eq!(A::count(), 0);
626
627 A::insert(3, 10);
629
630 assert_eq!(A::contains_key(3), true);
631 assert_eq!(A::get(3), 10);
632 assert_eq!(A::try_get(3), Ok(10));
633 assert_eq!(A::count(), 1);
634
635 A::swap(4, 3);
637
638 assert_eq!(A::contains_key(3), false);
639 assert_eq!(A::get(3), ADefault::get());
640 assert_eq!(A::try_get(3), Err(()));
641 assert_eq!(A::contains_key(4), true);
642 assert_eq!(A::get(4), 10);
643 assert_eq!(A::try_get(4), Ok(10));
644 assert_eq!(A::count(), 1);
645
646 A::swap(4, 3);
648
649 assert_eq!(A::try_get(3), Ok(10));
650 assert_eq!(A::contains_key(4), false);
651 assert_eq!(A::get(4), ADefault::get());
652 assert_eq!(A::try_get(4), Err(()));
653 assert_eq!(A::count(), 1);
654
655 A::insert(4, 11);
656
657 assert_eq!(A::try_get(3), Ok(10));
658 assert_eq!(A::try_get(4), Ok(11));
659 assert_eq!(A::count(), 2);
660
661 A::swap(3, 4);
663
664 assert_eq!(A::try_get(3), Ok(11));
665 assert_eq!(A::try_get(4), Ok(10));
666 assert_eq!(A::count(), 2);
667
668 A::insert(3, 12);
670
671 assert_eq!(A::try_get(3), Ok(12));
672 assert_eq!(A::count(), 2);
673
674 A::remove(2);
676
677 assert_eq!(A::contains_key(2), false);
678 assert_eq!(A::count(), 2);
679
680 A::remove(3);
682
683 assert_eq!(A::try_get(3), Err(()));
684 assert_eq!(A::count(), 1);
685
686 A::mutate(3, |query| {
688 assert_eq!(*query, ADefault::get());
689 *query = 40;
690 });
691
692 assert_eq!(A::try_get(3), Ok(40));
693 assert_eq!(A::count(), 2);
694
695 A::mutate(3, |query| {
697 assert_eq!(*query, 40);
698 *query = 40;
699 });
700
701 assert_eq!(A::try_get(3), Ok(40));
702 assert_eq!(A::count(), 2);
703
704 A::try_mutate(2, |query| {
706 assert_eq!(*query, ADefault::get());
707 *query = 4;
708 Result::<(), ()>::Err(())
709 })
710 .err()
711 .unwrap();
712
713 assert_eq!(A::try_get(2), Err(()));
714 assert_eq!(A::count(), 2);
715
716 A::try_mutate(2, |query| {
718 assert_eq!(*query, ADefault::get());
719 *query = 41;
720 Result::<(), ()>::Ok(())
721 })
722 .unwrap();
723
724 assert_eq!(A::try_get(2), Ok(41));
725 assert_eq!(A::count(), 3);
726
727 A::try_mutate(2, |query| {
729 assert_eq!(*query, 41);
730 *query = 41;
731 Result::<(), ()>::Ok(())
732 })
733 .unwrap();
734
735 assert_eq!(A::try_get(2), Ok(41));
736 assert_eq!(A::count(), 3);
737
738 A::try_mutate_exists(1, |query| {
740 assert_eq!(*query, None);
741 *query = Some(4);
742 Result::<(), ()>::Err(())
743 })
744 .err()
745 .unwrap();
746
747 assert_eq!(A::try_get(1), Err(()));
748 assert_eq!(A::count(), 3);
749
750 A::try_mutate_exists(1, |query| {
752 assert_eq!(*query, None);
753 *query = Some(43);
754 Result::<(), ()>::Ok(())
755 })
756 .unwrap();
757
758 assert_eq!(A::try_get(1), Ok(43));
759 assert_eq!(A::count(), 4);
760
761 A::try_mutate_exists(1, |query| {
763 assert_eq!(*query, Some(43));
764 *query = Some(45);
765 Result::<(), ()>::Ok(())
766 })
767 .unwrap();
768
769 assert_eq!(A::try_get(1), Ok(45));
770 assert_eq!(A::count(), 4);
771
772 A::try_mutate_exists(1, |query| {
774 assert_eq!(*query, Some(45));
775 *query = None;
776 Result::<(), ()>::Ok(())
777 })
778 .unwrap();
779
780 assert_eq!(A::try_get(1), Err(()));
781 assert_eq!(A::count(), 3);
782
783 assert_eq!(A::take(4), 10);
785
786 assert_eq!(A::try_get(4), Err(()));
787 assert_eq!(A::count(), 2);
788
789 assert_eq!(A::take(4), ADefault::get());
791
792 assert_eq!(A::try_get(4), Err(()));
793 assert_eq!(A::count(), 2);
794
795 let _ = A::clear(u32::max_value(), None);
797
798 assert_eq!(A::count(), 0);
799 assert_eq!(A::initialize_counter(), 0);
800
801 A::insert(1, 1);
802 A::insert(2, 2);
803
804 assert_eq!(A::iter_values().collect::<Vec<_>>(), vec![2, 1]);
806
807 assert_eq!(A::iter_values().drain().collect::<Vec<_>>(), vec![2, 1]);
809 assert_eq!(A::count(), 0);
810
811 A::insert(1, 1);
812 A::insert(2, 2);
813
814 assert_eq!(A::initialize_counter(), 2);
816
817 A::set(30, 100);
819
820 assert_eq!(A::contains_key(30), true);
821 assert_eq!(A::get(30), 100);
822 assert_eq!(A::try_get(30), Ok(100));
823 assert_eq!(A::count(), 3);
824
825 A::set(30, 101);
827
828 assert_eq!(A::contains_key(30), true);
829 assert_eq!(A::get(30), 101);
830 assert_eq!(A::try_get(30), Ok(101));
831 assert_eq!(A::count(), 3);
832 })
833 }
834
835 #[test]
836 fn test_option_query() {
837 type B = CountedStorageMap<Prefix, Twox64Concat, u16, u32>;
838
839 TestExternalities::default().execute_with(|| {
840 let mut k: Vec<u8> = vec![];
841 k.extend(&twox_128(b"test"));
842 k.extend(&twox_128(b"foo"));
843 k.extend(&3u16.twox_64_concat());
844 assert_eq!(B::hashed_key_for(3).to_vec(), k);
845
846 assert_eq!(B::contains_key(3), false);
847 assert_eq!(B::get(3), None);
848 assert_eq!(B::try_get(3), Err(()));
849 assert_eq!(B::count(), 0);
850
851 B::insert(3, 10);
853
854 assert_eq!(B::contains_key(3), true);
855 assert_eq!(B::get(3), Some(10));
856 assert_eq!(B::try_get(3), Ok(10));
857 assert_eq!(B::count(), 1);
858
859 B::swap(4, 3);
861
862 assert_eq!(B::contains_key(3), false);
863 assert_eq!(B::get(3), None);
864 assert_eq!(B::try_get(3), Err(()));
865 assert_eq!(B::contains_key(4), true);
866 assert_eq!(B::get(4), Some(10));
867 assert_eq!(B::try_get(4), Ok(10));
868 assert_eq!(B::count(), 1);
869
870 B::swap(4, 3);
872
873 assert_eq!(B::try_get(3), Ok(10));
874 assert_eq!(B::contains_key(4), false);
875 assert_eq!(B::get(4), None);
876 assert_eq!(B::try_get(4), Err(()));
877 assert_eq!(B::count(), 1);
878
879 B::insert(4, 11);
880
881 assert_eq!(B::try_get(3), Ok(10));
882 assert_eq!(B::try_get(4), Ok(11));
883 assert_eq!(B::count(), 2);
884
885 B::swap(3, 4);
887
888 assert_eq!(B::try_get(3), Ok(11));
889 assert_eq!(B::try_get(4), Ok(10));
890 assert_eq!(B::count(), 2);
891
892 B::insert(3, 11);
894
895 assert_eq!(B::count(), 2);
896
897 B::remove(2);
899
900 assert_eq!(B::contains_key(2), false);
901 assert_eq!(B::count(), 2);
902
903 B::remove(3);
905
906 assert_eq!(B::try_get(3), Err(()));
907 assert_eq!(B::count(), 1);
908
909 B::mutate(3, |query| {
911 assert_eq!(*query, None);
912 *query = Some(40)
913 });
914
915 assert_eq!(B::try_get(3), Ok(40));
916 assert_eq!(B::count(), 2);
917
918 B::mutate(3, |query| {
920 assert_eq!(*query, Some(40));
921 *query = Some(40)
922 });
923
924 assert_eq!(B::try_get(3), Ok(40));
925 assert_eq!(B::count(), 2);
926
927 B::mutate(3, |query| {
929 assert_eq!(*query, Some(40));
930 *query = None
931 });
932
933 assert_eq!(B::try_get(3), Err(()));
934 assert_eq!(B::count(), 1);
935
936 B::insert(3, 40);
937
938 B::try_mutate(2, |query| {
940 assert_eq!(*query, None);
941 *query = Some(4);
942 Result::<(), ()>::Err(())
943 })
944 .err()
945 .unwrap();
946
947 assert_eq!(B::try_get(2), Err(()));
948 assert_eq!(B::count(), 2);
949
950 B::try_mutate(2, |query| {
952 assert_eq!(*query, None);
953 *query = Some(41);
954 Result::<(), ()>::Ok(())
955 })
956 .unwrap();
957
958 assert_eq!(B::try_get(2), Ok(41));
959 assert_eq!(B::count(), 3);
960
961 B::try_mutate(2, |query| {
963 assert_eq!(*query, Some(41));
964 *query = Some(41);
965 Result::<(), ()>::Ok(())
966 })
967 .unwrap();
968
969 assert_eq!(B::try_get(2), Ok(41));
970 assert_eq!(B::count(), 3);
971
972 B::try_mutate(2, |query| {
974 assert_eq!(*query, Some(41));
975 *query = None;
976 Result::<(), ()>::Ok(())
977 })
978 .unwrap();
979
980 assert_eq!(B::try_get(2), Err(()));
981 assert_eq!(B::count(), 2);
982
983 B::insert(2, 41);
984
985 B::try_mutate_exists(1, |query| {
987 assert_eq!(*query, None);
988 *query = Some(4);
989 Result::<(), ()>::Err(())
990 })
991 .err()
992 .unwrap();
993
994 assert_eq!(B::try_get(1), Err(()));
995 assert_eq!(B::count(), 3);
996
997 B::try_mutate_exists(1, |query| {
999 assert_eq!(*query, None);
1000 *query = Some(43);
1001 Result::<(), ()>::Ok(())
1002 })
1003 .unwrap();
1004
1005 assert_eq!(B::try_get(1), Ok(43));
1006 assert_eq!(B::count(), 4);
1007
1008 B::try_mutate_exists(1, |query| {
1010 assert_eq!(*query, Some(43));
1011 *query = Some(43);
1012 Result::<(), ()>::Ok(())
1013 })
1014 .unwrap();
1015
1016 assert_eq!(B::try_get(1), Ok(43));
1017 assert_eq!(B::count(), 4);
1018
1019 B::try_mutate_exists(1, |query| {
1021 assert_eq!(*query, Some(43));
1022 *query = None;
1023 Result::<(), ()>::Ok(())
1024 })
1025 .unwrap();
1026
1027 assert_eq!(B::try_get(1), Err(()));
1028 assert_eq!(B::count(), 3);
1029
1030 assert_eq!(B::take(4), Some(10));
1032
1033 assert_eq!(B::try_get(4), Err(()));
1034 assert_eq!(B::count(), 2);
1035
1036 assert_eq!(B::take(4), None);
1038
1039 assert_eq!(B::try_get(4), Err(()));
1040 assert_eq!(B::count(), 2);
1041
1042 let _ = B::clear(u32::max_value(), None);
1044
1045 assert_eq!(B::count(), 0);
1046 assert_eq!(B::initialize_counter(), 0);
1047
1048 B::insert(1, 1);
1049 B::insert(2, 2);
1050
1051 assert_eq!(B::iter_values().collect::<Vec<_>>(), vec![2, 1]);
1053
1054 assert_eq!(B::iter_values().drain().collect::<Vec<_>>(), vec![2, 1]);
1056 assert_eq!(B::count(), 0);
1057
1058 B::insert(1, 1);
1059 B::insert(2, 2);
1060
1061 assert_eq!(B::initialize_counter(), 2);
1063
1064 B::set(30, Some(100));
1066
1067 assert_eq!(B::contains_key(30), true);
1068 assert_eq!(B::get(30), Some(100));
1069 assert_eq!(B::try_get(30), Ok(100));
1070 assert_eq!(B::count(), 3);
1071
1072 B::set(30, Some(101));
1074
1075 assert_eq!(B::contains_key(30), true);
1076 assert_eq!(B::get(30), Some(101));
1077 assert_eq!(B::try_get(30), Ok(101));
1078 assert_eq!(B::count(), 3);
1079
1080 B::set(30, None);
1082
1083 assert_eq!(B::contains_key(30), false);
1084 assert_eq!(B::get(30), None);
1085 assert_eq!(B::try_get(30), Err(()));
1086
1087 assert_eq!(B::count(), 2);
1088
1089 B::set(31, None);
1091
1092 assert_eq!(B::contains_key(31), false);
1093 assert_eq!(B::get(31), None);
1094 assert_eq!(B::try_get(31), Err(()));
1095
1096 assert_eq!(B::count(), 2);
1097 })
1098 }
1099
1100 #[test]
1101 fn append_decode_len_works() {
1102 type B = CountedStorageMap<Prefix, Twox64Concat, u16, Vec<u32>>;
1103
1104 TestExternalities::default().execute_with(|| {
1105 assert_eq!(B::decode_len(0), None);
1106 B::append(0, 3);
1107 assert_eq!(B::decode_len(0), Some(1));
1108 B::append(0, 3);
1109 assert_eq!(B::decode_len(0), Some(2));
1110 B::append(0, 3);
1111 assert_eq!(B::decode_len(0), Some(3));
1112 })
1113 }
1114
1115 #[test]
1116 fn try_append_decode_len_works() {
1117 type B = CountedStorageMap<Prefix, Twox64Concat, u16, BoundedVec<u32, ConstU32<3u32>>>;
1118
1119 TestExternalities::default().execute_with(|| {
1120 assert_eq!(B::decode_len(0), None);
1121 B::try_append(0, 3).unwrap();
1122 assert_eq!(B::decode_len(0), Some(1));
1123 B::try_append(0, 3).unwrap();
1124 assert_eq!(B::decode_len(0), Some(2));
1125 B::try_append(0, 3).unwrap();
1126 assert_eq!(B::decode_len(0), Some(3));
1127 B::try_append(0, 3).err().unwrap();
1128 assert_eq!(B::decode_len(0), Some(3));
1129 })
1130 }
1131
1132 #[test]
1133 fn migrate_keys_works() {
1134 type A = CountedStorageMap<Prefix, Twox64Concat, u16, u32>;
1135 type B = CountedStorageMap<Prefix, Blake2_128Concat, u16, u32>;
1136 TestExternalities::default().execute_with(|| {
1137 A::insert(1, 1);
1138 assert_eq!(B::migrate_key::<Twox64Concat, _>(1), Some(1));
1139 assert_eq!(B::get(1), Some(1));
1140 })
1141 }
1142
1143 #[test]
1144 fn translate_values() {
1145 type A = CountedStorageMap<Prefix, Twox64Concat, u16, u32>;
1146 TestExternalities::default().execute_with(|| {
1147 A::insert(1, 1);
1148 A::insert(2, 2);
1149 A::translate_values::<u32, _>(|old_value| if old_value == 1 { None } else { Some(1) });
1150 assert_eq!(A::count(), 1);
1151 assert_eq!(A::get(2), Some(1));
1152 })
1153 }
1154
1155 #[test]
1156 fn test_iter_drain_translate() {
1157 type A = CountedStorageMap<Prefix, Twox64Concat, u16, u32>;
1158 TestExternalities::default().execute_with(|| {
1159 A::insert(1, 1);
1160 A::insert(2, 2);
1161
1162 assert_eq!(A::iter().collect::<Vec<_>>(), vec![(2, 2), (1, 1)]);
1163
1164 assert_eq!(A::count(), 2);
1165
1166 A::translate::<u32, _>(
1167 |key, value| if key == 1 { None } else { Some(key as u32 * value) },
1168 );
1169
1170 assert_eq!(A::count(), 1);
1171
1172 assert_eq!(A::drain().collect::<Vec<_>>(), vec![(2, 4)]);
1173
1174 assert_eq!(A::count(), 0);
1175 })
1176 }
1177
1178 #[test]
1179 fn test_iter_from() {
1180 type A = CountedStorageMap<Prefix, Twox64Concat, u16, u32>;
1181 TestExternalities::default().execute_with(|| {
1182 A::insert(1, 1);
1183 A::insert(2, 2);
1184 A::insert(3, 3);
1185 A::insert(4, 4);
1186
1187 assert_eq!(A::iter_from(vec![]).collect::<Vec<_>>(), A::iter().collect::<Vec<_>>());
1189
1190 let iter_all = A::iter().collect::<Vec<_>>();
1191 let (before, after) = iter_all.split_at(2);
1192 let last_key = before.last().map(|(k, _)| k).unwrap();
1193 assert_eq!(A::iter_from(A::hashed_key_for(last_key)).collect::<Vec<_>>(), after);
1194 })
1195 }
1196
1197 #[test]
1198 fn test_metadata() {
1199 type A = CountedStorageMap<Prefix, Twox64Concat, u16, u32, ValueQuery, ADefault>;
1200 let mut entries = vec![];
1201 A::build_metadata(
1202 sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
1203 vec![],
1204 &mut entries,
1205 );
1206 assert_eq!(
1207 entries,
1208 vec![
1209 StorageEntryMetadataIR {
1210 name: "foo",
1211 modifier: StorageEntryModifierIR::Default,
1212 ty: StorageEntryTypeIR::Map {
1213 hashers: vec![StorageHasherIR::Twox64Concat],
1214 key: scale_info::meta_type::<u16>(),
1215 value: scale_info::meta_type::<u32>(),
1216 },
1217 default: 97u32.encode(),
1218 docs: vec![],
1219 deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
1220 },
1221 StorageEntryMetadataIR {
1222 name: "counter_for_foo",
1223 modifier: StorageEntryModifierIR::Default,
1224 ty: StorageEntryTypeIR::Plain(scale_info::meta_type::<Counter>()),
1225 default: vec![0, 0, 0, 0],
1226 docs: if cfg!(feature = "no-metadata-docs") {
1227 vec![]
1228 } else {
1229 vec!["Counter for the related counted storage map"]
1230 },
1231 deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
1232 },
1233 ]
1234 );
1235 }
1236
1237 #[docify::export]
1238 #[test]
1239 fn test_simple_count_works() {
1240 type FooCountedMap = CountedStorageMap<Prefix, Twox64Concat, u16, u32>;
1241 TestExternalities::default().execute_with(|| {
1242 FooCountedMap::insert(1, 1);
1243 FooCountedMap::insert(2, 2);
1244 assert_eq!(FooCountedMap::count(), 2);
1245 });
1246 }
1247}