Expand description
Has this ever happened to you?
#[derive(Debug, Default, PartialEq, Eq)]
struct Inner {
x: i32,
y: i32,
z: i32,
}
#[derive(Debug, Default, PartialEq, Eq)]
struct Mid {
a: Inner,
b: Inner,
c: Inner,
d: Inner
}
#[derive(Debug, Default, PartialEq, Eq)]
struct Outer {
mid1: Mid,
mid2: Mid,
mid3: Mid,
mid4: Mid,
}
fn build_outer() -> Outer {
Outer {
mid1: Mid {
a: Inner {
x: 10,
..Default::default() // :D
},
b: Inner {
y: 10,
..Default::default() // :)
},
..Default::default() // :|
},
mid2: Mid {
b: Inner {
z: 10,
..Default::default() // :/
},
..Default::default() // :(
},
..Default::default() // >:(
}
}
Wouldn’t it be nice if you could omit all the tedious ..Default::default()
calls when building deeply nested struct literals? Now you can! With
autodefault
, it’s never been easier to build up a large struct expression
for your tests, bevy components, or anything else
you might need!. Simply tag any function with the #[autodefault]
attribute
and let us handle the rest:
use autodefault::autodefault;
#[autodefault]
fn build_outer_simple() -> Outer {
Outer {
mid1: Mid {
a: Inner { x: 10 },
b: Inner { y: 10 },
},
mid2: Mid {
b: Inner { z: 10 },
}
}
} // :O
assert_eq!(build_outer(), build_outer_simple())
It’s never been easier!
§What it’s actually doing
When applied to a function, the #[autodefault]
will scan the body of the
function for all struct expressions that don’t already have a ..rest
trailing
initializer and insert a ..Default::default()
. It will do this unconditionally
for all struct expressions, regardless of whether they actually implement
Default
, so be sure to refactor into helper functions as necessary:
use autodefault::autodefault;
struct NoDefault {
x: i32,
y: i32,
z: i32,
}
#[autodefault]
fn nope() {
let _nope = NoDefault { x: 10 };
}
§Filtering Default
insertions
If you only want to add ..Default::default()
to some of the structs in your
function, autodefault
supports filtering by type name:
use autodefault::autodefault;
#[derive(Default)]
struct HasDefault {
a: i32,
b: i32,
c: i32,
d: i32,
}
struct NoDefault1 {
a: HasDefault,
}
struct NoDefault2 {
a: NoDefault1,
}
#[autodefault(except(NoDefault1, NoDefault2))]
fn example1() {
let _data = NoDefault2 { a: NoDefault1 { a: HasDefault {} } };
}
#[autodefault(only(HasDefault))]
fn example2() {
let _data = NoDefault2 { a: NoDefault1 { a: HasDefault {} } };
}
§Other behaviors
autodefault
will not descend into nested item definitions; if you nest an
fn
item inside another fn
, you’ll need to tag the inner function with
autodefault
again.
use autodefault::autodefault;
#[derive(Default)]
struct HasDefault {
x: i32
}
struct NoDefault {
x: i32
}
#[autodefault]
fn outer() {
let _x = HasDefault {};
fn inner() {
let _x = NoDefault {x: 10};
}
}
Attribute Macros§
- autodefault
- Modify a function such that some or all struct expressions include
..Default::default()
.