brownstone

Macro build

Source
macro_rules! build {
    (|$prefix:ident : &[$type:ty]| $item:expr $(; $len:expr)?) => { ... };
    (|$index:ident : usize| $item:expr $(; $len:expr)?) => { ... };
    ($item:expr $(; $len:expr)?) => { ... };
}
Expand description

Build an array with an expression.

This macro builds an array by calling an expression once for each element in the array:

use brownstone::build;

let x: [String; 3] = build!["hello".to_owned()];
assert_eq!(x, ["hello", "hello", "hello"])

You can also provide an explicit length in the macro, if the length can’t be inferred from context:

use brownstone::build;

let x = build!["hello".to_owned(); 3];
assert_eq!(x, ["hello", "hello", "hello"]);

If needed, you can use a closure syntax (with a usize parameter) to evaluate your expression with the index of the item being evaluated:

use brownstone::build;

let x = build!(|index: usize| (index as i32) * 2; 4);
assert_eq!(x, [0, 2, 4, 6]);

You can also instead use an &[T] parameter to to evaluate your expression with the full prefix of the array that has already been built:

use brownstone::build;

let x = build!(|prefix: &[i32]| match prefix {
    [.., a, b] => a + b,
    _ => 1,
});

assert_eq!(x, [1, 1, 2, 3, 5, 8, 13]);

All of these forms (even the closure-style forms) are evaluated locally, which means that you can use arbitrary* control flow inside the builder, such as ? or return or await:

use std::{io, num};
use brownstone::build;

#[derive(Debug)]
enum Error {
    Io(io::Error),
    Parse(num::ParseIntError),
}

fn read_4_ints(mut input: impl io::BufRead) -> Result<[i32; 4], Error> {
    let mut line = String::new();

    let array = build!({
        line.clear();
        input.read_line(&mut line).map_err(Error::Io)?;
        line.trim().parse().map_err(Error::Parse)?
    });

    Ok(array)
}

let data = b"12\n4\n6\n21\n5";
let data = read_4_ints(data.as_slice()).expect("failed to read or parse");
assert_eq!(data, [12, 4, 6, 21]);

* Currently it doesn’t support break or continue; this is a bug and will be fixed in a future release.