Making Constructor set fields with Default
Sometimes, we'd like to make a template template
that behave in different ways for different fields.
For example, let's suppose that we want our Constructor
template
to be able to set fields to their default values,
and not take them as arguments.
We can do this with an explicit conditional for each field:
#![allow(unused)] fn main() { use derive_deftly::define_derive_deftly; define_derive_deftly! { Constructor: impl<$tgens> $ttype where $twheres { $tvis fn // This is the function name, same as before. ${if tmeta(constructor(newfn)) { ${tmeta(constructor(newfn)) as ident} } else { new } } ( // These are the function arguments: $( ${when not(fmeta(constructor(default))) } // (1) $fname: $ftype , ) ) -> Self { Self { $( $fname: ${if fmeta(constructor(default)) { ::std::default::Default::default() // (2) } else { $fname } } , ) } } } } use derive_deftly::Deftly; #[derive(Deftly)] #[derive_deftly(Constructor)] struct Foo { #[deftly(constructor(default))] s: Vec<String>, n: u32, } }
Here we're using a new construct:
$when
.
It's only valid inside a loop like $( ... )
or ${for ...}
.
It causes the output of the loop to be suppressed
whenever the condition is not true.
The condition in this cases is not(fmeta(constructor(default)))
.
(See // (1)
.)
You've seen fmeta
before;
it's true when a given attribute is present on the current field.
The not
condition
is just how we express negation.
All together, this $when
keyword causes each field
that has #[deftly(Constructor(default))]
applied to it
to be omitted from the list of arguments
to the new()
function.
Note at
// (2)
that we're using::std::default::Default::default()
, rather than callingDefault::default()
unconditionally. Remember, macros expand at the position where they are invoked, and it's possible that we'll be invoked in a module that has been built without the standard prelude.
Besides $not
,
you can use other boolean operators in conditions too:
there is an
any(...)
that is true
whenever at least one of its arguments is true,
and an
all(...)
that is true
when all of its arguments are true.