Macro that, when called, generates next typenum

I know that it is possible using procedural macros to generate a macro that, when called, generates an ever increasing sequence of typenum's.

Is it possible to do this as a macro_rules? where

first call to magic!() -> 0
second call to magic!() -> 1
third call to magic!() -> 2
...

No, macro_rules! cannot keep state between invocations. Proc macros are also not supposed to do this.

This matches my intuition.

Can you cite any official reference for this? I'm currently agnostic on whether procedural macros should/should not do this.

There's no guarantees on the order proc macros execute, so if you're relying on it you may be surprised in the future. I'm not sure if this is explicitly stated anywhere, but it's certainly not stated that you can.

1 Like

So in this particular case, the order is not important, as long as they are different .

That’s also not guaranteed. Due to incremental compilation, proc macro results can be cached and reused run-to-run, or the compiler could spin up several processes that run in parallel. At least in theory.

To solve this problem, I ended up writing a typenum UUID generator.

2 Likes

I'm missing something obvious. I don't see where you call hash, random, or rnd. How are you generating the unique number ?

Phrased another way, in theory, if I call this gen_unique_typenum!() proc-macro 20 times in my program, in theory, rustc could decide "this is an expensive looking pacro macro; let me run it 20 times in parallel", then instead of some permutation of {0, 1, 2, .., 19} we get 20 0's.

This does sound like a legitimate concern. It's reasonable that rustc, to speed up compilation, run multiple proc-macro instances in parallel. It's also unreasonable to expect that incremental compilation somehow 'freeze / save' the proc-macro state in between runs.

I guess the solution here, within a single crate, to generate all the Labels at once.

1 Like

The call to Uuid::new_v4() generates a random UUID.

1 Like

Is it possible to guarantee that if we call with the same prefix, we always get the same UUID back?

I understand the due to the birthday paradox, the probability of collisions are tiny, but the idea that every time I compile, the compiler generates a bunch of random numbers, and if they collide, the compilation fails, -- makes me uncomfortable.

Good instincts. (The compiler needs to solve the same problem for TypeId.)

Obligatory quotation:

The probability that your entire development team is killed by wolves in the same night, at precisely the same point in time where a meteor lands on your data center, is much higher than the collision probability of UUIDs.

~ java - How to ensure that generated id does not exist in database - Stack Overflow

(Note that TypeId is different, as it's only 64-bits. The extra safety from 128-bit UUIDs, though, means that just isn't an issue.)

1 Like

The full quote is:

Why did you cut out the part where I explicitly state:

I don't see how this is a good faith argument.

Even when doing a clean build the macro could be run multiple times with the same input and rustc, seeing as the input hasn't changed, could expect the output to not change either and so it could reuse the initial output for the other runs. Not sure if this is how it currently works, but it wouldn't be unreasonable.