Skip to content

Commit

Permalink
Added #[trace(ignore)]
Browse files Browse the repository at this point in the history
  • Loading branch information
ecton committed Aug 9, 2024
1 parent 0225728 commit 5052d8f
Showing 1 changed file with 79 additions and 49 deletions.
128 changes: 79 additions & 49 deletions refuse-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ fn derive_map_as_inner(
}

#[manyhow]
#[proc_macro_derive(Trace)]
#[proc_macro_derive(Trace, attributes(trace))]
pub fn derive_trace(input: syn::Item) -> manyhow::Result {
match input {
syn::Item::Struct(item) => Ok(derive_struct_trace(item)),
syn::Item::Enum(item) => Ok(derive_enum_trace(item)),
syn::Item::Struct(item) => derive_struct_trace(item),
syn::Item::Enum(item) => derive_enum_trace(item),
_ => manyhow::bail!("Collectable can only derived on structs and enums"),
}
}
Expand All @@ -79,19 +79,19 @@ fn derive_struct_trace(
fields,
..
}: syn::ItemStruct,
) -> TokenStream {
) -> manyhow::Result {
require_trace_for_generics(&mut generics);
let (impl_gen, type_gen, where_clause) = generics.split_for_impl();

let fields_and_types = fields
.iter()
.enumerate()
.map(|(index, field)| {
let mut fields_and_types = Vec::new();
for (index, field) in fields.iter().enumerate() {
let field_attr = TraceFieldAttr::from_attributes(&field.attrs)?;
if !field_attr.ignore {
let field_accessor = field_accessor(field, index);

(field_accessor, field.ty.clone())
})
.collect::<Vec<_>>();
fields_and_types.push((field_accessor, field.ty.clone()));
}
}

let types = fields_and_types
.iter()
Expand All @@ -108,15 +108,15 @@ fn derive_struct_trace(
quote! {refuse::Trace::trace(&self.#field, tracer)}
});

quote! {
Ok(quote! {
impl #impl_gen refuse::Trace for #ident #type_gen #where_clause {
const MAY_CONTAIN_REFERENCES: bool = #may_contain_refs;

fn trace(&self, tracer: &mut refuse::Tracer) {
#(#traces;)*
}
}
}
})
}

fn require_trace_for_generics(generics: &mut Generics) {
Expand Down Expand Up @@ -145,62 +145,86 @@ fn derive_enum_trace(
variants,
..
}: syn::ItemEnum,
) -> TokenStream {
) -> manyhow::Result {
require_trace_for_generics(&mut generics);
let (impl_gen, type_gen, where_clause) = generics.split_for_impl();

let mut all_types = HashSet::new();
let traces = variants
.iter()
.map(|syn::Variant { ident, fields, .. }| match fields {
syn::Fields::Named(fields) => {
let mut field_names = Vec::new();
for field in &fields.named {
all_types.insert(field.ty.clone());

let name = field.ident.clone().expect("name missing");
let mut traces = Vec::new();

field_names.push(name);
for syn::Variant {
ident,
fields,
attrs,
..
} in &variants
{
let field_attr = TraceFieldAttr::from_attributes(attrs)?;
if !field_attr.ignore {
let trace = match fields {
syn::Fields::Named(fields) => {
let mut field_names = Vec::new();
for field in &fields.named {
let field_attr = TraceFieldAttr::from_attributes(&field.attrs)?;
if !field_attr.ignore {
all_types.insert(field.ty.clone());

let name = field.ident.clone().expect("name missing");

field_names.push(name);
}
}
quote! {Self::#ident { #(#field_names,)* } => {
#(refuse::Trace::trace(#field_names, tracer);)*
}}
}
quote! {Self::#ident { #(#field_names,)* } => {
#(refuse::Trace::trace(#field_names, tracer);)*
}}
}
syn::Fields::Unnamed(fields) => {
let mut field_names = Vec::new();
for (index, field) in fields.unnamed.iter().enumerate() {
all_types.insert(field.ty.clone());

field_names.push(syn::Ident::new(&format!("f{index}"), Span::call_site()));
syn::Fields::Unnamed(fields) => {
let mut field_names = Vec::new();
for (index, field) in fields.unnamed.iter().enumerate() {
let field_attr = TraceFieldAttr::from_attributes(&field.attrs)?;
if !field_attr.ignore {
all_types.insert(field.ty.clone());

field_names
.push(syn::Ident::new(&format!("f{index}"), Span::call_site()));
}
}
quote! {Self::#ident ( #(#field_names,)* ) => {
#(refuse::Trace::trace(#field_names, tracer);)*
}}
}
quote! {Self::#ident ( #(#field_names,)* ) => {
#(refuse::Trace::trace(#field_names, tracer);)*
}}
}
syn::Fields::Unit => {
quote! {Self::#ident => {}}
}
})
.collect::<Vec<_>>();
syn::Fields::Unit => {
quote! {Self::#ident => {}}
}
};
traces.push(trace);
}
}

let type_mays = all_types
.into_iter()
.map(|ty| quote! {<#ty as refuse::Trace>::MAY_CONTAIN_REFERENCES});
let may_contain_refs = quote! {
#(#type_mays |)* false
};

quote! {
let traces = if traces.is_empty() {
TokenStream::default()
} else {
quote!(
match self {
#(#traces)*
}
)
};
Ok(quote! {
impl #impl_gen refuse::Trace for #enum_name #type_gen #where_clause {
const MAY_CONTAIN_REFERENCES: bool = #may_contain_refs;

fn trace(&self, tracer: &mut refuse::Tracer) {
match self {
#(#traces)*
}
#traces
}
}
}
})
}

#[derive(FromAttr)]
Expand All @@ -209,3 +233,9 @@ struct MapAsAttr {
target: Option<syn::Type>,
map: Option<syn::Expr>,
}

#[derive(FromAttr)]
#[attribute(ident = trace)]
struct TraceFieldAttr {
ignore: bool,
}

0 comments on commit 5052d8f

Please sign in to comment.