Skip to main content

default_macro/
lib.rs

1#[macro_export]
2macro_rules! default {
3    ( $name:ident { } ) => { $name::default() };
4    ( $name:ident { $field_name:tt : $value:tt $($tail:tt)* } ) => {
5        default!(@x $name { $field_name : } {$value} $($tail)* )
6    };
7    ( $name:expr ) => { $name };
8    ( @x $name:ident {$($processed:tt)*} {$($current:tt)+} $(,)? ) => {
9        $name{ $($processed)* default!($($current)+)  , ..$name::default()}
10    };
11    ( @x $name:ident {$($processed:tt)+} {$($current:tt)+} , $field_name:tt : $value:tt $($tail:tt)* ) => {
12        default!(@x $name {$($processed)+ default!($($current)+), $field_name :} {$value} $($tail)*)
13    };
14    ( @x $name:ident {$($processed:tt)+} {$($current:tt)+} $value:tt $($tail:tt)*) => {
15        default!( @x $name {$($processed)+} {$($current)+ $value} $($tail)* )
16    };
17}
18
19#[cfg(test)]
20mod tests {
21    #[derive(Default, Debug)]
22    struct Foo {
23        a: i32,
24        b: f64,
25        c: Bar,
26    }
27    #[derive(Default, Debug)]
28    struct Bar {
29        d: i32,
30        e: i32,
31    }
32
33    #[test]
34    fn it_works() {
35        check(default!(Foo {}), Foo::default());
36        check(
37            default!(Foo { a: 1 }),
38            Foo {
39                a: 1,
40                ..Foo::default()
41            },
42        );
43        check(
44            default!(Foo { a: 1, b: 1.0 }),
45            Foo {
46                a: 1,
47                b: 1.0,
48                ..Foo::default()
49            },
50        );
51
52        check(
53            default!(Foo { a: 1 + 2, b: 1.0 }),
54            Foo {
55                a: 3,
56                b: 1.0,
57                ..Foo::default()
58            },
59        );
60        check(
61            default!(Foo { c: Bar { d: 1 } }),
62            Foo {
63                c: Bar {
64                    d: 1,
65                    ..Bar::default()
66                },
67                ..Foo::default()
68            },
69        );
70    }
71    fn check(foo1: Foo, foo2: Foo) {
72        assert_eq!(format!("{:?}", foo1), format!("{:?}", foo2));
73    }
74}