macro_rules! custom_struct {
(
attrs: { $($attrs:tt)* }
$(#$attr:tt)*
$vis:vis struct $name:ident { $($body:tt)* }
) => { ... };
(
@split_attrs,
cfg_attrs: { $($cfg_attrs:tt)* },
other_attrs: { $($other_attrs:tt)* },
remaining_attrs: {
#[cfg($($cfg:tt)*)]
$($tail:tt)*
},
found_exhaustive_attr: $found_exhaustive:tt,
vis: $vis:vis,
name: $name:ident,
body: { $($body:tt)* },
) => { ... };
(
@split_attrs,
cfg_attrs: { $($cfg_attrs:tt)* },
other_attrs: { $($other_attrs:tt)* },
remaining_attrs: {
#[exhaustive]
$($tail:tt)*
},
found_exhaustive_attr: $_:tt,
vis: $vis:vis,
name: $name:ident,
body: { $($body:tt)* },
) => { ... };
(
@split_attrs,
cfg_attrs: { $($cfg_attrs:tt)* },
other_attrs: { $($other_attrs:tt)* },
remaining_attrs: {
#$other:tt
$($tail:tt)*
},
found_exhaustive_attr: $found_exhaustive:tt,
vis: $vis:vis,
name: $name:ident,
body: { $($body:tt)* },
) => { ... };
(
@split_attrs,
cfg_attrs: { $($cfg_attrs:tt)* },
other_attrs: { $($other_attrs:tt)* },
remaining_attrs: { },
found_exhaustive_attr: $found_exhaustive:tt,
vis: $vis:vis,
name: $name:ident,
body: { $($body:tt)* },
) => { ... };
(
@struct,
cfg_attrs: { $($cfg_attrs:tt)* },
other_attrs: { $($other_attrs:tt)* },
found_exhaustive_attr: $found_exhaustive:tt,
vis: $vis:vis,
name: $name:ident,
processed_fields: { $($processed_fields:tt)* },
processed_field_defaults: { $($processed_field_defaults:tt)* },
remaining_fields: {
#[custom_default($default:expr)]
$(#[$fattr:meta])*
$fvis:vis $fname:ident: $fty:ty,
$($tail:tt)*
},
) => { ... };
(
@struct,
cfg_attrs: { $($cfg_attrs:tt)* },
other_attrs: { $($other_attrs:tt)* },
found_exhaustive_attr: $found_exhaustive:tt,
vis: $vis:vis,
name: $name:ident,
processed_fields: { $($processed_fields:tt)* },
processed_field_defaults: { $($processed_field_defaults:tt)* },
remaining_fields: {
$(#[$fattr:meta])*
$fvis:vis $fname:ident: $fty:ty,
$($tail:tt)*
},
) => { ... };
(
@struct,
cfg_attrs: { $($cfg_attrs:tt)* },
other_attrs: { $($other_attrs:tt)* },
found_exhaustive_attr: $found_exhaustive:tt,
vis: $vis:vis,
name: $name:ident,
processed_fields: { $($processed_fields:tt)* },
processed_field_defaults: { $($processed_field_defaults:tt)* },
remaining_fields: { },
) => { ... };
}Expand description
Emit a struct with the given derive attributes plus a generated Default impl. Ensure that the
record has an additional private field added to replicate #[non_exhaustive], unless it is
annotated with #[exhaustive].
Fields default to Default::default(). A field whose default can’t be derived must carry
#[custom_default(EXPR)] as its first attribute, and EXPR is used instead.
This works by scanning each field for #[custom_default] attributes. If one exists, the
attribute’s contents are added to processed_field_defaults and will be used in the expansion
for Default. If it does not exist, Default::default() is used instead. In either case, the
field is added to processed_fields with #[custom_default] stripped if necessary, and
custom_struct is invoked again with the remaining fields.
Attributes are split into cfg_attrs and other_attrs before the fields are scanned. Both go
on the struct, but only the cfgs are repeated on the Default impl. A cfg decides whether
the type exists at all, so without it a configured-out struct leaves an impl behind referring to
a type that isn’t there.
Out of other_attrs, we scan for #[exhaustive]. If found, we remove it but take into account
that the record should be expanded without an additional private field. The scan for both
cfg attributes and the (non-existent) exhaustive attribute is done in one linear pass.