Macro iunpack

Source
macro_rules! iunpack {
    (@if($($t:tt)*) else $($f:tt)*) => { ... };
    (@if else $($f:tt)*) => { ... };
    {@revpat_do_iter_back($iter:ident, $body:block, $errbody:expr)
        $(($used:pat) $(($pat:pat))*)?
    } => { ... };
    {@sized_pat($iter:ident, $body:block, $errbody:block, $errval:ident)
        $($fpat:pat $(, $pat:pat)*)?
    } => { ... };
    {@sized_pat($iter:ident, $body:block, $errbody:block)
        $($fpat:pat $(, $pat:pat)*)?
    } => { ... };
    {
        $($pat:pat),* $(,)?
        = $iter:expr => $body:block
        else $errbody:expr
    } => { ... };
    {
        $($pat:pat),* $(,)?
        = $iter:expr => $body:block
        else($err:ident) $errbody:block
    } => { ... };
    {
        $($fpat:pat ,)* * $($mid:ident $(: $ty:ty)?)? $(, $bpat:pat)* $(,)?
        = $iter:expr => $body:block
        else $errbody:expr
    } => { ... };
    {
        $($fpat:pat ,)* *=$mid:ident $(, $bpat:pat)* $(,)?
        = $iter:expr => $body:block
        else $errbody:expr
    } => { ... };
    {
        $($fpat:pat ,)* ** $(, $bpat:pat)+ $(,)?
        = $iter:expr => $body:block
        else $errbody:expr
    } => { ... };
    {
        $($fpat:pat ,)* ** $mid:ident $(: $ty:ty)? $(, $bpat:pat)+ $(,)?
        = $iter:expr => $body:block
        else $errbody:expr
    } => { ... };
}
Expand description

Use pattern unpack iterator

The expression after the equal sign must implement IntoIterator.
The final pattern may be followed by a trailing comma.

Use else to handle iterator length mismatch or pattern mismatch

  • Use *name pattern any elements to Vec, use DoubleEndedIterator pattern end elements.
  • Use *name: Type pattern any elements collect into impl FromIterator.
  • Use *=iter pattern start and end elements, do not check iter is stopped. Internally use the given variable name to store iterator for future use.
  • Use **name like *name, but use Iterator

There may be an internal loop, please use the label to break or continue.

ยงExamples

Sized iterator

assert_eq!(iunpack!(a, b, c, d, e = 0..5 => {
    (a, b, c, d, e)
} else panic!()), (0, 1, 2, 3, 4));

assert_eq!(iunpack!(a, b, c, d, e = 0..3 => {
    panic!()
} else(err) {
    err
}), 3); // fail, not enough values

assert_eq!(iunpack!(a, b, c, d, e = 0..7 => {
    panic!()
} else(err) {
    err
}), 5); // fail, too many values

Any size iterator

assert_eq!(iunpack!(a, b, *c, d, e = 0..8 => {
    (a, b, c, d, e)
} else panic!()), (0, 1, vec![2, 3, 4, 5], 6, 7));

assert_eq!(iunpack!(a, b, *=c, d, e = 0..8 => {
    (a, b, c.collect::<Vec<_>>(), d, e)
} else panic!()), (0, 1, vec![2, 3, 4, 5], 6, 7));

assert_eq!(iunpack!(a, b, *c: HashSet<_>, d, e = 0..8 => {
    (a, b, c, d, e)
} else panic!()), (0, 1, HashSet::from([2, 3, 4, 5]), 6, 7));

// use Iterator, is not DoubleEndedIterator
assert_eq!(iunpack!(a, b, **c, d, e = 0..8 => {
    (a, b, c, d, e)
} else panic!()), (0, 1, vec![2, 3, 4, 5], 6, 7));

// no collect
assert_eq!(iunpack!(a, b, *, d, e = 0..8 => {
    (a, b, d, e)
} else panic!()), (0, 1, 6, 7));

// use Iterator, is not DoubleEndedIterator, no collect
assert_eq!(iunpack!(a, b, **, d, e = 0..8 => {
    (a, b, d, e)
} else panic!()), (0, 1, 6, 7));

Pattern example

assert_eq!(iunpack!(_a, _b, 2..=10 = 0..3 => { true } else panic!()), true);

assert_eq!(iunpack!((0 | 1 | 2), _b, _c = 0..3 => {
    true
} else panic!()), true);

assert_eq!(iunpack!(*, 2..=10 = 0..3 => {
    true
} else panic!()), true);

assert_eq!(iunpack!((0 | 1 | 2), * = 0..3 => {
    true
} else panic!()), true);

// fails
assert_eq!(iunpack!(_a, _b, 3..=10 = 0..3 => {
    panic!()
} else true), true);

assert_eq!(iunpack!((1 | 2), _b, _c = 0..3 => {
    panic!()
} else true), true);

assert_eq!(iunpack!(_a, **, 3..=10 = 0..3 => {
    panic!()
} else true), true);

assert_eq!(iunpack!((1 | 2), * = 0..3 => {
    panic!()
} else true), true);