use quote::ToTokens;
use std::collections::HashSet;
use syn::{punctuated::Punctuated, token::Comma};
pub struct OdraEventItem {
item_struct: syn::ItemStruct
}
impl ToTokens for OdraEventItem {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let item = &self.item_struct;
let ident = &item.ident;
let name = ident.to_string();
let fields = item
.fields
.iter()
.map(|f| {
let ident = f.ident.as_ref().unwrap();
let ty = &f.ty;
quote::quote!(#ident: #ty)
})
.collect::<Punctuated<_, Comma>>();
let field_names = item
.fields
.iter()
.map(|f| f.ident.as_ref().unwrap())
.collect::<Punctuated<_, Comma>>();
let comment = format!("Creates a new instance of the {} event.", ident);
let doc_attr = quote::quote!(#[doc = #comment]);
let mut tmp = HashSet::<String>::new();
let mut chain = vec![];
item.fields.iter().for_each(|f| {
let ty = &f.ty;
let v = quote::quote!(.chain(<#ty as odra::schema::SchemaEvents>::custom_types()));
if tmp.insert(v.to_string()) {
chain.push(v);
}
});
let self_item = custom_struct(&name, &item.fields);
let item = quote::quote! {
#[derive(odra::Event, PartialEq, Eq, Debug)]
#item
impl #ident {
#doc_attr
pub fn new(#fields) -> Self {
Self {
#field_names
}
}
}
#[cfg(not(target_arch = "wasm32"))]
impl odra::schema::NamedCLTyped for #ident {
fn ty() -> odra::schema::casper_contract_schema::NamedCLType {
odra::schema::casper_contract_schema::NamedCLType::Custom(odra::prelude::String::from(#name))
}
}
#[cfg(not(target_arch = "wasm32"))]
impl odra::schema::SchemaCustomTypes for #ident {
fn schema_types() -> odra::prelude::vec::Vec<Option<odra::schema::casper_contract_schema::CustomType>> {
odra::prelude::BTreeSet::<Option<odra::schema::casper_contract_schema::CustomType>>::new()
.into_iter()
.chain(odra::prelude::vec![Some(#self_item)])
#(#chain)*
.collect()
}
}
};
item.to_tokens(tokens);
}
}
impl TryFrom<&proc_macro2::TokenStream> for OdraEventItem {
type Error = syn::Error;
fn try_from(code: &proc_macro2::TokenStream) -> Result<Self, Self::Error> {
Ok(Self {
item_struct: syn::parse2::<syn::ItemStruct>(code.clone())?
})
}
}
fn custom_struct(name: &str, fields: &syn::Fields) -> proc_macro2::TokenStream {
let members = fields.iter().map(|f| {
let name = f.ident.as_ref().unwrap().to_string();
let ty = &f.ty;
quote::quote! {
odra::schema::struct_member::<#ty>(#name),
}
});
quote::quote!(odra::schema::custom_struct(#name, odra::prelude::vec![#(#members)*]))
}