1

Problem

I've just caught my self writing dynamic assertion that depends on a constant usize::MAX.
I wrote:

  u128::try_from(letters.len())
     .expect("No suppor for platform with `max pointer value` >= 2**128.")

where letters.len() is an instance of usize.

Instead, I'd like my code to fail to compile on so rare (if existing) platforms with "pointers size >= 2**128".

I already know/read:

I've read a similar question (suggested by community). It shows methods to assert concrete size of pointer.
eg. #[cfg(not(target_pointer_width = "64"))]
I want my code to be very flexible. It's enough for usize::MAX<=u128::MAX && usize::MIN>=u128::MIN to be true.

Small reflection (maybe solution)

After some thinking, I concoct a solution that works quite good, both in my head & on the currently tested Debian with x64 architecture and Rust 1.60.
Code: const _:()= assert!(usize::BITS<=u128::BITS);
Do you know any cleaner & edge-case-proof resolution?

Sir
  • 337
  • 1
  • 7
  • This is a _direct_ duplicate, but for more general questions about static assertions in Rust see (related, but not exactly) [Compile-time generic type size check](https://stackoverflow.com/q/30330519/7884305); Wow, there aren't (well, I couldn't find) any questions about general const assert in Rust!! – Chayim Friedman May 28 '22 at 21:36
  • Your approach of `assert!()` is fine. As for the duplicate... I voted to re-open. There is no way to say GT/LT with `cfg`. However, not that, depending on your code, you may want a constant set of sizes, actually - will your code work with 48-bits sized pointers? – Chayim Friedman May 28 '22 at 22:25

1 Answers1

0

assert!() is fine. assert!() is only available in const contexts since Rust 1.57.0, so if you need to support older versions you can use the static_assertions crate. The idea is to replace assert!() with the following constant expression:

const _: [(); 0 - (!(usize::BITS <= u128::BITS)) as usize] = [];

Now, if the expression evaluates to true, its negation evaluates to false, and false as usize is zero. So we're declaring a zero-length array and everything is fine.

However, if the expression evaluates to false, its negation is true, and true as usize == 1. 0usize - 1usize overflows - and that is an error.

The downside is that it generates a pretty obscure error message:

error[E0080]: evaluation of constant value failed
 --> src/lib.rs:1:15
  |
1 | const _: [(); 0 - (!(usize::BITS > u128::BITS)) as usize] = [];
  |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow

(I swapped the condition so it will be false).

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
  • I don't understand what is an advantage of your solution over the one have shown: `const _:()= assert!(usize::BITS<=u128::BITS)` – Sir Jun 03 '22 at 07:00
  • @Sir That it works in Rust versions before 1.57.0. "so if you need to support older versions..." – Chayim Friedman Jun 05 '22 at 20:26