#[doc(hidden)]
#[macro_export]
macro_rules! do_expression {
($var:expr, ($($exprs:tt)*)$($tail:tt)*) => {
$crate::do_expression!($crate::do_expression!($var, $($exprs)*), $($tail)*)
};
($var:expr, [$expr:tt]$($tail:tt)*) => {
$crate::do_expression!($var[$expr], $($tail)*)
};
($var:expr, *$($tail:tt)*) => {
*$crate::do_expression!($var, $($tail)*)
};
($var:expr, .$expr:tt$($tail:tt)*) => {
$crate::do_expression!($var.$expr, $($tail)*)
};
($var:expr,) => {
$var
}
}
#[macro_export]
macro_rules! pluck {
(&mut $($expr:tt)+) => {
|value| &mut $crate::do_expression!(value, $( $expr )+)
};
(&$($expr:tt)+) => {
|value| & $crate::do_expression!(value, $( $expr )+)
};
($($expr:tt)+) => {
|value| $crate::do_expression!(value, $( $expr )+)
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ref_to_triple_deref() {
let list = vec![&&&0, &&&1, &&&2];
let derefed = list.into_iter().map(pluck!(&***)).collect::<Vec<_>>();
assert_eq!(derefed, &[&0, &1, &2]);
}
#[test]
fn mut_ref_deref() {
let mut list = vec![0, 1, 2];
let derefed = list.iter_mut().map(pluck!(&mut *)).collect::<Vec<_>>();
assert_eq!(derefed, &[&0, &1, &2]);
}
#[test]
fn deref_index() {
let mut list = vec![[&0], [&1], [&2]];
let derefed = list.iter_mut().map(pluck!(*[0])).collect::<Vec<_>>();
assert_eq!(derefed, &[0, 1, 2]);
}
#[test]
fn nested_index() {
let mut list = vec![[[0]], [[1]], [[2]]];
let derefed = list.iter_mut().map(pluck!([0][0])).collect::<Vec<_>>();
assert_eq!(derefed, &[0, 1, 2]);
}
#[test]
fn nested_property() {
struct Person { address: Address }
struct Address { street: &'static str }
let mut list = [Person { address: Address { street: "foo" } }];
let streets = list.iter_mut().map(pluck!(.address.street)).collect::<Vec<_>>();
assert_eq!(streets, &["foo"]);
}
#[test]
fn index_deref() {
let mut list = vec![[&[0]], [&[1]], [&[2]]];
let derefed = list.iter_mut().map(pluck!((*[0])[0])).collect::<Vec<_>>();
assert_eq!(derefed, &[0, 1, 2]);
}
#[test]
fn index_deref_property() {
struct Person { name: &'static str }
let mut list = vec![[&Person { name: "Alice" }]];
let derefed = list.iter_mut().map(pluck!((*[0]).name)).collect::<Vec<_>>();
assert_eq!(derefed, &["Alice"]);
}
}