Skip to main content

rkyv/
erased.rs

1//! Deserializers that can be used standalone and provide basic capabilities.
2
3use ::core::{fmt, mem::transmute};
4use ptr_meta::{from_raw_parts_mut, metadata, DynMetadata, Pointee};
5
6/// Type-erased pointer metadata.
7#[derive(Clone, Copy)]
8pub union Metadata {
9    unit: (),
10    usize: usize,
11    vtable: DynMetadata<()>,
12}
13
14impl fmt::Debug for Metadata {
15    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        write!(f, "<metadata>")
17    }
18}
19
20impl From<()> for Metadata {
21    fn from(value: ()) -> Self {
22        Self { unit: value }
23    }
24}
25
26impl From<usize> for Metadata {
27    fn from(value: usize) -> Self {
28        Self { usize: value }
29    }
30}
31
32impl<T: ?Sized> From<DynMetadata<T>> for Metadata {
33    fn from(value: DynMetadata<T>) -> Self {
34        Self {
35            vtable: unsafe {
36                transmute::<DynMetadata<T>, DynMetadata<()>>(value)
37            },
38        }
39    }
40}
41
42/// A type which can be extracted from `Metadata`.
43pub trait FromMetadata {
44    /// Extracts this type from [`Metadata`].
45    ///
46    /// # Safety
47    ///
48    /// The metadata must have been created by calling `Metadata::from` on a
49    /// value of this type.
50    unsafe fn from_metadata(metadata: Metadata) -> Self;
51}
52
53impl FromMetadata for () {
54    unsafe fn from_metadata(metadata: Metadata) -> Self {
55        unsafe { metadata.unit }
56    }
57}
58
59impl FromMetadata for usize {
60    unsafe fn from_metadata(metadata: Metadata) -> Self {
61        unsafe { metadata.usize }
62    }
63}
64
65impl<T: ?Sized> FromMetadata for DynMetadata<T> {
66    unsafe fn from_metadata(metadata: Metadata) -> Self {
67        unsafe { transmute::<DynMetadata<()>, DynMetadata<T>>(metadata.vtable) }
68    }
69}
70
71/// A type-erased pointer.
72#[derive(Clone, Copy, Debug)]
73pub struct ErasedPtr {
74    data_address: *mut (),
75    metadata: Metadata,
76}
77
78impl ErasedPtr {
79    /// Returns an erased pointer corresponding to the given pointer.
80    #[inline]
81    pub fn new<T>(ptr: *mut T) -> Self
82    where
83        T: Pointee + ?Sized,
84        T::Metadata: Into<Metadata>,
85    {
86        Self {
87            data_address: ptr.cast(),
88            metadata: metadata(ptr).into(),
89        }
90    }
91
92    /// Returns the data address corresponding to this erased pointer.
93    #[inline]
94    pub fn data_address(&self) -> *mut () {
95        self.data_address
96    }
97
98    /// Returns the metadata associated with this erased pointer.
99    #[inline]
100    pub fn metadata(&self) -> Metadata {
101        self.metadata
102    }
103
104    /// # Safety
105    ///
106    /// `self` must be created from a valid pointer to `T`.
107    #[inline]
108    pub unsafe fn downcast_unchecked<T>(&self) -> *mut T
109    where
110        T: Pointee + ?Sized,
111        T::Metadata: FromMetadata,
112    {
113        from_raw_parts_mut(self.data_address, unsafe {
114            T::Metadata::from_metadata(self.metadata)
115        })
116    }
117}