1#![recursion_limit = "128"]
6
7use proc_macro::TokenStream;
8use quote::quote;
9use syn::*;
10mod domobject;
11use crate::domobject::expand_dom_object;
12
13#[proc_macro_attribute]
14pub fn dom_struct(args: TokenStream, input: TokenStream) -> TokenStream {
15 let associated_memory = args.to_string().contains("associated_memory");
16 if !associated_memory && !args.is_empty() {
17 panic!("#[dom_struct] only takes 'associated_memory' as an argument");
18 }
19 let attributes = quote! {
20 #[derive(deny_public_fields::DenyPublicFields, JSTraceable, MallocSizeOf)]
21 #[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
22 #[repr(C)]
23 };
24
25 let attributes: TokenStream = attributes.to_string().parse().unwrap();
27
28 let output: TokenStream = attributes.into_iter().chain(input).collect();
29
30 let item: Item = syn::parse(output).unwrap();
31
32 if let Item::Struct(s) = item {
33 let expanded_dom_object = expand_dom_object(s.clone(), associated_memory);
34 let s2 = quote! { #s #expanded_dom_object };
35 if !s.generics.params.is_empty() {
36 return s2.into();
37 }
38 if let Fields::Named(ref f) = s.fields {
39 let f = f.named.first().expect("Must have at least one field");
40 let ident = f.ident.as_ref().expect("Must have named fields");
41 let name = &s.ident;
42 let ty = &f.ty;
43
44 quote! (
45 #s2
46
47 impl crate::HasParent for #name {
48 type Parent = #ty;
49 fn as_parent(&self) -> &#ty {
52 &self.#ident
53 }
54 }
55 )
56 .into()
57 } else {
58 panic!("#[dom_struct] only applies to structs with named fields");
59 }
60 } else {
61 panic!("#[dom_struct] only applies to structs");
62 }
63}