2

I would like to port some C code to Rust that does something similar to nullable pointers but with positive integers. Missing data in some large data structures is represented with negative integer values in a signed integer. 31 bits are available for the main value, and what is essentially an empty enum variant is packed into the sign bit.

Rust has the nullable pointer optimization to do something very similar with pointers.

I could do a 1 to 1 port and keep using raw signed integers for this, but is there a better way that doesn't incur a performance penalty? Some sort of advanced enum repr hint?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Andrew Wagner
  • 22,677
  • 21
  • 86
  • 100
  • 1
    When you say "performance penalty", you're meaning "memory performance", right? – Boiethios Oct 24 '18 at 07:42
  • You should be able to use `Option`, I think it was designed specifically for this kind of situation: https://doc.rust-lang.org/core/num/struct.NonZeroU32.html – Tarmil Oct 24 '18 at 09:11
  • 1
    I don't believe this is a real duplicate. `NonZeroU32` does something different; adding a bijection (as Matthieu's answer suggests) will work, but adds a performance penalty. – trent Oct 24 '18 at 13:17
  • This question is not a duplicate. Matthieu's answer is a good answer here, but wouldn't work on the other question. It may be possible to merge the two question into a more general one, but as they currently stand they are different. – Sven Marnach Oct 24 '18 at 15:37
  • "Reversing" the logic and returning an `Option<>` instead of using an `Option<>` is an alternative for avoiding memory penality. Since this is marked as duplicated [see here](https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=77b1a9b0072e127b0837e1fe042419e7) for an example. – attdona Oct 24 '18 at 19:38

1 Answers1

3

As mentioned by @Tarmil in comments, this is the exact usecase for NonZeroU32.

NonZeroU32 is known, by the compiler, never to be 0 and therefore Option<NonZeroU32> is 4 bytes, like a regular u32.

When 0 is a valid value for you, it is best to wrap Option<NonZeroU32> within your own type which performs a bijection between your domain values and the [1..2^32-1] domain:

  • when receiving a negative value, set field to None.
  • when receiving a positive value, add 1 (and substract 1 when reading).

Since your values are originally signed, there is no risk of overflow when adding 1, so there is no issue.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722