Crates.io | dry |
lib.rs | dry |
version | 0.1.1 |
source | src |
created_at | 2022-05-21 03:45:35.615959 |
updated_at | 2022-05-21 04:54:53.034706 |
description | Rust macros for idiomatic deduplication of code. Use whenever `macro_rules!` are too powerful and clunky. |
homepage | |
repository | https://github.com/coldriverstudio/dry-rs |
max_upload_size | |
id | 590571 |
size | 34,091 |
dry
— Don't Repeat YourselfRust macros for idiomatic deduplication of code. Use whenever macro_rules!
are too powerful and clunky.
[dependencies]
dry = "0.1.1"
macro_for!
You know the trusty for
loop:
for number in [1, 2, 3, 4, 5] {
println!("{}", number);
}
Use macro_for!
to iterate over tokens at compile time:
macro_for!($Struct in [A, B, C, D, E] {
struct $Struct {
many_fields: bool,
so_many_fields: bool,
impossibly_many_fields: bool,
}
});
Compared to using macro_rules!
:
macro_rules! my_struct {
($Struct:ident) => {
struct $Struct {
many_fields: bool,
so_many_fields: bool,
impossibly_many_fields: bool,
}
};
}
my_struct!(A);
my_struct!(B);
my_struct!(C);
my_struct!(D);
my_struct!(E);
See the examples for more details.
macro_wrap!
Allows you to use the other macros in this crate in places where macro invocations are illegal (e.g. struct fields, enum cases, match arms).
Wrap the closest syntax tree ancestor that is in a macro invocation position and you're good to go:
macro_wrap!(match x {
// ↓ can't usually call macros here, but `macro_wrap!` makes it work
macro_for!($Variant in [A, B, C, D, E] {
Enum::$Variant => 1,
})
})
The nightly
feature (disabled by default) enables functionality that uses the
unstable proc_macro_span
rustc feature. It enables better syntax checking
(disallows spaces between the "$" and the substitution variable names) and emits
more source code hints on errors (though quick-fixes for macros aren't
available even on nightly yet).
If you're running Rust nightly, you can enable it:
[dependencies]
dry = { version = "0.1.1", features = ["nightly"] }
The only dependency is proc-macro-error
, for those sweet, sweet, friendly
error messages across Rust versions. In turn, it depends on quote
and
proc-macro2
. However, we don't depend on syn
at all so dry
should be
really light on compile times.
You should try to use an abstraction like looping, traits, or generics if at
all possible. But when it's not, dry
makes it as painless and pleasant as
possible to avoid repeating yourself.
duplicate
: The most popular by far
and works more or less like a regular for
loop with tuple destructuring,
except for the very foreign syntax. It offers an attribute syntax which
avoids some nesting, but at the cost of clarity, in my opinion. The
function-like syntax can be used wherever the attribute sytnax is valid, plus
"$"-prefixed identifiers are invalid Rust and therefore not possible to
implement in an attribute syntax.akin
: Overloads the let
syntax with an
implicit for
comprehension.
Avoids nesting for large numbers of substitution variables but feels too
magical to feel at home in most Rust codebases, in my opinion.ct-for
: Almost there! However it uses
in ... do
syntax instead of the more familiar in ... {}
syntax Rustaceans
are used to. This also makes it more difficult for editors to correctly
indent the loop body. Finally, the ct
in ct_for
is not very descriptive.All of them use bare identifiers instead of "$"-prefixed identifiers like dry
and macro_rules!
do, which make it clear when macros are being used versus
standard language features within the loop body. None of them support
replicating struct fields, enum cases, or match arms as far as I'm aware.
repeated
: Not quite the same thing,
but alerted the author to the macro invocation position (e.g. match arms,
etc.) problem and one way to solve it. In fact, a match
with many arms for
an enum in an external crate without generic traits is what spurred initial
development of dry
!seq_macro
: Inspired the syntax used
in macro_for!
. Great if you want to idiomatically iterate over a range of
numeric or character values instead of a list of tokens at compile time.dry
is licensed under the MIT License and the Apache 2.0 License, at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Please open a pull request if you'd like to see anything fixed or added, or create an issue if you're not sure how to get started.
for
-like syntax.macro_wrap
.}
is ignored. Should be an
error instead.for
loop)macro_let
macro for idiomatic substitutions (replaces macro_rules!
without syntax arguments)$variable~_suffix
), or operators (variable $op~= change
). This is meant to be a straightforward replacement for
macro_rules!
in simple cases, though. How does it solve this problem?
See paste
crate.macro_wrap
expand macros outside of this crate, too? Probably not,
but let's investigate. Maybe we can let other macro crates plug into it
if we can't do it automatically.duplicate
solves this with what they call parametrized substitution