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?