0

I’d like to have a code that supposed to achieve this in end.

counters!(NAME1, “unit1”, NAME2, “unit2”)

// generates

const NAME1 = 0;
const NAME2 = 1;

static mut counters = [AtomicUsize::new(0), AtomicUsize::new(0)];

static units = [“unit1”, “unit2”]; 

So far I’ve been able to create indices names and the array of arbitrary values, but I have troubles combining this things together.

playgound link

use std::sync::atomic::AtomicUsize;

macro_rules! gen_array {
    ($out:expr; ) => { $out };
    ([$($out:tt)*]; $name:ident, $($names:tt)*) => {
        gen_array!([$($out)* $name,]; $($names)*)
    };
}

macro_rules! gen_vars {
    ($cnt:expr; ) => {};
    ($cnt:expr; $name:ident, $($names:tt)*) => {
        const $name: usize = $cnt;
        gen_vars!($cnt + 1; $($names)*)
    };
}

macro_rules! counters {
    ($($name:ident),+) => {
        gen_vars!(0; $($name),+,);
        gen_array!([]; $($name),+,);
    };
}

fn main() {
    let arr = counters!(ONE, TWO);
    dbg!(arr);
}
user1685095
  • 5,787
  • 9
  • 51
  • 100
  • Isn't it UB to have mutable static data? – Alexey S. Larionov Sep 07 '21 at 15:54
  • In your first code block, `counters!` emits multiple statements, but in your second code block, you use it in place of an expression. Is this by mistake? – Elias Holzmann Sep 07 '21 at 15:56
  • @EliasHolzmann it’s just an artificial of multiple failed attempts. What’s important is the end goal. – user1685095 Sep 07 '21 at 16:29
  • @AlexeyLarionov No, but it is UB if you have aliasing mutable references to it, or cause a data race. You can safely use it if you only have shared references to it or manipulate it from behind a raw pointer in a data-race-free manner. – Aiden4 Sep 07 '21 at 18:13
  • It looks like you copied the code of the first block from a word processor or something -- note the quote marks: `“unit1”` instead of `"unit1"`. In this case the intent is fairly clear; however, please be careful about this in the future. – trent Sep 07 '21 at 19:04
  • @trentcl It’s an iPAD autocorrect works in a such way If you connect keyboard to it. It’s very inconvenient. – user1685095 Sep 08 '21 at 05:08
  • 2
    OTOH, `counters` probably doesn't need to be `mut`: [`AtomicUsize::load`](https://doc.rust-lang.org/1.54.0/std/sync/atomic/struct.AtomicUsize.html#method.load) and [`AtomicUsize::store`](https://doc.rust-lang.org/1.54.0/std/sync/atomic/struct.AtomicUsize.html#method.store) don't need it. – Jmb Sep 08 '21 at 07:12

1 Answers1

2

This seems to do what you want.

use std::sync::atomic::AtomicUsize;

macro_rules! gen_array {
    ($out:expr; ) => { $out };
    ([$($out:tt)*]; $name:literal, $($names:tt)*) => {
        gen_array!([$($out)* $name,]; $($names)*)
    };
}

macro_rules! gen_vars {
    ($cnt:expr; ) => {};
    ($cnt:expr; $name:ident, $($names:tt)*) => {
        const $name: usize = $cnt;
        gen_vars!($cnt + 1; $($names)*)
    };
}

macro_rules! counters {
    ($($name:ident,$value:literal),+) => {
        gen_vars!(0; $($name),+,);
        gen_array!([]; $($value),+,);
    };
}

fn main() {
    counters!(ONE, "unit1", TWO, "unit2");
}

Playground

Elias Holzmann
  • 3,216
  • 2
  • 17
  • 33