►
Description
Macros for a More Productive Rust by jam1garner
The macro system in Rust is still arguably in its infancy. While a lot of the implementation has already been done, plenty of projects don't properly take advantage of macros due to the limited resources on what macro programming should look like. This talk is aimed at introducing those interested in using macros in existing or future projects to macro idioms often needed in order to take projects to the next level.
A
Hey
so
this
is
macros
for
a
more
productive
rust.
Just
a
little
bit
about
me
before
I
get
started,
my
name
is
jam.
I
use
he
him
pronouns
professionally.
I
do
security
research.
However,
in
my
free
time
I
mostly
focus
on
modding
general,
open
source
stuff,
so
macros,
here's
the
simplest
macro.
A
It's
composed
of
only
a
few
parts.
You
have
the
declaration
which
just
sets
what
the
name
of
the
macro
is.
You
have
the
pattern
which
essentially
handles
parsing
the
input
to
the
macro,
so
you
might
have
different
types
of
syntax
fragments,
so
you
might
have
expressions,
you
might
have
names
of
types
you
might
have
identifiers.
A
So,
as
the
name
implies,
it
is
what
it
expands
into
so
and
then
you
also
have
here's
an
instance
in
here's
an
example
of
calling
the
macro,
so
in
this
case
just
passing
in
a
symbol
3,
which
is
a
valid
expression,
and
if
we
want
to
see
what
it
looks
like
when
this
expands,
we
just
basically
take
the
expansion
and
we
template
in
the
variable
that
we're
passing
in
so
in
this
case,
it's
just
num,
which
is
going
to
be
prefixed
by
a
dollar
sign,
and
so
then
it
expands
to
this.
A
If
you
want
to
expand
things
on
your
own,
there's
two
really
great
resources
for
it.
There's
cargo
expand,
which
is
a
cargo
sub
command
made
by
david
tolnay,
which
is
which
just
allows
you
to
see.
Okay,
what
happens
when
my
macro
expands?
What
is
it
expanding
to,
and
you
also
have
the
ability
to
under
the
rust
playground
at
the
bottom
of
the
tool
section
you
have
the
ability
to
expand
your
macros
and
so
highly
recommend
going
on
rust
playground
in
order
to
play
around
with
that.
A
So
another
feature
of
macros
is
that
you
can
have
it
match
against
something
multiple
times
so
kind
of
like
regex,
where
you
have
star
plus
and
question
mark
to
control
the
amount
of
times
you
match
against
something.
It's
exactly
the
same
here
in
rust.
You
define
a
capture
group
and
then
you
say:
okay,
how
many
times
do
I
want
this
to
repeat
so
you
use
like
star.
If
you
want
zero
or
more,
you
have
question
mark.
A
If
you
want
it
to
be
once
or
no
times
and
then
another
the
last,
you
know
big
feature
of
macro
rules.
Macros
is
that
you
can
have
multiple
different
patterns
that
you're
matching
against
and
the
different
patterns
can
have
different
expansions,
and
so
that
allows
you
to
essentially
encode
parsing
logic
in
order
to
figure
out
how
you
actually
want
to
handle
your
expansion.
A
So
in
this
case
it's
just
a
simple
macro
which
expands
differently
based
off
of
whether
or
not
you
pass
a
two
or
three
into
it,
simple
enough.
So
when
we
put
those
all
together,
we
can
do
a
lot
cooler
things
with
macro
rules
macros.
So,
for
example,
we
have
this
trait
called
as
bytes.
It's
a
simple
trait.
All
it
does
is
takes
whatever
structure
that
implements
as
bytes
and
then
it
converts
it
into
a
vector
of
bytes.
A
So,
for
example,
if
we
want
to
implement
it
for
u16,
we
might
use
the
associated
functions
for
converting
u16s
into
bytes
simple
enough.
But
the
thing
is
is
that
if
you
have
to
type
this
in
for
every
different
integer
type,
it's
going
to
be
a
lot
of
repetitive
code
and
it's
not
going
to
be
easy
to
manage
it
after
you've
written
it,
and
it's
going
to
be
harder
to
not
necessarily
harder
to
read.
But
it's
just
going
to
be
a
lot
to
read
and
anytime.
You
have
to
go
in
and
make
a
change.
A
Be
matching
against
repeated,
comma
separated
type
names,
and
then
we
replace
every
instance
of
u16
with
our
type
name,
and
so
that
allows
it
to.
It
says:
okay
generate
this
code
in
multiple
repetitions
of
it,
for
whatever
given
types
we
pass
in,
and
so
then,
if
we
call
it
with
all
of
the
types
it'll
generate
implementations
for
all
of
those
types,
and
then
we
only
have
one
implementation
that
we
have
to
maintain,
and
it's
the
templated
one,
and
so
some
intermediate
techniques
for
macro
rules.
A
Macros
is
you
can
use
internal
rules
which,
basically,
in
this
example,
we
have
two
macros.
We
have
macro
one
and
we
have
macro
two
and
macro
1
calls
onto
macro
2
and
that
might
be
necessary
because,
like
I
said
earlier,
the
only
way
to
really
encode
parsing
logic
is,
if
you
have
multiple
patterns
or
rules
that
you
are
matching
against
in
order
to
encode
that
logic.
And
so,
if
we
have
to
have
multiple
steps
of
parsing
logic,
then
we
end
up
having
to
have
essentially
multiple
macros
to
handle
each
layer
of
logic.
A
And
so
in
this
case
this
actually
causes
a
problem,
because
if
we
import
macro
1
into
scope
but
not
macro
2,
then
macro
1
tries
to
use
macro
2
after
it
expands,
but
it's
not
in
scope.
So
how
do
we
fix
this?
A
Is
that
if
you,
everything
in
rust
is
going
to
be
split
up
into
tokens,
you
a
basically
in
a
tree
format,
because
if
you
have
like
brackets,
everything
inside
of
the
brackets
is
going
to
be
a
child
of
that
the
bracket
tokens
in
your
token
tree,
and
so,
if
you
match
against
repeated
token
trees,
then
you
match
against
everything
that
gets
passed
into
the
macro.
A
And
so,
if
you
match
against
something
and
then
the
rest
of
the
token
trees,
then
you
can
essentially
say:
okay,
I'm
only
matching
against
the
first
token
and
then
I
can
pass
the
rest
of
those
token
trees
back
into
the
macro,
and
so
I
can
handle
parsing
one
set
of
tokens
at
a
time.
So
in
this
example,
we
have
matching
against
either
up
or
down
and
each
time
it's
followed
by
the
rest
of
the
token
trees.
A
And
so
if
we
actually
look
at
what
that,
what
happens
when
we
try
to
handle
that
is,
we
have
up
up
down
down
and
then
it
matches
against
that
first
up
for
the
first
branch
of
it,
and
then
it
take
captures
the
up
down
down
as
the
rest
of
the
token
trees.
And
then
it
passes
that
back
in
to
the
macro.
So
then
it's
just
another
call
of
up
down
down
and
then
there's
those
recursive
calls
allow
us
to
handle
it
one
at
a
time
going
down
down
and
then
down.
A
And
then
we
hit
our
base
case,
which
is
just
when
nothing
gets
passed
in.
We
then
just
do
nothing,
and
so
after
that
it
expands
into
nothing,
and
then
we
have
all
of
our
code
and
we've
been
able
to
handle
it
one
step
one
set
of
tokens
at
a
time,
so
we
can
have
multiple
repeating
tokens,
but
each
one
has
parsing
logic
for
handling.
A
A
If
you
wanted
to
find
this
crate
or
other
crates
like
it,
david
tolnay,
the
person
who
actually
made
paste
actually
has
a
site
that
allows
you
to
look
at
a
lot
of
useful
stuff
related
to
macros.
It's
actually
his
github,
so
proc
macros,
the
other
type
of
macro
different
from
macro
rules,
so
proc
macros.
A
So
in
this
example,
it's
a
json
macro
from
rocket
and
it
allows
you
to
essentially
just
trade
up
right
json
within
your
code
and
even
use
rust
expressions
as
values
or
keys
within
your
json,
and
that's
great
for
like
if
you're
writing
a
web
server,
and
you
want
a
quick
ergonomic
way
to
build
a
json
response,
a
wonderful
way
to
do
it.
And
so
then,
we
also
have
attribute
macros.
A
So,
for
example,
serde.json
is
a
great
for
converting
to
and
from
json
strings,
and
it's
absolutely
great,
you
should
definitely
check
it
out
and
so
proc
macros.
If
you
want
to
create
one
yourself,
all
you
have
to
do
is
create
a
new
library.
Throw
proc
macro
equals
true
in
your
tomml,
and
then
you
just
have
to
make
a
function
which
takes
in
a
token
stream
and
outputs
a
different
stream.
So
here's
an
example
of
how
we
can
make
a
proc
macro,
and
so
what
this
does
is.
A
This
is
a
attribute
macro
which
you
put
it
at
the
top
of
a
function
and
what
it'll
do
is
it'll
insert
a
print
statement
at
the
beginning
of
the
function
so
that
it
prints
out
okay,
I'm
entering
this
function,
which
allows
you
to
trace
things
so,
basically,
the
way
this
macro
works
is
first
up.
We
have
a
line
that
uses
syn,
parse
macro
input,
and
so
what
syn
is
syn
is
it
allows
you
to
parse
arbitrary,
rust
source
from
tokens
so
like
in
this
situation.
A
It's
parsing
the
input
to
our
proc
macro
as
a
function,
and
it
also
handles
the
error
handling
for
you.
So
it'll
give
you
a
pretty
error
if
they
try.
If
someone
tries
to
pass
in
something
other
than
a
function,
and
so
then
we
take
the
name
of
the
function
and
convert
it
to
a
string,
and
so
here's
a
sin,
parse
quote,
and
so
what
that
allows
you
to
do
is
quote
is
a
crate
which
allows
you
to
essentially
pseudo
quote
your
code
and
convert
it
to
tokens.
A
A
A
I
definitely
recommend
you
check
it
out
if
you
are
doing
any
binary
parsing,
but
essentially
the
idea
of
it
is
instead
of
writing
a
bunch
of
code
for
handling
your
parsing
logic.
Instead
use
your
struct
declaration
and
use
the
ordering
of
your
field
and
some
metadata
in
attributes
in
order
to
actually
encode
the
parsing
logic,
so
that
you
don't
actually
have
to
write
your
parsing
code.
You
have
your
parsing
code
generated
for
you,
and
so
that
allows
you
to
have
kind
of
declarative
programming
for
your
parsing,
and
I
think
that
was
a
pretty
successful
experiment.
A
But
one
cool
thing
you
can
kind
of
learn
from
this
is
basically
when
you're
implementing
a
derived
macro.
What
you
want
to
do
is
you
want
to
offload
as
much
of
the
lot,
the
actual
like
code
out
of
the
proc
macro
itself
and
into,
for
example,
like
a
trait.
So
in
this
case
I
have
like
been
read.
The
trait
in
question,
implemented
for
all
of
the
like
integer
types
and
all
the
other
primitives,
and
then
some
more
helper
types
and
then
my
derived
macro
all
it
does.
A
A
And
so
here's
one
of
the
really
coolest
examples
of
how
you
can
use
function
like
macros
and
for
a
function
like
proc
macros,
since
you
can
just
write
arbitrary
tokens
in
there,
because
it's
imbe
it's
inside
of
a
separator
and
therefore
doesn't
actually
have
to
be
valid
rust
like
an
attribute
macro.
If
you
attach
it
to
a
function,
it
still
has
to
be
a
valid
function,
but
within
it
you
can
kind
of
it
has
to
parse
properly,
but
with
function
like
macros.
A
A
This
is
just
a
arbitrary
language
that
allows
you
to
encode
moveset
information
for
a
game,
so
like
okay,
wait,
16
frames
and
then
create
a
hitbox
and
then
do
this
and
that,
but
an
even
cooler
example
of
using
that
is
this
crate
called
inline
python,
and
so
you
might
think
inline
python
that
doesn't
make
any
sense
rust
has
like
it.
It
doesn't
care
about
white
space.
It's
completely
ignores
it.
It
just
parses
the
tokens
between
the
white
space.
So
how
can
you
encode
python,
like
python,
is
dependent
on
the
white
space?
A
Okay,
there
is
a
tab
in
here
and
we
can
recreate
the
white
space
from
the
positions
of
the
tokens
and
this
allows
you
to
essentially
write
arbitrary
inline
languages
for
your
specific
domain.
So
if
you
want
to
write
python
that
pulls
rust
variables,
you
can
use
inline
python
or
you
can
write
your
own
and
that's
insanely,
powerful
and
so
here's
an
example
of
an
attribute
macro.
Also
one
I
wrote
it's
called
skyline
hook
and
essentially
what
it
does
is.
It
allows
you
to
replace
a
function
in
another
binary
with
your
rust
function.
A
That
is
a
somebody
made
a
pokemon
randomizer,
and
so
it
really
just
takes
one
like
50
line
function
or
it
just
randomizes
some
values
in
some
function.
It's
overriding
and
that's
all
it
takes,
and
the
attribute
macro
actually
handles
all
of
the
inserting
your
code
patching
and
everything
like
that.
But
can
we
take
macros
even
further,
so
in
an
earlier
talk,
esteban
started
talking
a
lot
about
rus,
plus
plus,
and
it
got
me
thinking
you
know
like
rust,
great
language.
I
love
it.
A
It's
my
favorite
language
but
like
it
still
needs
a
lot
of
features
like
if
you
think
about
it,
like
it
can't
interrupt
with
c
plus
at
all.
Like
what's
up
with
that
and
like
also,
I
don't
have
the
ability
to
do
inheritance,
like
is
russ,
not
even
an
object-oriented
programming
language,
like
I
don't
understand
so
like
the
conclusion
I
came
to
is
rust
must
be
a
bad
language.
Like
you
know,
a
good
language
like
sipos
plus
has
these
features
kidding.
A
Obviously,
but
still
this
got
me
thinking
about
like
oh,
you
know
what,
if
we
actually
introduce
inheritance
and
c
plus
interoperability
with
a
macro,
and
so
I
made
this
crate
called
cpp
inherit
and
what
it
allows
you
to
do.
A
And
so
that's
all
I
got
thank
you
for
watching.
It
was
a
great
time.