Reputation: 999
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
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
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
}
Upvotes: 13