Is there a way to get the field names of a struct in a macro?

A macro is expanded during parsing, more or less; it has no access to the AST or anything like that—all it has access to is the stuff that you pass to it, which for my_macro!(S) is purely that there should be a type named S.

If you define the struct as part of the macro then you can know about the fields:

macro_rules! my_macro {
    (struct $name:ident {
        $($field_name:ident: $field_type:ty,)*
    }) => {
        struct $name {
            $($field_name: $field_type,)*
        }

        impl $name {
            // This is purely an example—not a good one.
            fn get_field_names() -> Vec<&'static str> {
                vec![$(stringify!($field_name)),*]
            }
        }
    }
}

my_macro! {
    struct S {
        a: String,
        b: String,
    }
}

// S::get_field_names() == vec!["a", "b"]

… but this is, while potentially useful, often going to be a dubious thing to do.


Here is another possibility that does not require to write a macro (however, the field names will be resolved at run time):

extern crate rustc_serialize;

use rustc_serialize::json::{Encoder, Json};
use rustc_serialize::json::Json::Object;
use rustc_serialize::Encodable;

#[derive(Default, RustcEncodable)]
struct S {
    a: String,
    b: String,
}

fn main() {
    let mut json = "".to_owned();
    {
        let mut encoder = Encoder::new(&mut json);
        S::default().encode(&mut encoder).unwrap();
    }

    let json = Json::from_str(&json).unwrap();
    if let Object(object) = json {
        let field_names: Vec<_> = object.keys().collect();
        println!("{:?}", field_names);
    }
}

(this solution needs the rustc-serialize crate)

The derive(Default) has been added to avoid having to manually create a struct as you wanted (but a struct will still be created).

This solution works by encoding the struct to a String in JSON format and decoding it to a Json. From the Json object, we can extract the field names (if it is an Object variant).

A possibly more efficient method is to write its own encoder:

struct FieldNames {
    names: Vec<String>,
}

impl FieldNames {
    fn new() -> FieldNames {
        FieldNames {
            names: vec![],
        }
    }
}

struct FieldsEncoder<'a> {
    fields: &'a mut FieldNames,
}

impl<'a> FieldsEncoder<'a> {
    fn new(fields: &mut FieldNames) -> FieldsEncoder {
        FieldsEncoder {
            fields: fields,
        }
    }
}

type EncoderError = ();

impl<'a> Encoder for FieldsEncoder<'a> {
    fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        f(self)
    }

    fn emit_struct_field<F>(&mut self, f_name: &str, _f_idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        self.fields.names.push(f_name.to_owned());
        Ok(())
    }

    type Error = EncoderError;
    fn emit_nil(&mut self) -> Result<(), Self::Error> { Err(()) }
    fn emit_usize(&mut self, _v: usize) -> Result<(), Self::Error> { Err(()) }
    fn emit_u64(&mut self, _v: u64) -> Result<(), Self::Error> { Err(()) }
    fn emit_u32(&mut self, _v: u32) -> Result<(), Self::Error> { Err(()) }
    fn emit_u16(&mut self, _v: u16) -> Result<(), Self::Error> { Err(()) }
    fn emit_u8(&mut self, _v: u8) -> Result<(), Self::Error> { Err(()) }
    fn emit_isize(&mut self, _v: isize) -> Result<(), Self::Error> { Err(()) }
    fn emit_i64(&mut self, _v: i64) -> Result<(), Self::Error> { Err(()) }
    fn emit_i32(&mut self, _v: i32) -> Result<(), Self::Error> { Err(()) }
    fn emit_i16(&mut self, _v: i16) -> Result<(), Self::Error> { Err(()) }
    fn emit_i8(&mut self, _v: i8) -> Result<(), Self::Error> { Err(()) }
    fn emit_bool(&mut self, _v: bool) -> Result<(), Self::Error> { Err(()) }
    fn emit_f64(&mut self, _v: f64) -> Result<(), Self::Error> { Err(()) }
    fn emit_f32(&mut self, _v: f32) -> Result<(), Self::Error> { Err(()) }
    fn emit_char(&mut self, _v: char) -> Result<(), Self::Error> { Err(()) }
    fn emit_str(&mut self, _v: &str) -> Result<(), Self::Error> { Err(()) }
    fn emit_enum<F>(&mut self, _name: &str, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_enum_variant<F>(&mut self, _v_name: &str, _v_id: usize, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_enum_struct_variant<F>(&mut self, _v_name: &str, _v_id: usize, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_enum_struct_variant_field<F>(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_tuple<F>(&mut self, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_tuple_arg<F>(&mut self, _idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_tuple_struct<F>(&mut self, _name: &str, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_tuple_struct_arg<F>(&mut self, _f_idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_option<F>(&mut self, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_option_none(&mut self) -> Result<(), Self::Error> { Err(()) }
    fn emit_option_some<F>(&mut self, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_seq<F>(&mut self, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_seq_elt<F>(&mut self, _idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_map<F>(&mut self, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_map_elt_key<F>(&mut self, _idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_map_elt_val<F>(&mut self, _idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
}

which can be used as such:

fn main() {
    let mut fields = FieldNames::new();
    {
        let mut encoder = FieldsEncoder::new(&mut fields);
        S::default().encode(&mut encoder).unwrap();
    }

    println!("{:?}", fields.names);
}

Tags:

Macros

Rust