tokio/util/
typeid.rs

1use std::{
2    any::TypeId,
3    marker::PhantomData,
4    mem::{self, ManuallyDrop},
5};
6
7// SAFETY: this function does not compare lifetimes. Values returned as `Ok`
8// may have their lifetimes extended.
9pub(super) unsafe fn try_transmute<Src, Target: 'static>(x: Src) -> Result<Target, Src> {
10    if nonstatic_typeid::<Src>() == TypeId::of::<Target>() {
11        let x = ManuallyDrop::new(x);
12        // SAFETY: we have checked that the types are the same.
13        Ok(unsafe { mem::transmute_copy::<Src, Target>(&x) })
14    } else {
15        Err(x)
16    }
17}
18
19// https://github.com/dtolnay/typeid/blob/b06a3c08a0eaccc7df6091ade1ae4e3fb53609d5/src/lib.rs#L197-L222
20#[inline(always)]
21fn nonstatic_typeid<T>() -> TypeId
22where
23    T: ?Sized,
24{
25    trait NonStaticAny {
26        fn get_type_id(&self) -> TypeId
27        where
28            Self: 'static;
29    }
30
31    impl<T: ?Sized> NonStaticAny for PhantomData<T> {
32        #[inline(always)]
33        fn get_type_id(&self) -> TypeId
34        where
35            Self: 'static,
36        {
37            TypeId::of::<T>()
38        }
39    }
40
41    let phantom_data = PhantomData::<T>;
42    NonStaticAny::get_type_id(unsafe {
43        mem::transmute::<&dyn NonStaticAny, &(dyn NonStaticAny + 'static)>(&phantom_data)
44    })
45}