Macro returning a certain integer type

In my program I have constants

pub const HEIGHT: usize = 6;
pub const WIDTH: usize = 7;

Now I want my program to use the smallest unsigned integer with at least HEIGHT * WIDTH bits. So intuitively something like

type CustomInt = if HEIGHT * WIDTH < 64 {
    u64
} else {
    u128
}

Now this does not work of course, as the type needs to be known by the compiler. So I tried doing it with macros, but couldn't get it to work.

Here's what I've tried so far:
Declarative Macros seem to not be powerful enough to make comparisons ( > 64 ).
I tried using a Procedural Macro: I defined the constants with macros as well, so HEIGHT!() is 6 and WIDTH!() is 7. I then invoke my macro with
custom_macros::uint_min!(WIDTH!() * HEIGHT!())
but instead of evaluating WIDTH!() and HEIGHT!() first to 6 and 7 respectively, the precompiler just parses the whole argument as a string to the uint_min-macro, which lives in another crate and therefore has no knowledge of what WIDTH!() and HEIGHT!() are.

This works

pub const HEIGHT: usize = 6;
pub const WIDTH: usize = 7;

trait CustomIntHelperTrait<const N: usize> {
    type Ty;
}
impl CustomIntHelperTrait<8> for () {
    type Ty = u8;
}
impl CustomIntHelperTrait<16> for () {
    type Ty = u16;
}
impl CustomIntHelperTrait<32> for () {
    type Ty = u32;
}
impl CustomIntHelperTrait<64> for () {
    type Ty = u64;
}
impl CustomIntHelperTrait<128> for () {
    type Ty = u128;
}
type CustomInt = <() as CustomIntHelperTrait<
    {
        let size = (HEIGHT * WIDTH).next_power_of_two();
        assert!(size <= 128, "HEIGHT * WIDTH is too large");
        if size >= 8 {
            size
        } else {
            8
        }
    },
>>::Ty;

fn main() {
    let _x: CustomInt = 42;
    // uncomment to ask the compiler what type we got :-)
    // let _: () = _x; // -> “expected `()`, found `u64`”
}
4 Likes

Wow, not even a single macro necessary. Thank you so much!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.