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