How to assert size of `usize` to drop support for incompatible platforms?

266 views Asked by At

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?

1

There are 1 answers

2
Chayim Friedman On

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).