Static assert on function arguments

Hi,

I was wondering if there is an idiomatic way to check for static asserts, thus at compile time, on function arguments in order to prevent passing of out of range values in simple scenario.

Let me show you a simple example of my idea:

fn divide(p: i32, q: i32) -> i32 { 
    // First argument of static_assert_not_eq  must be a function argument
    // Second one must be a const expression
    static_assert_not_eq( q, 0 )

    p / q
}

const fn zero() -> i32 {
    0
}

fn use_divide() {
    let x = 0;
    let r0 = divide(6, x); // No assert, crash at run time
    let r1 = divide(6, 0); // Assert at compile time, 0 is a literal, so a const expr
    let r2 = divide(6, zero()); // Assert at compile time, since zero is a c const expr
}

I have noticed that a feature request is open about static assert, but I didn't get if it would also cover this scenario.

Thanks

We do not really have static assertions in Rust, at least not in that form. One alternative we do have is the ability to encode invariants in the type system, e.g.:

use std::num::NonZeroI32;

fn divide(p: i32, q: NonZeroI32) -> i32 { 
    p / q.get()
}

Of course, you can't call this function with an i32. You have to wrap it, at which point you can manually handle the error or say that it should cause a panic:

divide(6, NonZeroI32::new(x).unwrap())

That said, new is not a const function. There is the new_unchecked const fn, but as it name implies, it doesn't actually check it, rather it causes UB if the provided i32 is zero.

Edit: This does actually cause a compilation failure:

const NUM: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(0) };
2 Likes

Thanks for your reply @alice

Anyway I was thinking/hoping a more straightforward solution that doesn't impact on my types definition.