#array-vec #array #vec #macro #literals #default-value

no-std array-lit

Macros for array and Vec literals with superpowers

2 unstable releases

0.2.0 May 9, 2020
0.1.0 May 8, 2020

#1984 in Rust patterns

Download history 5/week @ 2024-03-13 8/week @ 2024-03-27 6/week @ 2024-04-03 9/week @ 2024-05-22 64/week @ 2024-05-29 60/week @ 2024-06-05 54/week @ 2024-06-12 78/week @ 2024-06-19 64/week @ 2024-06-26

270 downloads per month

MIT/Apache

16KB
153 lines

array-lit

Documentation · Crates.io · Lib.rs

Rust macros for array and Vec literals with superpowers. The macro for arrays is called arr!; the macro for Vec is called vec! and shadows the macro from the standard library.

They allow creating an array or Vec where only some elements are specified, and the rest is set to a default value.

The following macro specifies three consecutive values at index 0:

let a = arr![0; 8; { [0]: [1, 2, 3] }];
assert_eq!(a, [1, 2, 3, 0, 0, 0, 0, 0]);

The square brackets are only needed when specifying multiple consecutive elements:

let a = arr![1; 8; { 6: 0 }];
assert_eq!(a, [1, 1, 1, 1, 1, 1, 0, 1]);

You can specify as many single and consecutive values as you like:

let a = arr![0; 8; {
    6: 1,            // 1 at index 6
    [2]: [3, 4],     // 3 and 4 starting from index 2
    7: 5,            // 5 at index 7
}];
assert_eq!(a, [0, 0, 3, 4, 0, 0, 1, 5]);

The familiar array syntax (arr![a; N] and arr![a, b, c]) is also supported, so the vec! macro from this crate is a drop-in replacement for std::vec!.

How does it work?

The macros generate a block that first creates a array or Vec, and then inserts the specified values:

arr![4; 10; { 0: 0, 1: 1 }]
// is expanded to
{
    let mut arr = [4; 10];  // in the vec! macro, std::vec! is used
    arr[0] = 0;
    arr[1] = 1;
    arr
}

If an array is inserted that is not of the form [a, b, c, ..], a loop is used:

arr![4; 10; { [1]: [2; 4] }]
// is expanded to
{
    let mut arr = [4; 10];
    let mut i = 1;
    let end = i + 4;
    while i < end {
        arr[i] = 2;
        i += 1;
    }
    arr
}

This even works for slices, arrays and Vecs created at runtime:

let my_slice = &[1, 2, 3, 4];
arr![4; 10; { [1]: my_slice }];

What about array lifetimes?

In trivial cases such as arr![3; 5], the 'static lifetime is inferred for array literals. This means that they have the exact same behavior as normal array literals.

In the other cases, the 'static lifetime is not inferred. This means that the array literal is computed at runtime and doesn't have a fixed memory location. It also means that the following

// does NOT compile!
fn return_temporary() -> &'static [i32; 4] {
    &arr![0; 4; { 0: 1 }]
}

produces error[E0515]: cannot return reference to temporary value. This can be solved by assigning the literal to a const or static variable first:

fn return_temporary() -> &'static [i32; 4] {
    static ARR: &[i32; 4] = &arr![0; 4; { 0: 1 }];
    ARR
}

Values assigned to a static or const variable must be constant. Due to limitations in the compiler, macros that expand to loops aren't allowed there:

// does NOT compile!

const ARR: [i32; 4] = arr![0; 16; { [0]: [1; 8] }];
// this is expanded to a loop ~~~~~~~~~~~^^^^^^

Note that const enforces const evaluation, which means that the whole array is included in the application binary. This might not be desirable if the array is large.

Usage

Import the macros with

use array_lit::{arr, vec};

If you don't want to shadow std::vec!, you can rename the macro:

use array_lit::{arr, vec as vector};

Importing the macros globally is also supported, although not recommended:

#[macro_use]
extern crate array_lit;

Custom indices

If you want to use your own Index/IndexMut implementation in these macros, you probably need an extra pair of parentheses:

#[derive(Copy, Clone)]
struct S(bool);

/// Your custom index
struct Idx(usize);

impl std::ops::Index<Idx> for Vec<S> {
    type Output = bool;
    // etc.
}

impl std::ops::IndexMut<Idx> for Vec<S> {
    // etc.
}

vec![S(true); 1000; { (Idx(16)): false }];
// parens needed ~~~~~^~~~~~~~^

no_std support

This library supports no_std, if default features are disabled. This makes the vec! macro unavailable.

Minimum required Rust version

Requires Rust 1.33.

License

Licensed under MIT or Apache 2.0 at your choice.

No runtime deps

Features