Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust proc_macro_derive: How do I check if a field is of a primitive type, like boolean?

I'm trying to filter out all the fields of a struct that are of type bool. But the syn::Type enum doesn't seem to have a case for it, or I'm reading the definitions incorrectly:

pub enum Type {
    Array(TypeArray),
    BareFn(TypeBareFn),
    Group(TypeGroup),
    ImplTrait(TypeImplTrait),
    Infer(TypeInfer),
    Macro(TypeMacro),
    Never(TypeNever),
    Paren(TypeParen),
    Path(TypePath),
    Ptr(TypePtr),
    Reference(TypeReference),
    Slice(TypeSlice),
    TraitObject(TypeTraitObject),
    Tuple(TypeTuple),
    Verbatim(TokenStream),
    // some variants omitted
}

I looked trough syn::Types source, to check which variants where ommited, but that didn't bring me any further. Here's what I have until now:

#[proc_macro_derive(Creator)]
pub fn derive_creator(_item: TokenStream) -> TokenStream {
    let item = parse_macro_input!(_item as syn::DeriveInput);
    let item_ident = item.ident;

    let fields = if let syn::Data::Struct(syn::DataStruct {
        fields: syn::Fields::Named(syn::FieldsNamed { ref named, .. }),
        ..
    }) = item.data
    {
        named
    } else {
        panic!("You can derive Creator only on a struct!")
    };

    let bool_fields = fields.iter().filter(|field| 
        match field.ty {
            // case when field type is bool => true
            _ => false
        }
    );
    unimplemented!()
}

Am I going down the wrong path? Or is this simply not possible? Or am I missing something?

like image 534
Typhaon Avatar asked Mar 01 '23 16:03

Typhaon


1 Answers

I feel like there might be a cleaner way (without having to clone and allocate a string), but in the past I've done something like:

match field.ty {
    Type::Path(type_path) if type_path.clone().into_token_stream().to_string() == "bool" => {
        true
    }
    _ => false
}

You might be able to define the bool type once and then compare it for equality:

let bool_ty = Type::Path(TypePath {
    qself: None,
    path: Path::from(Ident::new("bool", Span::call_site())),
});

if field.ty == bool_ty {
    // it's a bool
}

But I'm not sure if a difference in the span would affect equality. Span appears to not implement PartialEq, so my guess is that this is ok.*


*Edits to clarify this are welcome.

like image 69
Peter Hall Avatar answered May 12 '23 23:05

Peter Hall