Netwave
Netwave

Reputation: 42756

Is it possible to const assert trait const value equality?

I have some example code, in where I tried to use static_assertions crate. But I am not sure it is even possible.

use static_assertions::{const_assert_eq, const_assert_ne};

pub trait Foo {
    const ID: &'static str;
}

struct A;
struct B;

impl Foo for A {
    const ID: &'static str = "A";
}

impl Foo for B {
    const ID: &'static str = "B";
}


const fn assert_ids() {
    const_assert_ne!(A::ID, B::ID);
}

fn main() {
    assert_ids();
    println!("Compiles successfully!");
}

Playground

Fails compiling with:

error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
  --> src\main.rs:35:5
   |
35 |     const_assert_ne!(A::ID, B::ID);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: this error originates in the macro `const_assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info)

I have been reading on some threads like:

but couldn't related it.

EDIT:

When changing the type to usize in the trait:

pub trait Foo {
    const ID: usize;
}

The above example works. So I guess it may be related to the type being &'static str.

Upvotes: 1

Views: 4226

Answers (2)

Netwave
Netwave

Reputation: 42756

A combination of const_str and static_assertions crates worked for the purpose:

use static_assertions::{const_assert};
use const_str;

pub trait Foo {
    const ID: &'static str;
}

struct A;
struct B;

impl Foo for A {
    const ID: &'static str = "A";
}

impl Foo for B {
    const ID: &'static str = "B";
}


const fn assert_ids() {
    const_assert!(!const_str::equal!(A::ID, B::ID));
}

fn main() {
    assert_ids();
    println!("Compiles successfully!");
}

As per @ChayimFriedman suggestion, since rust 1.57 it is possible to use plain assert!:

const _: () = assert!(const_str::equal!(A::ID, B::ID));

Upvotes: 4

Stargateur
Stargateur

Reputation: 26757

The problem here is that str::eq() is not const. For now you can only compare primitive type such as integers, chars, bools. I don't know if there is a tracking issue for str and slice. #67792

So yes it's possible but not with str:

pub trait Foo {
    const ID: i32;
}

struct A;
struct B;

impl Foo for A {
    const ID: i32 = 42;
}

impl Foo for B {
    const ID: i32 = 3;
}

const fn assert_ids() {
    if A::ID == B::ID {
        panic!("nooooo");
    }
}

fn main() {
    assert_ids();
    println!("Compiles successfully!");
}

Upvotes: 3

Related Questions