1

Say we need to declare a fixed size array with values, where the size of the array is defined by a constant that may change depending on compile time settings.

So for example:

let my_array = expand_into_array!(j, ARRAY_SIZE, -v0[j] * f);

Where ARRAY_SIZE is a constant, for example: const ARRAY_SIZE: usize = 3;

Could expand into something like...

let my_array = [
    {let j = 0; {-v0[j] * f}},
    {let j = 1; {-v0[j] * f}},
    {let j = 2; {-v0[j] * f}},
];

Since the expression is a fixed size array, it may be possible to use pattern matching, for a limited number of items ... up to 32 for example.

Is it possible to write a macro that expands an expression N times, based on a constant integer?


Details...

Looking into this, I wrote a macro which defines an array, then fills it in, eg:

const ARRAY_SIZE: usize = 3;

macro_rules! expand_into_array {
    ($index_var:ident, $const_size:expr, $body:expr) => {
        {
            let mut tmp: [_; $const_size] = [0.0; $const_size];
            for $index_var in 0..$const_size {
                tmp[$index_var] = $body;
            }
            // TODO, check $body _never_ breaks.
            tmp
        }
    }
}

pub fn negated_array(v0: &[f64; ARRAY_SIZE]) -> [f64; ARRAY_SIZE] {
    expand_into_array!(j, ARRAY_SIZE, {
        -v0[j]
    })
}

This works as expected, and besides the wrinkle (that the $body expression could include a break). this works without problems.

However initializing the array to 0.0 isn't getting optimized out (changing this value shows up as changes when run with:
cargo rustc --release -- --emit asm

I'd rather not use unsafe { std::mem::uninitialized }.


Update, from asking another question, it seems macros can only match against literals, and not constants.

So this is simply not possible with macros in Rust.

Community
  • 1
  • 1
ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • This question is asking about using constants to declare arrays, the other question is dealing with dynamic vectors. While they're related, I don't think this is a duplicate. – ideasman42 Sep 06 '16 at 10:51
  • 1
    @ker: I think that this is actually a *reverse* of the question you linked. Counting repetitions is tricky, but doable, here however the question is about *generating* repetitions when there are none in the input (just a literal number). – Matthieu M. Sep 06 '16 at 10:59
  • The [implementation of `Default` for primitive arrays](https://github.com/rust-lang/rust/blob/master/src/libcore/array.rs#L221) is close (up to a fixed length). You might be able to replace the sequence of `T`s in the macro call with a clever expression which lets you pass the index in. – Chris Emerson Sep 06 '16 at 10:59
  • Read all 3 questions marked as duplicate, and they all seem only *slightly* related. While its not useful to have every variation of a question, is it necessary to be so zealous marking duplicates here? Also, the other questions seem quite a bit more advanced then this one. – ideasman42 Sep 06 '16 at 11:54
  • @ideasman42: The first one (http://stackoverflow.com/questions/33751796/is-there-a-way-to-count-with-macros) is actually spot on, although simpler. – Matthieu M. Sep 06 '16 at 13:10
  • @MatthieuM. this matches against a literal, not a constant *(noted in the title and the example)*. From checking on this further it seems this is the reason attempting to follow similar methods to the answers given failed. – ideasman42 Sep 06 '16 at 13:43
  • @ideasman42: Oh sorry, I am afraid that it was so clear to everyone that using macros necessarily meant using a literals (since they do not evaluate values, only reason in tokens) that we took for granted that the actual issue was in the generation of repetitions. Since you opened a new question specifically on the constant/literal distinction though I would say it does not matter. – Matthieu M. Sep 06 '16 at 13:46
  • Since this question is not a duplicate, could the duplicate mark be removed? – ideasman42 Sep 12 '16 at 13:14

0 Answers0