pallet macro: allow to declare individual unbounded storage for those who cannot go into PoV (#9670)

* allow unbounded individual storage

* better doc

* fix UI tests

* update doc

* Update frame/support/procedural/src/pallet/parse/storage.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
Guillaume Thiolliere
2021-09-27 10:25:24 +02:00
committed by GitHub
parent d565382b50
commit 1ebcbe1c34
7 changed files with 106 additions and 44 deletions
@@ -27,6 +27,7 @@ mod keyword {
syn::custom_keyword!(pallet);
syn::custom_keyword!(getter);
syn::custom_keyword!(storage_prefix);
syn::custom_keyword!(unbounded);
syn::custom_keyword!(OptionQuery);
syn::custom_keyword!(ValueQuery);
}
@@ -34,15 +35,17 @@ mod keyword {
/// Parse for one of the following:
/// * `#[pallet::getter(fn dummy)]`
/// * `#[pallet::storage_prefix = "CustomName"]`
/// * `#[pallet::unbounded]`
pub enum PalletStorageAttr {
Getter(syn::Ident, proc_macro2::Span),
StorageName(syn::LitStr, proc_macro2::Span),
Unbounded(proc_macro2::Span),
}
impl PalletStorageAttr {
fn attr_span(&self) -> proc_macro2::Span {
match self {
Self::Getter(_, span) | Self::StorageName(_, span) => *span,
Self::Getter(_, span) | Self::StorageName(_, span) | Self::Unbounded(span) => *span,
}
}
}
@@ -76,12 +79,45 @@ impl syn::parse::Parse for PalletStorageAttr {
})?;
Ok(Self::StorageName(renamed_prefix, attr_span))
} else if lookahead.peek(keyword::unbounded) {
content.parse::<keyword::unbounded>()?;
Ok(Self::Unbounded(attr_span))
} else {
Err(lookahead.error())
}
}
}
struct PalletStorageAttrInfo {
getter: Option<syn::Ident>,
rename_as: Option<syn::LitStr>,
unbounded: bool,
}
impl PalletStorageAttrInfo {
fn from_attrs(attrs: Vec<PalletStorageAttr>) -> syn::Result<Self> {
let mut getter = None;
let mut rename_as = None;
let mut unbounded = false;
for attr in attrs {
match attr {
PalletStorageAttr::Getter(ident, ..) if getter.is_none() => getter = Some(ident),
PalletStorageAttr::StorageName(name, ..) if rename_as.is_none() =>
rename_as = Some(name),
PalletStorageAttr::Unbounded(..) if !unbounded => unbounded = true,
attr =>
return Err(syn::Error::new(
attr.attr_span(),
"Invalid attribute: Duplicate attribute",
)),
}
}
Ok(PalletStorageAttrInfo { getter, rename_as, unbounded })
}
}
/// The value and key types used by storages. Needed to expand metadata.
pub enum Metadata {
Value { value: syn::Type },
@@ -131,6 +167,8 @@ pub struct StorageDef {
/// generics of the storage.
/// If generics are not named, this is none.
pub named_generics: Option<StorageGenerics>,
/// If the value stored in this storage is unbounded.
pub unbounded: bool,
}
/// The parsed generic from the
@@ -629,25 +667,8 @@ impl StorageDef {
};
let attrs: Vec<PalletStorageAttr> = helper::take_item_pallet_attrs(&mut item.attrs)?;
let (mut getters, mut names) = attrs
.into_iter()
.partition::<Vec<_>, _>(|attr| matches!(attr, PalletStorageAttr::Getter(..)));
if getters.len() > 1 {
let msg = "Invalid pallet::storage, multiple argument pallet::getter found";
return Err(syn::Error::new(getters[1].attr_span(), msg))
}
if names.len() > 1 {
let msg = "Invalid pallet::storage, multiple argument pallet::storage_prefix found";
return Err(syn::Error::new(names[1].attr_span(), msg))
}
let getter = getters.pop().map(|attr| match attr {
PalletStorageAttr::Getter(ident, _) => ident,
_ => unreachable!(),
});
let rename_as = names.pop().map(|attr| match attr {
PalletStorageAttr::StorageName(lit, _) => lit,
_ => unreachable!(),
});
let PalletStorageAttrInfo { getter, rename_as, unbounded } =
PalletStorageAttrInfo::from_attrs(attrs)?;
let cfg_attrs = helper::get_item_cfg_attrs(&item.attrs);
@@ -704,6 +725,7 @@ impl StorageDef {
where_clause,
cfg_attrs,
named_generics,
unbounded,
})
}
}