How can I get same result of `std::any::TypeId::of` over `T`, `&T` and `&mut` T in Rust?

Viewed 221

I want to get some instances of TypeId for the given type T which implements Sized + 'static.

use std::any::TypeId;

trait Comp: Sized + 'static { }

impl<T: 'static> Comp for T { }

struct Foo;

fn main() {
    println!("{}", TypeId::of::<Foo>());
    println!("{}", TypeId::of::<&Foo>());
    println!("{}", TypeId::of::<&mut Foo>());
}

But the results are different. Yes, I know it's perfectly normal behavior. To handle this issue, I modified this code as below.

use std::ops::Deref;

// Same codes are omitted...

fn main() {
    println!("{}", TypeId::of::<Foo>());
    println!("{}", TypeId::of::<<&Foo as Deref>::Target>());
    println!("{}", TypeId::of::<<&mut Foo as Deref>::Target>());
}

Now it prints same values. To implement this behavior for all Comp, I wrote below.

use std::any::TypeId;
use std::ops::Deref;

trait Comp: Sized + 'static {
   type Pure: Comp;
}

impl<T: 'static> Comp for T {
   type Pure = T;
}

impl<T: Deref + 'static> Comp for T {
    type Pure = <T as Deref>::Target;
}

struct Foo;

fn main() {
    println!("{}", TypeId::of::<<Foo as Comp>::Pure>());
    println!("{}", TypeId::of::<<&Foo as Comp>::Pure>());
    println!("{}", TypeId::of::<<&mut Foo as Comp>::Pure>());
}

It won't compile because I provided conflicting implementations. How can I solve this problem?

1 Answers

I finally found a solution on the official community of the Rust. It can be implemented with the specialization unstable feature.

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=4c5f206ef3a7843ed57c256ee73ac58c

#![feature(specialization)]
use std::any::TypeId;
use std::ops::Deref;

trait Comp: Sized {
   type Pure: Comp;
}

impl<T> Comp for T {
   default type Pure = T;
}

impl<T: Deref> Comp for T where <T as Deref>::Target: Comp {
    type Pure = <T as Deref>::Target;
}

struct Foo;

fn main() {
    println!("{:?}", TypeId::of::<<Foo as Comp>::Pure>());
    println!("{:?}", TypeId::of::<<&Foo as Comp>::Pure>());
    println!("{:?}", TypeId::of::<<&mut Foo as Comp>::Pure>());
}
Related