syn icon indicating copy to clipboard operation
syn copied to clipboard

Help Request | Determining type from syn::Type

Open bcpeinhardt opened this issue 3 years ago • 2 comments

Hello! I'm a little confused by syn::Type. I'm writing a derive macro and I really just need to know if a given field on the input struct is a String or a bool, otherwise it's invalid (at least for now). For instance, I need to create a new object with String::new() for each String member and false for each bool member. I've got

let component_field_inits = fields.iter().map(|field| {
        let field_ident = field.ident.clone();
        let field_type = field.ty.clone();
        
        // let field_init = ... do some stuff
        
        quote! { #field_ident: #field_init}
    });

where fields is an &Punctuated<Field, Comma>. I feel like it's either a path or a Verbatim but I just don't know. I'd like to destructure my way there in two match arms (one for String and one for bool) and then use _ to panic otherwise. Any help would be appreciated.

Update: Current Solution ->

let ty_is_string = |field: &syn::Field| {
        if let syn::Type::Path(ref p) = field.ty {
            return p.path.segments.len() == 1 && p.path.segments[0].ident == "String";
        }
        false
    };

    let ty_is_bool = |field: &syn::Field| {
        if let syn::Type::Path(ref p) = field.ty {
            return p.path.segments.len() == 1 && p.path.segments[0].ident == "bool";
        }
        false
    };

    // Create the fields for initializing the struct
    let component_field_inits = fields.iter().map(|field| {
        let field_ident = field.ident.clone().unwrap();
        if ty_is_string(field) {
            quote! { #field_ident: String::new() }
        } else if ty_is_bool(field) {
            quote! { #field_ident: false }
        } else {
            panic!("Field type not supported");
        }
    });

This is basically copy pasted from (halfway through) Jon Gjengset's procedural macro video series. I'm sure I can improve this.

bcpeinhardt avatar Aug 16 '22 18:08 bcpeinhardt

I was working on something similar and came across this issue - it's definitely not easy 😆 - so I have a solution that's similar to yours and works well, however - it falls apart when I have types with generics such as Option<T> - because, Ident will be Option, awesome, but then the args will be < String > so it seems like I'd have to write a parser to figure out the T - (using nom, or contains) - which seems like a rabbit hole. There must be an easier way 🤔

edude03 avatar Sep 09 '22 18:09 edude03

I ended up writing some sort of type checking helper functions that deal with options here: https://github.com/bcpeinhardt/formulaY/blob/main/src/util.rs The part about checking options is largely converted from a stack overflow answer.

bcpeinhardt avatar Sep 09 '22 18:09 bcpeinhardt

Sorry that no one was able to provide guidance here. If this is still an issue, you could try taking this question to any of the resources shown in https://www.rust-lang.org/community. This library is one of the most widely used Rust libraries and plenty of people will be able to provide guidance about it.

dtolnay avatar Jan 23 '23 05:01 dtolnay