dyn_dyn/
fat.rs

1use crate::{DowncastUnchecked, DynDynBase, DynDynTable, GetDynDynTable};
2use core::cmp::Ordering;
3use core::fmt::{self, Display, Pointer};
4use core::hash::{Hash, Hasher};
5use core::marker::{PhantomData, Unsize};
6use core::ops::CoerceUnsized;
7use core::ops::{Deref, DerefMut};
8use core::ptr::{self, Pointee};
9use stable_deref_trait::{CloneStableDeref, StableDeref};
10
11/// A fat pointer to an object that can be downcast via the base trait object `B`.
12///
13/// Such a pointer will only perform a call to retrieve the [`DynDynTable`] of the referenced object once when created. Thereafter, the
14/// cached table will be used for trait object metadata lookups. This effectively avoids the overhead of the repeated indirect calls to
15/// retrieve the table at the cost of increasing the size of the pointer to the object.
16#[derive(Debug)]
17pub struct DynDynFat<B: ?Sized + DynDynBase, P> {
18    ptr: P,
19    table: DynDynTable,
20    _base: PhantomData<fn(B) -> B>,
21}
22
23impl<B: ?Sized + DynDynBase, P: GetDynDynTable<B>> DynDynFat<B, P> {
24    /// Creates a new fat pointer with the provided pointer and [`DynDynTable`].
25    ///
26    /// # Safety
27    ///
28    /// `table` must refer to the same table as a table that would be returned by calling [`GetDynDynTable::get_dyn_dyn_table`] on `ptr` at
29    /// the time that this function is called.
30    pub unsafe fn new_unchecked(ptr: P, table: DynDynTable) -> Self {
31        DynDynFat {
32            ptr,
33            table,
34            _base: PhantomData,
35        }
36    }
37
38    /// Creates a new fat pointer wrapping the provided pointer. This will immediately get the pointer's [`DynDynTable`] by calling
39    /// [`GetDynDynTable<B>::get_dyn_dyn_table`] and cache it for future use.
40    pub fn new(ptr: P) -> Self {
41        let table = ptr.get_dyn_dyn_table();
42
43        // SAFETY: This table was just retrieved by calling get_dyn_dyn_table, so it's valid
44        unsafe { Self::new_unchecked(ptr, table) }
45    }
46
47    /// Gets the [`DynDynTable`] of the object referenced by a fat pointer without dereferencing it.
48    pub fn get_dyn_dyn_table(ptr: &Self) -> DynDynTable {
49        ptr.table
50    }
51
52    /// Unwraps a fat pointer, returning the pointer originally used to construct it.
53    pub fn unwrap(ptr: Self) -> P {
54        ptr.ptr
55    }
56}
57
58impl<B: ?Sized + DynDynBase, P: Deref> DynDynFat<B, P>
59where
60    P::Target: Unsize<B>,
61{
62    /// Dereferences a fat pointer to produce a fat pointer with a reference.
63    pub fn deref_fat(ptr: &Self) -> DynDynFat<B, &P::Target> {
64        DynDynFat {
65            ptr: ptr.ptr.deref(),
66            table: ptr.table,
67            _base: PhantomData,
68        }
69    }
70}
71
72impl<B: ?Sized + DynDynBase, P: DerefMut> DynDynFat<B, P>
73where
74    P::Target: Unsize<B>,
75{
76    /// Dereferences a fat pointer to produce a fat pointer with a mutable reference.
77    pub fn deref_mut_fat(ptr: &mut Self) -> DynDynFat<B, &mut P::Target> {
78        DynDynFat {
79            ptr: ptr.ptr.deref_mut(),
80            table: ptr.table,
81            _base: PhantomData,
82        }
83    }
84}
85
86impl<B: ?Sized + DynDynBase, P: Clone> DynDynFat<B, P> {
87    /// Clones a fat pointer without verifying that the [`DynDynTable`] held by the new fat pointer is applicable to the cloned pointer.
88    ///
89    /// # Safety
90    ///
91    /// The caller must guarantee that the result of calling `ptr.clone()` will dereference to an object having the same concrete type as
92    /// that pointed to by `ptr`.
93    pub unsafe fn clone_unchecked(ptr: &Self) -> Self {
94        DynDynFat {
95            ptr: ptr.ptr.clone(),
96            table: ptr.table,
97            _base: PhantomData,
98        }
99    }
100}
101
102// SAFETY: The table returned by this implementation was retrieved from the pointer at the time the DynDynFat was created and DynDynFat does
103//         not expose any way to mutate the pointer itself. Additionally, DynTarget is simply passed through from the pointer, so it must be
104//         valid for that pointer.
105unsafe impl<B: ?Sized + DynDynBase, P: GetDynDynTable<B>> GetDynDynTable<B> for DynDynFat<B, P> {
106    type DynTarget = P::DynTarget;
107
108    fn get_dyn_dyn_table(&self) -> DynDynTable {
109        self.table
110    }
111}
112
113impl<'a, B: ?Sized + DynDynBase, P: DowncastUnchecked<'a> + 'a> DowncastUnchecked<'a>
114    for DynDynFat<B, P>
115{
116    type DowncastResult<D: ?Sized + 'a> = <P as DowncastUnchecked<'a>>::DowncastResult<D>;
117
118    unsafe fn downcast_unchecked<D: ?Sized + Pointee>(
119        self,
120        metadata: <D as Pointee>::Metadata,
121    ) -> Self::DowncastResult<D> {
122        // SAFETY: Just passing through to the pointer's implementation.
123        unsafe { self.ptr.downcast_unchecked(metadata) }
124    }
125}
126
127impl<B: ?Sized + DynDynBase, P: Deref> Deref for DynDynFat<B, P> {
128    type Target = P::Target;
129
130    fn deref(&self) -> &Self::Target {
131        self.ptr.deref()
132    }
133}
134
135// SAFETY: DynDynFat implements deref() by dereferencing the wrapped pointer, so if that pointer is StableDeref then so is the DynDynFat
136unsafe impl<B: ?Sized + DynDynBase, P: StableDeref> StableDeref for DynDynFat<B, P> {}
137
138// SAFETY: DynDynFat implements clone() by cloning the wrapped pointer and implements deref() by dereferencing the wrapped pointer, so if
139//         that pointer is CloneStableDeref then so is the DynDynFat
140unsafe impl<B: ?Sized + DynDynBase, P: CloneStableDeref + GetDynDynTable<B>> CloneStableDeref
141    for DynDynFat<B, P>
142{
143}
144
145impl<B: ?Sized + DynDynBase, P: DerefMut> DerefMut for DynDynFat<B, P> {
146    fn deref_mut(&mut self) -> &mut Self::Target {
147        self.ptr.deref_mut()
148    }
149}
150
151impl<B: ?Sized + DynDynBase, P: Deref + Clone + GetDynDynTable<B>> Clone for DynDynFat<B, P> {
152    fn clone(&self) -> Self {
153        let ptr = self.ptr.clone();
154        let table = if ptr::eq(ptr.deref(), self.ptr.deref()) {
155            self.table
156        } else {
157            <P as GetDynDynTable<B>>::get_dyn_dyn_table(&ptr)
158        };
159
160        DynDynFat {
161            ptr,
162            table,
163            _base: PhantomData,
164        }
165    }
166}
167
168impl<B: ?Sized + DynDynBase, P: Deref + Copy + GetDynDynTable<B>> Copy for DynDynFat<B, P> where
169    P::Target: Unsize<B>
170{
171}
172
173impl<B: ?Sized + DynDynBase, P: GetDynDynTable<B> + Default> Default for DynDynFat<B, P> {
174    fn default() -> Self {
175        DynDynFat::new(Default::default())
176    }
177}
178
179impl<B: ?Sized + DynDynBase, P: GetDynDynTable<B>> From<P> for DynDynFat<B, P> {
180    fn from(ptr: P) -> Self {
181        DynDynFat::new(ptr)
182    }
183}
184
185impl<B: ?Sized + DynDynBase, P: Deref> AsRef<P> for DynDynFat<B, P> {
186    fn as_ref(&self) -> &P {
187        &self.ptr
188    }
189}
190
191impl<B1: ?Sized + DynDynBase, B2: ?Sized + DynDynBase, P1: Deref, P2: Deref>
192    PartialEq<DynDynFat<B2, P2>> for DynDynFat<B1, P1>
193where
194    P1::Target: Unsize<B1> + PartialEq<P2::Target>,
195    P2::Target: Unsize<B2>,
196{
197    fn eq(&self, other: &DynDynFat<B2, P2>) -> bool {
198        PartialEq::eq(&*self.ptr, &*other.ptr)
199    }
200}
201
202impl<B: ?Sized + DynDynBase, P: Deref> Eq for DynDynFat<B, P> where P::Target: Unsize<B> + Eq {}
203
204impl<B: ?Sized + DynDynBase, P: Deref> Hash for DynDynFat<B, P>
205where
206    P::Target: Unsize<B> + Hash,
207{
208    fn hash<H: Hasher>(&self, state: &mut H) {
209        Hash::hash(&*self.ptr, state)
210    }
211}
212
213impl<B1: ?Sized + DynDynBase, B2: ?Sized + DynDynBase, P1: Deref, P2: Deref>
214    PartialOrd<DynDynFat<B2, P2>> for DynDynFat<B1, P1>
215where
216    P1::Target: Unsize<B1> + PartialOrd<P2::Target>,
217    P2::Target: Unsize<B2>,
218{
219    fn partial_cmp(&self, other: &DynDynFat<B2, P2>) -> Option<Ordering> {
220        PartialOrd::partial_cmp(&*self.ptr, &*other.ptr)
221    }
222}
223
224impl<B: ?Sized + DynDynBase, P: Deref> Ord for DynDynFat<B, P>
225where
226    P::Target: Unsize<B> + Ord,
227{
228    fn cmp(&self, other: &Self) -> Ordering {
229        Ord::cmp(&*self.ptr, &*other.ptr)
230    }
231}
232
233impl<B: ?Sized + DynDynBase, P1: Deref + CoerceUnsized<P2>, P2: Deref>
234    CoerceUnsized<DynDynFat<B, P2>> for DynDynFat<B, P1>
235where
236    P1::Target: Unsize<B>,
237    P2::Target: Unsize<B>,
238{
239}
240
241impl<B: ?Sized + DynDynBase, P: Display> Display for DynDynFat<B, P> {
242    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
243        write!(f, "{}", self.ptr)
244    }
245}
246
247impl<B: ?Sized + DynDynBase, P: Pointer> Pointer for DynDynFat<B, P> {
248    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
249        write!(f, "{:p}", self.ptr)
250    }
251}