Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit a1d42aa

Browse files
ruseinovbkchr
andauthored
[Feature] Introduce storage_alias for CountedStorageMap (#13366)
* [Feature] Introduce storagage_alias for CountedStorageMap * bit more dry * bit more dry * address review comments * some tests and fixes * fix ui tests * Apply suggestions from code review Co-authored-by: Bastian Köcher <[email protected]> * compare metadata --------- Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher <[email protected]>
1 parent 1cc2a00 commit a1d42aa

File tree

6 files changed

+119
-13
lines changed

6 files changed

+119
-13
lines changed

frame/support/procedural/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ fn get_cargo_env_var<T: FromStr>(version_env: &str) -> std::result::Result<T, ()
6969
T::from_str(&version).map_err(drop)
7070
}
7171

72+
/// Generate the counter_prefix related to the storage.
73+
/// counter_prefix is used by counted storage map.
74+
fn counter_prefix(prefix: &str) -> String {
75+
format!("CounterFor{}", prefix)
76+
}
77+
7278
/// Declares strongly-typed wrappers around codec-compatible types in storage.
7379
///
7480
/// ## Example

frame/support/procedural/src/pallet/expand/storage.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
// See the License for the specific language governing permissions and
1616
// limitations under the License.
1717

18-
use crate::pallet::{
19-
parse::storage::{Metadata, QueryKind, StorageDef, StorageGenerics},
20-
Def,
18+
use crate::{
19+
counter_prefix,
20+
pallet::{
21+
parse::storage::{Metadata, QueryKind, StorageDef, StorageGenerics},
22+
Def,
23+
},
2124
};
2225
use quote::ToTokens;
2326
use std::{collections::HashMap, ops::IndexMut};
@@ -39,12 +42,6 @@ fn counter_prefix_ident(storage_ident: &syn::Ident) -> syn::Ident {
3942
)
4043
}
4144

42-
/// Generate the counter_prefix related to the storage.
43-
/// counter_prefix is used by counted storage map.
44-
fn counter_prefix(prefix: &str) -> String {
45-
format!("CounterFor{}", prefix)
46-
}
47-
4845
/// Check for duplicated storage prefixes. This step is necessary since users can specify an
4946
/// alternative storage prefix using the #[pallet::storage_prefix] syntax, and we need to ensure
5047
/// that the prefix specified by the user is not a duplicate of an existing one.

frame/support/procedural/src/storage_alias.rs

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
//! Implementation of the `storage_alias` attribute macro.
1919
20+
use crate::counter_prefix;
2021
use frame_support_procedural_tools::generate_crate_access_2018;
2122
use proc_macro2::{Span, TokenStream};
2223
use quote::{quote, ToTokens};
@@ -136,6 +137,7 @@ impl ToTokens for SimpleGenerics {
136137
mod storage_types {
137138
syn::custom_keyword!(StorageValue);
138139
syn::custom_keyword!(StorageMap);
140+
syn::custom_keyword!(CountedStorageMap);
139141
syn::custom_keyword!(StorageDoubleMap);
140142
syn::custom_keyword!(StorageNMap);
141143
}
@@ -168,6 +170,21 @@ enum StorageType {
168170
_trailing_comma: Option<Token![,]>,
169171
_gt_token: Token![>],
170172
},
173+
CountedMap {
174+
_kw: storage_types::CountedStorageMap,
175+
_lt_token: Token![<],
176+
prefix: SimplePath,
177+
prefix_generics: Option<TypeGenerics>,
178+
_hasher_comma: Token![,],
179+
hasher_ty: Type,
180+
_key_comma: Token![,],
181+
key_ty: Type,
182+
_value_comma: Token![,],
183+
value_ty: Type,
184+
query_type: Option<(Token![,], Type)>,
185+
_trailing_comma: Option<Token![,]>,
186+
_gt_token: Token![>],
187+
},
171188
DoubleMap {
172189
_kw: storage_types::StorageDoubleMap,
173190
_lt_token: Token![<],
@@ -235,12 +252,22 @@ impl StorageType {
235252
>;
236253
}
237254
},
255+
Self::CountedMap {
256+
value_ty, query_type, hasher_ty, key_ty, prefix_generics, ..
257+
} |
238258
Self::Map { value_ty, query_type, hasher_ty, key_ty, prefix_generics, .. } => {
239259
let query_type = query_type.as_ref().map(|(c, t)| quote!(#c #t));
260+
let map_type = Ident::new(
261+
match self {
262+
Self::Map { .. } => "StorageMap",
263+
_ => "CountedStorageMap",
264+
},
265+
Span::call_site(),
266+
);
240267

241268
quote! {
242269
#( #attributes )*
243-
#visibility type #storage_name #storage_generics = #crate_::storage::types::StorageMap<
270+
#visibility type #storage_name #storage_generics = #crate_::storage::types::#map_type<
244271
#storage_instance #prefix_generics,
245272
#hasher_ty,
246273
#key_ty,
@@ -296,6 +323,7 @@ impl StorageType {
296323
match self {
297324
Self::Value { prefix, .. } |
298325
Self::Map { prefix, .. } |
326+
Self::CountedMap { prefix, .. } |
299327
Self::NMap { prefix, .. } |
300328
Self::DoubleMap { prefix, .. } => prefix,
301329
}
@@ -306,6 +334,7 @@ impl StorageType {
306334
match self {
307335
Self::Value { prefix_generics, .. } |
308336
Self::Map { prefix_generics, .. } |
337+
Self::CountedMap { prefix_generics, .. } |
309338
Self::NMap { prefix_generics, .. } |
310339
Self::DoubleMap { prefix_generics, .. } => prefix_generics.as_ref(),
311340
}
@@ -363,6 +392,22 @@ impl Parse for StorageType {
363392
_trailing_comma: input.peek(Token![,]).then(|| input.parse()).transpose()?,
364393
_gt_token: input.parse()?,
365394
})
395+
} else if lookahead.peek(storage_types::CountedStorageMap) {
396+
Ok(Self::CountedMap {
397+
_kw: input.parse()?,
398+
_lt_token: input.parse()?,
399+
prefix: input.parse()?,
400+
prefix_generics: parse_pallet_generics(input)?,
401+
_hasher_comma: input.parse()?,
402+
hasher_ty: input.parse()?,
403+
_key_comma: input.parse()?,
404+
key_ty: input.parse()?,
405+
_value_comma: input.parse()?,
406+
value_ty: input.parse()?,
407+
query_type: parse_query_type(input)?,
408+
_trailing_comma: input.peek(Token![,]).then(|| input.parse()).transpose()?,
409+
_gt_token: input.parse()?,
410+
})
366411
} else if lookahead.peek(storage_types::StorageDoubleMap) {
367412
Ok(Self::DoubleMap {
368413
_kw: input.parse()?,
@@ -476,6 +521,7 @@ pub fn storage_alias(input: TokenStream) -> Result<TokenStream> {
476521
input.storage_type.prefix(),
477522
input.storage_type.prefix_generics(),
478523
&input.visibility,
524+
matches!(input.storage_type, StorageType::CountedMap { .. }),
479525
)?;
480526

481527
let definition = input.storage_type.generate_type_declaration(
@@ -511,6 +557,7 @@ fn generate_storage_instance(
511557
prefix: &SimplePath,
512558
prefix_generics: Option<&TypeGenerics>,
513559
visibility: &Visibility,
560+
is_counted_map: bool,
514561
) -> Result<StorageInstance> {
515562
if let Some(ident) = prefix.get_ident().filter(|i| *i == "_") {
516563
return Err(Error::new(ident.span(), "`_` is not allowed as prefix by `storage_alias`."))
@@ -546,9 +593,37 @@ fn generate_storage_instance(
546593

547594
let where_clause = storage_where_clause.map(|w| quote!(#w)).unwrap_or_default();
548595

549-
let name = Ident::new(&format!("{}_Storage_Instance", storage_name), Span::call_site());
596+
let name_str = format!("{}_Storage_Instance", storage_name);
597+
let name = Ident::new(&name_str, Span::call_site());
550598
let storage_name_str = storage_name.to_string();
551599

600+
let counter_code = is_counted_map.then(|| {
601+
let counter_name = Ident::new(&counter_prefix(&name_str), Span::call_site());
602+
let counter_storage_name_str = counter_prefix(&storage_name_str);
603+
604+
quote! {
605+
#visibility struct #counter_name< #impl_generics >(
606+
#crate_::sp_std::marker::PhantomData<(#type_generics)>
607+
) #where_clause;
608+
609+
impl<#impl_generics> #crate_::traits::StorageInstance
610+
for #counter_name< #type_generics > #where_clause
611+
{
612+
fn pallet_prefix() -> &'static str {
613+
#pallet_prefix
614+
}
615+
616+
const STORAGE_PREFIX: &'static str = #counter_storage_name_str;
617+
}
618+
619+
impl<#impl_generics> #crate_::storage::types::CountedStorageMapInstance
620+
for #name< #type_generics > #where_clause
621+
{
622+
type CounterPrefix = #counter_name < #type_generics >;
623+
}
624+
}
625+
});
626+
552627
// Implement `StorageInstance` trait.
553628
let code = quote! {
554629
#visibility struct #name< #impl_generics >(
@@ -564,6 +639,8 @@ fn generate_storage_instance(
564639

565640
const STORAGE_PREFIX: &'static str = #storage_name_str;
566641
}
642+
643+
#counter_code
567644
};
568645

569646
Ok(StorageInstance { name, code })

frame/support/src/storage/types/counted_map.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,16 @@ mod test {
543543
97
544544
}
545545
}
546+
#[crate::storage_alias]
547+
type ExampleCountedMap = CountedStorageMap<Prefix, Twox64Concat, u16, u32>;
548+
549+
#[test]
550+
fn storage_alias_works() {
551+
TestExternalities::default().execute_with(|| {
552+
assert_eq!(ExampleCountedMap::count(), 0);
553+
ExampleCountedMap::insert(3, 10);
554+
})
555+
}
546556

547557
#[test]
548558
fn test_value_query() {

frame/support/test/tests/pallet.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use frame_support::{
1919
dispatch::{
2020
DispatchClass, DispatchInfo, GetDispatchInfo, Parameter, Pays, UnfilteredDispatchable,
2121
},
22-
pallet_prelude::ValueQuery,
22+
pallet_prelude::{StorageInfoTrait, ValueQuery},
2323
storage::unhashed,
2424
traits::{
2525
ConstU32, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize,
@@ -1906,14 +1906,30 @@ fn assert_type_all_pallets_without_system_reversed_is_correct() {
19061906

19071907
#[test]
19081908
fn test_storage_alias() {
1909+
use frame_support::Twox64Concat;
1910+
19091911
#[frame_support::storage_alias]
19101912
type Value<T: pallet::Config>
19111913
where
19121914
<T as frame_system::Config>::AccountId: From<SomeType1> + SomeAssociation1,
19131915
= StorageValue<pallet::Pallet<T>, u32, ValueQuery>;
19141916

1917+
#[frame_support::storage_alias]
1918+
type SomeCountedStorageMap<T: pallet2::Config>
1919+
where
1920+
<T as frame_system::Config>::AccountId: From<SomeType1> + SomeAssociation1,
1921+
= CountedStorageMap<pallet2::Pallet<T>, Twox64Concat, u8, u32>;
1922+
19151923
TestExternalities::default().execute_with(|| {
19161924
pallet::Value::<Runtime>::put(10);
19171925
assert_eq!(10, Value::<Runtime>::get());
1926+
1927+
pallet2::SomeCountedStorageMap::<Runtime>::insert(10, 100);
1928+
assert_eq!(Some(100), SomeCountedStorageMap::<Runtime>::get(10));
1929+
assert_eq!(1, SomeCountedStorageMap::<Runtime>::count());
1930+
assert_eq!(
1931+
SomeCountedStorageMap::<Runtime>::storage_info(),
1932+
pallet2::SomeCountedStorageMap::<Runtime>::storage_info()
1933+
);
19181934
})
19191935
}

frame/support/test/tests/storage_alias_ui/forbid_underscore_as_prefix.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: expected one of: `StorageValue`, `StorageMap`, `StorageDoubleMap`, `StorageNMap`
1+
error: expected one of: `StorageValue`, `StorageMap`, `CountedStorageMap`, `StorageDoubleMap`, `StorageNMap`
22
--> tests/storage_alias_ui/forbid_underscore_as_prefix.rs:2:14
33
|
44
2 | type Ident = CustomStorage<Hello, u32>;

0 commit comments

Comments
 (0)