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        Ok(mem::transmute_copy::<Src, Target>(&x))
13    } else {
14        Err(x)
15    }
16}
17
18// https://github.com/dtolnay/typeid/blob/b06a3c08a0eaccc7df6091ade1ae4e3fb53609d5/src/lib.rs#L197-L222
19#[inline(always)]
20fn nonstatic_typeid<T>() -> TypeId
21where
22    T: ?Sized,
23{
24    trait NonStaticAny {
25        fn get_type_id(&self) -> TypeId
26        where
27            Self: 'static;
28    }
29
30    impl<T: ?Sized> NonStaticAny for PhantomData<T> {
31        #[inline(always)]
32        fn get_type_id(&self) -> TypeId
33        where
34            Self: 'static,
35        {
36            TypeId::of::<T>()
37        }
38    }
39
40    let phantom_data = PhantomData::<T>;
41    NonStaticAny::get_type_id(unsafe {
42        mem::transmute::<&dyn NonStaticAny, &(dyn NonStaticAny + 'static)>(&phantom_data)
43    })
44}