How to iterate through all properties in macro


#1

I’m trying to write a macro that is implementing js Object.assign behaviour. It takes array of objects and assign properties if they are not set yet. Here is sample code for concrete code:

struct Config {
    a: Option<i32>,
    b: Option<String>,
    c: Option<Vec<i32>>,
    d: Option<i32>,
}

impl Config {
    fn merge2(mut self, other: &Config) -> Config {
        macro_rules! merge {
            ($($m:ident),*) => {
                $(self.$m = other.$m.or_else(||self.$m.clone());)*
            }
        }
        merge!(a, b, c, d);
        self
    }
}

Now I want to abstract from concrete type and implement it for all types T:

trait Merge {
    fn merge2(mut self, other: &Self) -> Self;
}


impl<T> Merge for T {
    fn merge2(mut self, other: &Self) -> Self {
        macro_rules! merge {
            ($($m:ident),*) => {
                $(self.$m = self.$m.or_else(||other.$m.clone());)*
            }
        }
        merge!(get_keys!(T));
        self
    }
}

The problem here is that I don’t have get_keys!(T) macro that could help me. E.g. in TypeScript there is a compile time reflection that allows to iterate through all keys, e.g.

// Keep types the same, but make each property to be read-only.
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

// Same property names, but make the value a promise instead of a concrete one
type Deferred<T> = {
    [P in keyof T]: Promise<T[P]>;
};

// Wrap proxies around properties of T
type Proxify<T> = {
    [P in keyof T]: { get(): T[P]; set(v: T[P]): void }
};

How can it be done in Rust? Probably common macros are not powerful enough, maybe procedural macros should be used here. But I have not idea anyway how to implement it. My current code doesn’t seem to be any close to working solution.


Ping?


#2

You will have to use a proc-macro (https://doc.rust-lang.org/book/first-edition/procedural-macros.html)