mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 11:38:01 +00:00
Implement ResultQuery (#11257)
* Implement ResultQuery * Fix test expectations * Add more tests * Fix test expectations * Clean up some names * Silence warnings * Specify error type when supplying error type to ResultQuery * cargo fmt * Add support for type parameters in parameter_types macro * Reduce deeply indented code * Fixes * Update test expectation * Rewrite and document formula for calculating max storage size * More docs * cargo fmt * formatting Co-authored-by: parity-processbot <>
This commit is contained in:
@@ -19,7 +19,9 @@ use crate::pallet::{
|
||||
parse::storage::{Metadata, QueryKind, StorageDef, StorageGenerics},
|
||||
Def,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use quote::ToTokens;
|
||||
use std::{collections::HashMap, ops::IndexMut};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Generate the prefix_ident related to the storage.
|
||||
/// prefix_ident is used for the prefix struct to be given to storage as first generic param.
|
||||
@@ -84,12 +86,28 @@ fn check_prefix_duplicates(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct ResultOnEmptyStructMetadata {
|
||||
/// The Rust ident that is going to be used as the name of the OnEmpty struct.
|
||||
pub name: syn::Ident,
|
||||
/// The path to the error type being returned by the ResultQuery.
|
||||
pub error_path: syn::Path,
|
||||
/// The visibility of the OnEmpty struct.
|
||||
pub visibility: syn::Visibility,
|
||||
/// The type of the storage item.
|
||||
pub value_ty: syn::Type,
|
||||
/// The name of the pallet error enum variant that is going to be returned.
|
||||
pub variant_name: syn::Ident,
|
||||
/// The span used to report compilation errors about the OnEmpty struct.
|
||||
pub span: proc_macro2::Span,
|
||||
}
|
||||
|
||||
///
|
||||
/// * if generics are unnamed: replace the first generic `_` by the generated prefix structure
|
||||
/// * if generics are named: reorder the generic, remove their name, and add the missing ones.
|
||||
/// * Add `#[allow(type_alias_bounds)]`
|
||||
pub fn process_generics(def: &mut Def) -> syn::Result<()> {
|
||||
pub fn process_generics(def: &mut Def) -> syn::Result<Vec<ResultOnEmptyStructMetadata>> {
|
||||
let frame_support = &def.frame_support;
|
||||
let mut on_empty_struct_metadata = Vec::new();
|
||||
|
||||
for storage_def in def.storages.iter_mut() {
|
||||
let item = &mut def.item.content.as_mut().expect("Checked by def").1[storage_def.index];
|
||||
@@ -120,27 +138,72 @@ pub fn process_generics(def: &mut Def) -> syn::Result<()> {
|
||||
|
||||
let default_query_kind: syn::Type =
|
||||
syn::parse_quote!(#frame_support::storage::types::OptionQuery);
|
||||
let default_on_empty: syn::Type = syn::parse_quote!(#frame_support::traits::GetDefault);
|
||||
let mut default_on_empty = |value_ty: syn::Type| -> syn::Type {
|
||||
if let Some(QueryKind::ResultQuery(error_path, variant_name)) =
|
||||
storage_def.query_kind.as_ref()
|
||||
{
|
||||
let on_empty_ident =
|
||||
quote::format_ident!("__Frame_Internal_Get{}Result", storage_def.ident);
|
||||
on_empty_struct_metadata.push(ResultOnEmptyStructMetadata {
|
||||
name: on_empty_ident.clone(),
|
||||
visibility: storage_def.vis.clone(),
|
||||
value_ty,
|
||||
error_path: error_path.clone(),
|
||||
variant_name: variant_name.clone(),
|
||||
span: storage_def.attr_span,
|
||||
});
|
||||
return syn::parse_quote!(#on_empty_ident)
|
||||
}
|
||||
syn::parse_quote!(#frame_support::traits::GetDefault)
|
||||
};
|
||||
let default_max_values: syn::Type = syn::parse_quote!(#frame_support::traits::GetDefault);
|
||||
|
||||
let set_result_query_type_parameter = |query_type: &mut syn::Type| -> syn::Result<()> {
|
||||
if let Some(QueryKind::ResultQuery(error_path, _)) = storage_def.query_kind.as_ref() {
|
||||
if let syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. }) =
|
||||
query_type
|
||||
{
|
||||
if let Some(seg) = segments.last_mut() {
|
||||
if let syn::PathArguments::AngleBracketed(
|
||||
syn::AngleBracketedGenericArguments { args, .. },
|
||||
) = &mut seg.arguments
|
||||
{
|
||||
args.clear();
|
||||
args.push(syn::GenericArgument::Type(syn::parse_quote!(#error_path)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let msg = format!(
|
||||
"Invalid pallet::storage, unexpected type for query, expected ResultQuery \
|
||||
with 1 type parameter, found `{}`",
|
||||
query_type.to_token_stream().to_string()
|
||||
);
|
||||
return Err(syn::Error::new(query_type.span(), msg))
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
|
||||
if let Some(named_generics) = storage_def.named_generics.clone() {
|
||||
args.args.clear();
|
||||
args.args.push(syn::parse_quote!( #prefix_ident<#type_use_gen> ));
|
||||
match named_generics {
|
||||
StorageGenerics::Value { value, query_kind, on_empty } => {
|
||||
args.args.push(syn::GenericArgument::Type(value));
|
||||
let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
args.args.push(syn::GenericArgument::Type(value.clone()));
|
||||
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
set_result_query_type_parameter(&mut query_kind)?;
|
||||
args.args.push(syn::GenericArgument::Type(query_kind));
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone());
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
|
||||
args.args.push(syn::GenericArgument::Type(on_empty));
|
||||
},
|
||||
StorageGenerics::Map { hasher, key, value, query_kind, on_empty, max_values } => {
|
||||
args.args.push(syn::GenericArgument::Type(hasher));
|
||||
args.args.push(syn::GenericArgument::Type(key));
|
||||
args.args.push(syn::GenericArgument::Type(value));
|
||||
let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
args.args.push(syn::GenericArgument::Type(value.clone()));
|
||||
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
set_result_query_type_parameter(&mut query_kind)?;
|
||||
args.args.push(syn::GenericArgument::Type(query_kind));
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone());
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
|
||||
args.args.push(syn::GenericArgument::Type(on_empty));
|
||||
let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
|
||||
args.args.push(syn::GenericArgument::Type(max_values));
|
||||
@@ -155,10 +218,11 @@ pub fn process_generics(def: &mut Def) -> syn::Result<()> {
|
||||
} => {
|
||||
args.args.push(syn::GenericArgument::Type(hasher));
|
||||
args.args.push(syn::GenericArgument::Type(key));
|
||||
args.args.push(syn::GenericArgument::Type(value));
|
||||
let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
args.args.push(syn::GenericArgument::Type(value.clone()));
|
||||
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
set_result_query_type_parameter(&mut query_kind)?;
|
||||
args.args.push(syn::GenericArgument::Type(query_kind));
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone());
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
|
||||
args.args.push(syn::GenericArgument::Type(on_empty));
|
||||
let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
|
||||
args.args.push(syn::GenericArgument::Type(max_values));
|
||||
@@ -177,20 +241,22 @@ pub fn process_generics(def: &mut Def) -> syn::Result<()> {
|
||||
args.args.push(syn::GenericArgument::Type(key1));
|
||||
args.args.push(syn::GenericArgument::Type(hasher2));
|
||||
args.args.push(syn::GenericArgument::Type(key2));
|
||||
args.args.push(syn::GenericArgument::Type(value));
|
||||
let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
args.args.push(syn::GenericArgument::Type(value.clone()));
|
||||
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
set_result_query_type_parameter(&mut query_kind)?;
|
||||
args.args.push(syn::GenericArgument::Type(query_kind));
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone());
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
|
||||
args.args.push(syn::GenericArgument::Type(on_empty));
|
||||
let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
|
||||
args.args.push(syn::GenericArgument::Type(max_values));
|
||||
},
|
||||
StorageGenerics::NMap { keygen, value, query_kind, on_empty, max_values } => {
|
||||
args.args.push(syn::GenericArgument::Type(keygen));
|
||||
args.args.push(syn::GenericArgument::Type(value));
|
||||
let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
args.args.push(syn::GenericArgument::Type(value.clone()));
|
||||
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
set_result_query_type_parameter(&mut query_kind)?;
|
||||
args.args.push(syn::GenericArgument::Type(query_kind));
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone());
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
|
||||
args.args.push(syn::GenericArgument::Type(on_empty));
|
||||
let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
|
||||
args.args.push(syn::GenericArgument::Type(max_values));
|
||||
@@ -198,10 +264,40 @@ pub fn process_generics(def: &mut Def) -> syn::Result<()> {
|
||||
}
|
||||
} else {
|
||||
args.args[0] = syn::parse_quote!( #prefix_ident<#type_use_gen> );
|
||||
|
||||
let (value_idx, query_idx, on_empty_idx) = match storage_def.metadata {
|
||||
Metadata::Value { .. } => (1, 2, 3),
|
||||
Metadata::NMap { .. } => (2, 3, 4),
|
||||
Metadata::Map { .. } | Metadata::CountedMap { .. } => (3, 4, 5),
|
||||
Metadata::DoubleMap { .. } => (5, 6, 7),
|
||||
};
|
||||
|
||||
if query_idx < args.args.len() {
|
||||
if let syn::GenericArgument::Type(query_kind) = args.args.index_mut(query_idx) {
|
||||
set_result_query_type_parameter(query_kind)?;
|
||||
}
|
||||
} else if let Some(QueryKind::ResultQuery(error_path, _)) =
|
||||
storage_def.query_kind.as_ref()
|
||||
{
|
||||
args.args.push(syn::GenericArgument::Type(syn::parse_quote!(#error_path)))
|
||||
}
|
||||
|
||||
// Here, we only need to check if OnEmpty is *not* specified, and if so, then we have to
|
||||
// generate a default OnEmpty struct for it.
|
||||
if on_empty_idx >= args.args.len() &&
|
||||
matches!(storage_def.query_kind.as_ref(), Some(QueryKind::ResultQuery(_, _)))
|
||||
{
|
||||
let value_ty = match args.args[value_idx].clone() {
|
||||
syn::GenericArgument::Type(ty) => ty,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let on_empty = default_on_empty(value_ty);
|
||||
args.args.push(syn::GenericArgument::Type(on_empty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(on_empty_struct_metadata)
|
||||
}
|
||||
|
||||
///
|
||||
@@ -212,9 +308,10 @@ pub fn process_generics(def: &mut Def) -> syn::Result<()> {
|
||||
/// * Add `#[allow(type_alias_bounds)]` on storages type alias
|
||||
/// * generate metadatas
|
||||
pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
if let Err(e) = process_generics(def) {
|
||||
return e.into_compile_error()
|
||||
}
|
||||
let on_empty_struct_metadata = match process_generics(def) {
|
||||
Ok(idents) => idents,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
|
||||
// Check for duplicate prefixes
|
||||
let mut prefix_set = HashMap::new();
|
||||
@@ -277,6 +374,10 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ResultQuery(error_path, _) =>
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
Result<#value, #error_path>
|
||||
),
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
@@ -296,6 +397,10 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ResultQuery(error_path, _) =>
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
Result<#value, #error_path>
|
||||
),
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
@@ -317,6 +422,10 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ResultQuery(error_path, _) =>
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
Result<#value, #error_path>
|
||||
),
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
@@ -338,6 +447,10 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ResultQuery(error_path, _) =>
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
Result<#value, #error_path>
|
||||
),
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
@@ -361,6 +474,10 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ResultQuery(error_path, _) =>
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
Result<#value, #error_path>
|
||||
),
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
@@ -459,6 +576,61 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
)
|
||||
});
|
||||
|
||||
let on_empty_structs = on_empty_struct_metadata.into_iter().map(|metadata| {
|
||||
use crate::pallet::parse::GenericKind;
|
||||
use syn::{GenericArgument, Path, PathArguments, PathSegment, Type, TypePath};
|
||||
|
||||
let ResultOnEmptyStructMetadata {
|
||||
name,
|
||||
visibility,
|
||||
value_ty,
|
||||
error_path,
|
||||
variant_name,
|
||||
span,
|
||||
} = metadata;
|
||||
|
||||
let generic_kind = match error_path.segments.last() {
|
||||
Some(PathSegment { arguments: PathArguments::AngleBracketed(args), .. }) => {
|
||||
let (has_config, has_instance) =
|
||||
args.args.iter().fold((false, false), |(has_config, has_instance), arg| {
|
||||
match arg {
|
||||
GenericArgument::Type(Type::Path(TypePath {
|
||||
path: Path { segments, .. },
|
||||
..
|
||||
})) => {
|
||||
let maybe_config =
|
||||
segments.first().map_or(false, |seg| seg.ident == "T");
|
||||
let maybe_instance =
|
||||
segments.first().map_or(false, |seg| seg.ident == "I");
|
||||
|
||||
(has_config || maybe_config, has_instance || maybe_instance)
|
||||
},
|
||||
_ => (has_config, has_instance),
|
||||
}
|
||||
});
|
||||
GenericKind::from_gens(has_config, has_instance).unwrap_or(GenericKind::None)
|
||||
},
|
||||
_ => GenericKind::None,
|
||||
};
|
||||
let type_impl_gen = generic_kind.type_impl_gen(proc_macro2::Span::call_site());
|
||||
let config_where_clause = &def.config.where_clause;
|
||||
|
||||
quote::quote_spanned!(span =>
|
||||
#[doc(hidden)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#visibility struct #name;
|
||||
|
||||
impl<#type_impl_gen> #frame_support::traits::Get<Result<#value_ty, #error_path>>
|
||||
for #name
|
||||
#config_where_clause
|
||||
{
|
||||
fn get() -> Result<#value_ty, #error_path> {
|
||||
Err(<#error_path>::#variant_name)
|
||||
}
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
let mut where_clauses = vec![&def.config.where_clause];
|
||||
where_clauses.extend(def.storages.iter().map(|storage| &storage.where_clause));
|
||||
let completed_where_clause = super::merge_where_clauses(&where_clauses);
|
||||
@@ -489,5 +661,6 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
|
||||
#( #getters )*
|
||||
#( #prefix_structs )*
|
||||
#( #on_empty_structs )*
|
||||
)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ mod keyword {
|
||||
syn::custom_keyword!(storage_prefix);
|
||||
syn::custom_keyword!(unbounded);
|
||||
syn::custom_keyword!(OptionQuery);
|
||||
syn::custom_keyword!(ResultQuery);
|
||||
syn::custom_keyword!(ValueQuery);
|
||||
}
|
||||
|
||||
@@ -129,6 +130,7 @@ pub enum Metadata {
|
||||
|
||||
pub enum QueryKind {
|
||||
OptionQuery,
|
||||
ResultQuery(syn::Path, syn::Ident),
|
||||
ValueQuery,
|
||||
}
|
||||
|
||||
@@ -153,7 +155,7 @@ pub struct StorageDef {
|
||||
/// Optional expression that evaluates to a type that can be used as StoragePrefix instead of
|
||||
/// ident.
|
||||
pub rename_as: Option<syn::LitStr>,
|
||||
/// Whereas the querytype of the storage is OptionQuery or ValueQuery.
|
||||
/// Whereas the querytype of the storage is OptionQuery, ResultQuery or ValueQuery.
|
||||
/// Note that this is best effort as it can't be determined when QueryKind is generic, and
|
||||
/// result can be false if user do some unexpected type alias.
|
||||
pub query_kind: Option<QueryKind>,
|
||||
@@ -695,21 +697,105 @@ impl StorageDef {
|
||||
let (named_generics, metadata, query_kind) = process_generics(&typ.path.segments[0])?;
|
||||
|
||||
let query_kind = query_kind
|
||||
.map(|query_kind| match query_kind {
|
||||
syn::Type::Path(path)
|
||||
if path.path.segments.last().map_or(false, |s| s.ident == "OptionQuery") =>
|
||||
Some(QueryKind::OptionQuery),
|
||||
syn::Type::Path(path)
|
||||
if path.path.segments.last().map_or(false, |s| s.ident == "ValueQuery") =>
|
||||
Some(QueryKind::ValueQuery),
|
||||
_ => None,
|
||||
.map(|query_kind| {
|
||||
use syn::{
|
||||
AngleBracketedGenericArguments, GenericArgument, Path, PathArguments, Type,
|
||||
TypePath,
|
||||
};
|
||||
|
||||
let result_query = match query_kind {
|
||||
Type::Path(path)
|
||||
if path
|
||||
.path
|
||||
.segments
|
||||
.last()
|
||||
.map_or(false, |s| s.ident == "OptionQuery") =>
|
||||
return Ok(Some(QueryKind::OptionQuery)),
|
||||
Type::Path(TypePath { path: Path { segments, .. }, .. })
|
||||
if segments.last().map_or(false, |s| s.ident == "ResultQuery") =>
|
||||
segments
|
||||
.last()
|
||||
.expect("segments is checked to have the last value; qed")
|
||||
.clone(),
|
||||
Type::Path(path)
|
||||
if path.path.segments.last().map_or(false, |s| s.ident == "ValueQuery") =>
|
||||
return Ok(Some(QueryKind::ValueQuery)),
|
||||
_ => return Ok(None),
|
||||
};
|
||||
|
||||
let error_type = match result_query.arguments {
|
||||
PathArguments::AngleBracketed(AngleBracketedGenericArguments {
|
||||
args, ..
|
||||
}) => {
|
||||
if args.len() != 1 {
|
||||
let msg = format!(
|
||||
"Invalid pallet::storage, unexpected number of generic arguments \
|
||||
for ResultQuery, expected 1 type argument, found {}",
|
||||
args.len(),
|
||||
);
|
||||
return Err(syn::Error::new(args.span(), msg))
|
||||
}
|
||||
|
||||
args[0].clone()
|
||||
},
|
||||
args => {
|
||||
let msg = format!(
|
||||
"Invalid pallet::storage, unexpected generic args for ResultQuery, \
|
||||
expected angle-bracketed arguments, found `{}`",
|
||||
args.to_token_stream().to_string()
|
||||
);
|
||||
return Err(syn::Error::new(args.span(), msg))
|
||||
},
|
||||
};
|
||||
|
||||
match error_type {
|
||||
GenericArgument::Type(Type::Path(TypePath {
|
||||
path: Path { segments: err_variant, leading_colon },
|
||||
..
|
||||
})) => {
|
||||
if err_variant.len() < 2 {
|
||||
let msg = format!(
|
||||
"Invalid pallet::storage, unexpected number of path segments for \
|
||||
the generics in ResultQuery, expected a path with at least 2 \
|
||||
segments, found {}",
|
||||
err_variant.len(),
|
||||
);
|
||||
return Err(syn::Error::new(err_variant.span(), msg))
|
||||
}
|
||||
let mut error = err_variant.clone();
|
||||
let err_variant = error
|
||||
.pop()
|
||||
.expect("Checked to have at least 2; qed")
|
||||
.into_value()
|
||||
.ident;
|
||||
|
||||
// Necessary here to eliminate the last double colon
|
||||
let last =
|
||||
error.pop().expect("Checked to have at least 2; qed").into_value();
|
||||
error.push_value(last);
|
||||
|
||||
Ok(Some(QueryKind::ResultQuery(
|
||||
syn::Path { leading_colon: leading_colon.clone(), segments: error },
|
||||
err_variant,
|
||||
)))
|
||||
},
|
||||
gen_arg => {
|
||||
let msg = format!(
|
||||
"Invalid pallet::storage, unexpected generic argument kind, expected a \
|
||||
type path to a `PalletError` enum variant, found `{}`",
|
||||
gen_arg.to_token_stream().to_string(),
|
||||
);
|
||||
Err(syn::Error::new(gen_arg.span(), msg))
|
||||
},
|
||||
}
|
||||
})
|
||||
.unwrap_or(Some(QueryKind::OptionQuery)); // This value must match the default generic.
|
||||
.transpose()?
|
||||
.unwrap_or(Some(QueryKind::OptionQuery));
|
||||
|
||||
if let (None, Some(getter)) = (query_kind.as_ref(), getter.as_ref()) {
|
||||
let msg = "Invalid pallet::storage, cannot generate getter because QueryKind is not \
|
||||
identifiable. QueryKind must be `OptionQuery`, `ValueQuery`, or default one to be \
|
||||
identifiable.";
|
||||
identifiable. QueryKind must be `OptionQuery`, `ResultQuery`, `ValueQuery`, or default \
|
||||
one to be identifiable.";
|
||||
return Err(syn::Error::new(getter.span(), msg))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user