multi_any/
typed_metadata.rs

1use crate::Meta;
2use crate::ptr_metadata::*;
3use std::any::TypeId;
4use std::mem::transmute;
5
6/// Trait for converting between fat pointer metadata and type-erased `Meta`.
7///
8/// Implemented for `()` (for concrete types) and `DynMetadata<T>` (for trait objects).
9pub trait TypedMetadata {
10    /// Converts `Meta` into the corresponding metadata type.
11    fn from_meta(meta: Meta) -> Self;
12
13    /// Converts metadata type into a type-erased `Meta`.
14    fn into_meta<Data: 'static>(self) -> Meta;
15}
16
17impl TypedMetadata for () {
18    fn from_meta(meta: Meta) -> Self {
19        assert_eq!(meta.meta_id, TypeId::of::<()>(), "Wrong Metadata type");
20    }
21
22    fn into_meta<Data: 'static>(self) -> Meta {
23        Meta {
24            meta_raw: 0,
25            data_id: TypeId::of::<Data>(),
26            meta_id: TypeId::of::<Self>(),
27        }
28    }
29}
30
31impl<T> TypedMetadata for DynMetadata<T>
32where
33    T: Pointee<Metadata = Self> + ?Sized + 'static,
34{
35    fn from_meta(meta: Meta) -> Self {
36        assert_eq!(meta.meta_id, TypeId::of::<Self>(), "Wrong Metadata type");
37
38        // SAFETY: We transmute usize to DynMetadata<T>.
39        // This is safe because we are sure that usize was acquired by transmuting the exact same type.
40        // Note: transmute guarantees that types has the same size.
41        let typed_meta: Self = unsafe { transmute(meta.meta_raw) };
42
43        typed_meta
44    }
45
46    fn into_meta<Data: 'static>(self) -> Meta {
47        // SAFETY: We transmute DynMetadata<T> to usize.
48        // This is safe because we will only use the resulting usize to transmute back to the exact same type.
49        // Note: transmute guarantees that types has the same size.
50        let meta_raw: usize = unsafe { transmute(self) };
51
52        Meta {
53            meta_raw,
54            data_id: TypeId::of::<Data>(),
55            meta_id: TypeId::of::<Self>(),
56        }
57    }
58}