Macro crecurse

Source
macro_rules! crecurse {
    (@macro_def ($dol:tt) $name:ident $($cargs:ident)*) => { ... };
    (
        @static [$(($cargs:ident, $cargsexpr:expr, $cargsty:ty))*] [$(,)?],
        fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) -> $ret:ty $body:block
    ) => { ... };
    (@static [$($pcaps:tt)*] [$(,)?], fn $func:ident ($($argstt:tt)*) $($rest:tt)*) => { ... };
    (@static [$($pcaps:tt)*] [$carg:ident: &mut $cargty:ty, $($caps:tt)*], $($rest:tt)*) => { ... };
    (@static [$($pcaps:tt)*] [$carg:ident: &$cargty:ty, $($caps:tt)*], $($rest:tt)*) => { ... };
    (@static [$($pcaps:tt)*] [$carg:ident: $cargty:ty, $($caps:tt)*], $($rest:tt)*) => { ... };
    ($([$($caps:tt)*],)? static fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) $($rest:tt)*) => { ... };
    (
        @default [$($cargs:ident: $cargsty:ty),* $(,)?],
        fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) -> $ret:ty $body:block
    ) => { ... };
    (@default [$($caps:tt)*], fn $func:ident ($($argstt:tt)*) $($rest:tt)*) => { ... };
    ($([$($caps:tt)*],)? fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) $($rest:tt)*) => { ... };
    (
        @unsafe [$($cargs:ident: $cargsty:ty),* $(,)?],
        fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) -> $ret:ty $body:block
    ) => { ... };
    (@unsafe [$($caps:tt)*], fn $func:ident ($($argstt:tt)*) $($rest:tt)*) => { ... };
    ($([$($caps:tt)*],)? unsafe fn $func:ident ($($args:ident: $argsty:ty),* $(,)?) $($rest:tt)*) => { ... };
    ($($t:tt)*) => { ... };
}
Expand description

Macro that returns a recursive function that (semi-)automatically captures.

§Example

default version

let mut res = 0usize;
let coeff = 3usize;
crecurse!(
    // (1) semi-automatically capture mutable reference (res: &mut usize)
    [res: usize],
    fn mul(x: usize, y: usize) {
        if y > 0 {
            if y % 2 == 1 {
                // (2) automatically capture reference (coeff: &usize)
                *res += coeff * x;
            }
            // (3) call macro to recurse
            mul!(x + x, y / 2);
        }
    }
)(10, 19); // (4) macro returns captured version of the recursive function
assert_eq!(res, coeff * 10 * 19);

unsafe version (automatically capture everything)

let mut res = 0usize;
let coeff = 3usize;
crecurse!(
    unsafe fn mul(x: usize, y: usize) {
        if y > 0 {
            if y % 2 == 1 {
                res += coeff * x;
            }
            mul!(x + x, y / 2);
        }
    }
)(10, 19);
assert_eq!(res, coeff * 10 * 19);

no overhead version (semi-automatically capture everything)

let mut res = 0usize;
let coeff = 3usize;
crecurse!(
    [res: &mut usize, coeff: &usize],
    static fn mul(x: usize, y: usize) {
        if y > 0 {
            if y % 2 == 1 {
                *res += coeff * x;
            }
            mul!(x + x, y / 2);
        }
    }
)(10, 19);
assert_eq!(res, coeff * 10 * 19);

§Syntax

crecurse!(
    ([($ident: $type),*,?],)?
    (unsafe|static)? fn $ident\(($ident: $type),*,?\) (-> $type)? $block
)