Transforming names and strings
Often, it's useful to define new identifiers based on existing ones, or to convert identifiers into strings.
You could use the existing paste
crate for this,
or you can use a native facility provided by derive-deftly.
For example, suppose that you want
to define a template that makes a "discriminant" type
for your enumerations.
You want the new type to be named FooDiscriminant
,
where Foo
is the name of your existing type.
While you're at it, you want to add an is_
function
to detect each variant.
You can do that like this:
#![allow(unused)] fn main() { use derive_deftly::define_derive_deftly; define_derive_deftly! { Discriminant: #[derive(Copy,Clone,Eq,PartialEq,Debug)] enum ${paste $tname Discriminant} { $( $vname, ) } impl<$tgens> $ttype where $twheres { fn discriminant(&self) -> ${paste $tname Discriminant} { match self { $( $vpat => ${paste $tname Discriminant}::$vname, ) } } $( fn ${paste is_ ${snake_case $vname}} (&self) -> bool { self.discriminant() == ${paste $tname Discriminant} ::$vname } ) } } }
Here we see a couple of new constructs.
First, we're using
${paste}
to glue several identifiers together into one.
When we say ${paste $tname Discriminant}
,
we are generating a new identifier from $tname
(the type name)
and the word Discriminant.
So if the type name is Foo
,
the new type will be called FooDiscriminant
.
Second, we're using
${snake_case}
to transform an identifier into snake_case
(that is, lowercase words separated by underscores).
We use this to turn the name of each variant ($vname
)
into a name suitable for use in a function name.
So if a variant is called ExampleVariant
,
${snake_case $vname}
will be example_variant
,
and ${paste is_ ${snake_case $vname}}
will be
is_example_variant
.
There are other case-changers:
${pascal_case my_ident}
becomesMyIdent
. You can also write this as${upper_camel_case ..}
.${lower_camel_case my_ident}
becomesmyIdent
.${shouty_snake_case MyIdent}
becomesMY_IDENT
.${snake_case MyIdent}
becomesmy_ident
, as you've already seen.
You can abbreviate ${paste ...}
as $<...>
.
Pasting onto types
Here's a side-note:
You can use ${paste}
to append identifiers to a type
(like $ttype
or $ftype
),
not just an identifier.
When you do this, ${paste}
will
do the right thing
even if the type is generic.
For example, if $ftype
is Vec<u8>
,
then ${paste $ftype Builder}
will expand to
VecBuilder<u8>
, not Vec<u8>Builder
.
A note on syntax
In this last section,
you've seen a new syntax for the first time.
Both ${paste ident ident..}
and ${snake_case ident}
are special cases of the following meta-syntax,
which derive-deftly uses everywhere:
In fact, if you want,
you can use this format
for all of the expansion macros you have already seen:
$ttype
is just a shortened form for ${ttype}
,
$fname
is just ${fname}
,
and so on.
Some keywords, including some of those we've already seen, can take named arguments. The syntax for this is:
${KEYWORD ARGNAME=VALUE ARGNAME=VALUE...}
For example, we can use this syntax to give optional arguments to
$vpat
; see the template syntax reference for more information.
If you ever need to write a literal $
(say, if you want to confuse yourself
by making derive-deftly-generated pattern macros)
you can write $$
.