0

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.

Netwave
  • 40,134
  • 6
  • 50
  • 93
  • 4
    Just a note: since Rust 1.57, you don't need the static-assertions crate and can use `assert!()` directly: `const _: () = assert!(...);`. You also get better diagnostics (unfortunately, you cannot use `assert_eq!()` and `assert_ne!()` yet, [since they rely on a non-`const` `fn`](https://doc.rust-lang.org/stable/src/core/panicking.rs.html#135-146)). – Chayim Friedman Jan 31 '22 at 12:44
  • You can also create a `static_assert!()` macro quite easily, for conveience: `macro_rules! static_assert { ($($t:tt)*) => { const _: () = $($t)*; }; }`, then `static_assert!(A::ID == B::ID);`. – Chayim Friedman Jan 31 '22 at 12:46
  • @ChayimFriedman, nice notes, definetly gonna use plain `assert!`. Thanks! – Netwave Jan 31 '22 at 12:49

2 Answers2

3

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));
Netwave
  • 40,134
  • 6
  • 50
  • 93
3

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!");
}
Stargateur
  • 24,473
  • 8
  • 65
  • 91
  • Thanks for the confirmation @Stargateur! It makes sensse. I dont know the magic behind `const_str` though. Something to take a look. – Netwave Jan 31 '22 at 12:31
  • @Netwave a good old loop https://github.com/Nugine/const-str/blob/master/const-str/src/bytes.rs#L14 – Stargateur Jan 31 '22 at 12:36
  • awesome! Actually that may solve my next issue, because I want to check a matrix of those ids while keeping const! – Netwave Jan 31 '22 at 12:43