Skip to content

Instantly share code, notes, and snippets.

@jirutka
Last active January 15, 2023 12:00
Show Gist options
  • Save jirutka/7161f1bcc7d4d79aeed8e06a57b26d74 to your computer and use it in GitHub Desktop.
Save jirutka/7161f1bcc7d4d79aeed8e06a57b26d74 to your computer and use it in GitHub Desktop.
Rust with! macro, aka tap, methods cascade, method chaining…
// Sources:
// * https://internals.rust-lang.org/t/method-chaining-special-form/342
// * https://github.com/rust-lang/rust/issues/6679
// * https://gist.github.com/huonw/2812cd9433dc5f0cf7f2
// * https://www.reddit.com/r/rust/comments/2wssch/function_chaining/
//
// TODO:
// * How to correctly process generic methods (e.g. collect::<Vec<_>>() ?)
macro_rules! with {
(
$subj:expr;
$(
$(
.$meth:ident($( $arg:expr ),*)
)+
),+
$(,)* // permit trailing commas
) => {{
let mut subj = $subj;
$(
subj$( .$meth($($arg),*) )+;
)+
subj
}};
}
#[cfg(test)]
mod tests {
#[test]
fn with() {
let actual = with!(vec![1, 2]; .push(4), .push(8));
assert_eq!(actual, vec![1, 2, 4, 8])
}
#[test]
fn with_trailing_comma() {
let actual = with!(vec![1, 2]; .push(4), .push(8),);
assert_eq!(actual, vec![1, 2, 4, 8])
}
#[test]
fn with_method_calls() {
let actual = with! { vec!["hi".to_string()];
.push("there".into()),
.get_mut(1).map(|v| v.push('?')),
};
assert_eq!(actual, vec!["hi".to_string(), "there?".to_string()])
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment