#![recursion_limit = "128"]
use proc_macro::TokenStream;
use quote::quote;
use syn::*;
mod domobject;
use crate::domobject::expand_dom_object;
#[proc_macro_attribute]
pub fn dom_struct(args: TokenStream, input: TokenStream) -> TokenStream {
let associated_memory = args.to_string().contains("associated_memory");
if !associated_memory && !args.is_empty() {
panic!("#[dom_struct] only takes 'associated_memory' as an argument");
}
let attributes = quote! {
#[derive(deny_public_fields::DenyPublicFields, JSTraceable, MallocSizeOf)]
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
#[repr(C)]
};
let attributes: TokenStream = attributes.to_string().parse().unwrap();
let output: TokenStream = attributes.into_iter().chain(input).collect();
let item: Item = syn::parse(output).unwrap();
if let Item::Struct(s) = item {
let expanded_dom_object = expand_dom_object(s.clone(), associated_memory);
let s2 = quote! { #s #expanded_dom_object };
if !s.generics.params.is_empty() {
return s2.into();
}
if let Fields::Named(ref f) = s.fields {
let f = f.named.first().expect("Must have at least one field");
let ident = f.ident.as_ref().expect("Must have named fields");
let name = &s.ident;
let ty = &f.ty;
quote! (
#s2
impl crate::HasParent for #name {
type Parent = #ty;
fn as_parent(&self) -> &#ty {
&self.#ident
}
}
)
.into()
} else {
panic!("#[dom_struct] only applies to structs with named fields");
}
} else {
panic!("#[dom_struct] only applies to structs");
}
}