Macro tuplez::folder

source ·
macro_rules! folder {
    ($($t:tt)*) => { ... };
}
Expand description

Provides a simple way to build a folder that implements Folder.

§Syntax

Generic = [Lifetime1, Lifetime2, ...] [Type1 [: Bound1], Type2 [: Bound2], ...]
Rule    = [ < Generic > ] | Variable1, Variable2 : InputType | { Body } [,] [;]

folder!( OutputType; [Rule1 Rule2 ... ] )

[ and ] only indicate the optional content but not that they need to be input.

Similarly, ... indicates several repeated segments, rather than inputting ....

§Explanation

A folding rule is much like a closure, except that it must annotate the element type:

|acc, x: i32| { acc + x }

Note that it’s just like but not really a closure, so you can’t capture context variables.

You’d better not annotate types for the accumulation value and return value, because they must to be annotated uniformly. Of course you can do that, but there would be no advantage other than potential compilation errors.

Also supports adding mut:

|mut acc, mut x: i32| -> i64 { acc += 1; x += 1; acc + x }

You can also introduce generic types like this:

<T: ToString> |x: Option<T>| { x.unwrap().to_string() }

You need to determine the type of the accumulation value, for example, i32. Then, construct folding rules for all element types in the tuple, and then combine them in the folder! macro to fold the tuple:

use std::convert::AsRef;
use tuplez::{folder, tuple, TupleLike};

let tup = tuple!(1, "2", 3.0);
let result = tup.fold(
    folder! {i32;        // Annotate the accumulation value type
        |acc, x: i32| { acc + x }
        |acc, x: f32| { acc + (x as i32) }
        // `str` is a DST, so `?Sized` bound is required.
        <T: AsRef<str> + ?Sized> |acc, x: &T| { acc + x.as_ref().parse::<i32>().unwrap() }
    },
    0
);
assert_eq!(result, 6);

It is allowed to add commas or semicolons as separators between rules. Sometimes this may look better.