Awesome
cargo-expand
Once installed, the following command prints out the result of macro expansion
and #[derive]
expansion applied to the current crate.
$ cargo expand
This is a wrapper around the more verbose compiler command:
$ cargo rustc --profile=check -- -Zunstable-options --pretty=expanded
Installation
Install with cargo install cargo-expand
.
This command optionally uses rustfmt to format the expanded output. The
resulting code is typically much more readable than what you get from the
compiler. If rustfmt is not available, the expanded code is not formatted.
Install rustfmt with rustup component add rustfmt
.
Cargo expand relies on unstable compiler flags so it requires a nightly
toolchain to be installed, though does not require nightly to be the default
toolchain or the one with which cargo expand itself is executed. If the default
toolchain is one other than nightly, running cargo expand
will find and use
nightly anyway.
Example
$ cat src/main.rs
#[derive(Debug)]
struct S;
fn main() {
println!("{:?}", S);
}
$ cargo expand
#![feature(prelude_import)]
#![no_std]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std as std;
struct S;
#[automatically_derived]
#[allow(unused_qualifications)]
impl $crate::fmt::Debug for S {
fn fmt(&self, f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result {
match *self {
S => {
let mut debug_trait_builder = f.debug_tuple("S");
debug_trait_builder.finish()
}
}
}
}
fn main() {
{
$crate::io::_print($crate::fmt::Arguments::new_v1_formatted(
&["", "\n"],
&match (&S,) {
(arg0,) => [$crate::fmt::ArgumentV1::new(
arg0,
$crate::fmt::Debug::fmt,
)],
},
&[$crate::fmt::rt::v1::Argument {
position: $crate::fmt::rt::v1::Position::At(0usize),
format: $crate::fmt::rt::v1::FormatSpec {
fill: ' ',
align: $crate::fmt::rt::v1::Alignment::Unknown,
flags: 0u32,
precision: $crate::fmt::rt::v1::Count::Implied,
width: $crate::fmt::rt::v1::Count::Implied,
},
}],
));
};
}
Options
See cargo expand --help
for a complete list of options, most of which are
consistent with other Cargo subcommands. Here are a few that are common in the
context of cargo expand.
To expand a particular test target:
$ cargo expand --test test_something
To expand without rustfmt:
$ cargo expand --ugly
To expand a specific module or type or function only:
$ cargo expand path::to::module
Configuration
The cargo expand command reads the [expand]
section of $CARGO_HOME/config if
there is one (usually ~/.cargo/config). Currently the only configuration option
is the syntax highlighting theme.
[expand]
theme = "TwoDark"
Run cargo expand --themes
to print a list of available themes. Use theme = "none"
to disable coloring.
Disclaimer
Be aware that macro expansion to text is a lossy process. This is a debugging aid only. There should be no expectation that the expanded code can be compiled successfully, nor that if it compiles then it behaves the same as the original code.
For instance the following function returns 3
when compiled ordinarily by Rust
but the expanded code compiles and returns 4
.
fn f() -> i32 {
let x = 1;
macro_rules! first_x {
() => { x }
}
let x = 2;
x + first_x!()
}
Refer to The Book for more on the considerations around macro hygiene.
<br>