Rust proc_macro's: adding constants

Viewed 159

I am trying to add a procedural macro that adds constant field to a struct.

Example:

#[add_const]
struct MyStruct {
    id: u32,
    name: String
}

// Expands to:
struct MyStruct {
    id: u32,
    name: String
}
impl MyStruct {
    const FIELDS: [&'static str; 2] = ["id", "name"];
    const TYPES: [syn::Type; 2] = [/*Types of the fields*/];
}

My code for the procedural macro is the following:

#[proc_macro_attribute]
pub fn add_const(_attrs: TokenStream, input: TokenStream) -> TokenStream {
    let item_struct = parse_macro_input!(input as ItemStruct);
    let struct_name = &item_struct.ident;
    let fields: Vec<(String, syn::Type)>;
    if let syn::Fields::Named(ref _fields) = item_struct.fields {
        let _fields = &_fields.named;
        fields = _fields.iter().map(|field| {
            if let Some(ident) = &field.ident {
                let field_name: String = ident.to_string();
                let field_type = &field.ty;
                let entry = (field_name, field_type.to_owned());
                entry
            } else {
                panic!("Only named fields are supported.")
            }
        }).collect();
    } else {
        panic!("The row struct has no fields.");
    }

    let mut field_names: Vec<String> = Vec::new();
    let mut field_types: Vec<syn::Type> = Vec::new();
    
    fields.iter().for_each(|field| {
        let (_name, _type) = field;
        field_names.push(_name.to_owned());
        field_types.push(_type.to_owned());
    });

    TokenStream::from(
        quote!(
            #item_struct
            
            impl #struct_name {
                const FIELDS: [&'static str; #field_len] = [#(#field_names),*];
                const TYPES: [syn::Type; #field_len] = [#(#field_types),*];
            }
        )
    )
}

This throws the following errors:

error[E0423]: expected value, found builtin type `i32`
 --> tests/table_row.rs:7:13
  |
7 |         id: i32,
  |             ^^^ not a value

error[E0423]: expected value, found struct `String`
   --> tests/table_row.rs:8:15
    |
8   |         name: String,
    |               ^^^^^^ help: use struct literal syntax instead: `String { vec: val }`
    |
   ::: /Users/jonaseveraert/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/string.rs:292:1
    |
292 | pub struct String {
    | ----------------- `String` defined here

I have been able to iron down where the problem lies;

/*CODE*/
impl #struct_name {
    const FIELDS: [&'static str; #field_len] = [#(#field_names),*];
    // const TYPES: [syn::Type; #field_len] = [#(#field_types),*]; // Commenting out this line makes the errors disappear
}
/*MORE CODE*/

How can I fix this? i.e. how can I add the second constant without the errors appearing and why do those errors appear?

Thank you in advance, Jonas

0 Answers
Related