mod config;
use crate::utils::find_storage_key_salt;
use config::StorageItemConfig;
use proc_macro2::TokenStream as TokenStream2;
use quote::{
quote,
ToTokens,
};
use std::collections::HashSet;
pub struct StorageItem {
ast: syn::DeriveInput,
config: StorageItemConfig,
}
impl StorageItem {
pub fn new(config: TokenStream2, item: TokenStream2) -> Result<Self, syn::Error> {
let ast = syn::parse2::<syn::DeriveInput>(item)?;
let parsed_config = syn::parse2::<crate::ast::AttributeArgs>(config)?;
let config = StorageItemConfig::try_from(parsed_config)?;
for attr in &ast.attrs {
if attr
.path()
.to_token_stream()
.to_string()
.contains("storage_item")
{
return Err(format_err_spanned!(
attr,
"only one `ink::storage_item` is allowed",
))
}
}
Ok(Self { ast, config })
}
pub fn ast(&self) -> &syn::DeriveInput {
&self.ast
}
pub fn all_used_types(&self) -> Vec<syn::Type> {
let res: Vec<_> = match self.data().clone() {
syn::Data::Struct(st) => {
st.fields.iter().map(|field| field.ty.clone()).collect()
}
syn::Data::Enum(en) => {
en.variants
.iter()
.flat_map(|variant| variant.fields.iter())
.map(|field| field.ty.clone())
.collect()
}
syn::Data::Union(un) => {
un.fields
.named
.iter()
.map(|field| field.ty.clone())
.collect()
}
};
let mut set = HashSet::new();
res.into_iter()
.filter(|ty| {
if !set.contains(ty) {
set.insert(ty.clone());
true
} else {
false
}
})
.collect()
}
pub fn config(&self) -> &StorageItemConfig {
&self.config
}
pub fn vis(&self) -> &syn::Visibility {
&self.ast.vis
}
pub fn attrs(&self) -> &[syn::Attribute] {
&self.ast.attrs
}
pub fn ident(&self) -> &syn::Ident {
&self.ast.ident
}
pub fn generics(&self) -> TokenStream2 {
let types = self.ast.generics.clone();
let (_, _, where_closure) = self.ast.generics.split_for_impl();
quote! {
#types #where_closure
}
}
pub fn data(&self) -> &syn::Data {
&self.ast.data
}
pub fn salt(&self) -> TokenStream2 {
if let Some(param) = find_storage_key_salt(&self.ast) {
param.ident.to_token_stream()
} else {
quote! { () }
}
}
}