炸鱼薯条德里克
炸鱼薯条德里克

Reputation: 999

How to test for type equality in Rust?

I need to test if two types are equal in const fn. Comparing the TypeId doesn't work:

#![feature(const_if_match)]
#![feature(const_fn)]
#![feature(const_type_id)]

const fn t<T1: 'static, T2: 'static>() -> bool{
    std::any::TypeId::of::<T1>() == std::any::TypeId::of::<T2>()
}

Error:

error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 --> src/lib.rs:5:8
  |
5 |     std::any::TypeId::of::<T1>()==std::any::TypeId::of::<T2>()
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Template specialization as in C++ does not work in Rust, as Rust doesn't have "templates specialization". So, is there any way to test for type equality in Rust?

Upvotes: 9

Views: 7546

Answers (2)

user-id-14900042
user-id-14900042

Reputation: 1284

another stable solution with abusing auto-deref specialization:

macro_rules! eq_type {
    ($a:ty, $b:ty) => {
        {
            use $crate::EqType;
            (&&&$crate::Wrap::<($a, $b)>(::core::marker::PhantomData)).eq_type()
        }
    }
}

struct Wrap<T>(::core::marker::PhantomData<fn(T) -> T>);

trait EqType {
    fn eq_type(&self) -> bool;
}

impl<A> EqType for &&Wrap<(A, A)> {
    fn eq_type(&self) -> bool {
        true
    }
}

impl<A, B> EqType for &Wrap<(A, B)> {
    fn eq_type(&self) -> bool {
        false
    }
}

mod tests {
    #[test]
    fn as_eq() {
        assert!(eq_type!(i32, i32));
    }
    
    #[test]
    fn as_ne() {
        assert!(!eq_type!(i32, u32));
    }
}

Upvotes: 2

Freyja
Freyja

Reputation: 40794

If you're using Rust nightly (which it seems like you are), you can use the unstable specialization feature and some helper traits to do this:

#![feature(specialization)]

/// Are `T` and `U` are the same type?
pub const fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
    // Helper trait. `VALUE` is false, except for the specialization of the
    // case where `T == U`.
    trait TypeEq<U: ?Sized> {
        const VALUE: bool;
    }

    // Default implementation.
    impl<T: ?Sized, U: ?Sized> TypeEq<U> for T {
        default const VALUE: bool = false;
    }

    // Specialization for `T == U`.
    impl<T: ?Sized> TypeEq<T> for T {
        const VALUE: bool = true;
    }

    <T as TypeEq<U>>::VALUE
}

Example in playground

Upvotes: 13

Related Questions