Get type of a struct fields within a `quote` macro

60 views Asked by At

I have the following construct in a Derive procedural macro for generating a From implementation.

quote! {
  impl From<#other_struct_name> for #this_struct_name {
    fn from(other: #other_struct_name) -> Self {
      Self {
        #(#fields_from_other)*
      }
    }
  }
}

other_struct_name is an attribute defined by the user to indicate which struct to use to clone from. Within fields_from_other I have this

let fields_from_other = fields.iter().map(|f| {
    let ty = &f.ty;
    let name = &f.ident;
    quote! {
      #name: other.#name,
    }
});

fields are the fields of the struct I use the derive macro on so getting the type for those is not an issue. But how can I get the type of other.#name here? Eventually, I would like to check if it is an Option.

1

There are 1 answers

1
Aurel Bílý On

You cannot get type information (which includes the fields belonging to a struct) at this point, because macro expansion happens on the AST, which is an untyped representation of the code. Consider also that if this were possible, what would happen if you applied your macro to two structs which would reference each other?

Maybe you can achieve what you want without having type information? Since you mention "checking if a field is an Option", I'm guessing you want to apply different logic (like unwrap_or_default()) on Option-typed fields.

Some possible workarounds that come to mind:

  • On the struct with the derive macro, you could annotate individual fields with a new attribute e.g. #[unwrap] or #[unwrap_or(some_value)], then parse these attributes in the derive macro implementation.
  • If the set of possible types in the fields is limited, you could create a trait Copyable, then implement impl Copyable for i32 { ... } as well as impl Copyable for Option<i32> { ... }. In the generated From implementation, you can then invoke these as e.g. #field: Copyable::copy(&other.#field).