Macro using

Source
macro_rules! using {
    ($target:expr => { $( $t:tt )* }) => { ... };
    ($id:ident @ $target:expr => { $( $t:tt )* }) => { ... };
}
Expand description

A macro that provides method cascading for an object.

§Usage

using!(expression => { ... })

using!(identifier @ expression => { ... })

Binds expression to a mutable variable (called “target”) that can be manipulated inside the block with expressions starting with a dot (called “target expressions”). The target variable can be explicitly named with an @-binding. If the block does not contain a trailing expression, the target is returned instead.

Target expression are a sequence of field accessess (e.g. .x) and method calls (e.g. .push(10)) and can only be used in blocks, let statements, bodies of if expressions, match expressions, and loops. They cannot be used in the conditional expressions and also not in compound expressions, e.g. .last().unwrap() + 1 is not valid. For details see below.

Besides the target expressions, every statement and expression can be used inside the block, which also allows nesting using macros.

§Examples:

let hello_world = using!(Vec::new() => {
    .push("Hello");
    .push("World!");
    .join(", ")
});
assert_eq!(hello_world, "Hello, World!");

// Generated code:
//
// let hello_world = {
//     let mut target = Vec::new();
//     target.push("Hello");
//     target.push("World!");
//     target.join(", ")
// };

More complicated example with for, if, and let:

let vec = using!(Vec::new() => {
    for i in 0..10 {
        if i % 2 == 0 {
            .push(i);
        }
    }
    let sum = .iter().sum();
    .push(sum);
});
assert_eq!(&vec[..], [ 0, 2, 4, 6, 8, 20 ]);

§Syntax:

This section explains the syntax in a BNF-like form to clarify the details and where target expressions can be used. The symbols IDENTIFIER, Statement, Expression, BlockExpression, Pattern, GenericArgs, CallParams, and Type are defined in The Rust Reference. The syntax of the macro is defined by:

"using" "!" "(" Expression "=>" UsingBlock ")"

"using" "!" "(" IDENTIFIER "@" Expression "=>" UsingBlock ")"

A UsingBlock is an extension of Rusts BlockExpression: it is a block surrounded by curly braces, containing a sequence of UsingStatements followed by an optional UsingExpression.

A UsingStatement is either a Statement or one of the following:

UsingExpression ";"

"let" IDENTIFIER ( ":" Type )? = UsingExpression ";"

A UsingExpression is either an Expression or one of the following:

UsingBlock

// This defines the "target expressions"
( "." IDENTIFIER | "." IDENTIFIER ( "::" GenericArgs )? "(" CallParams? ")" )+

"if" Expression UsingBlock ( "else" "if" Expression UsingBlock )* ( "else" UsingBlock )?

"match" Expression "{" ( Pattern ( "if" Expression )? => ( UsingBlock | UsingExpression "," ) )* "}"

"loop" UsingBlock

"while" Pattern "in" Expression UsingBlock

"for" Pattern "in" Expression UsingBlock