dyn_dyn/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(feature = "std"), no_std)]
3#![warn(missing_docs)]
4#![warn(clippy::undocumented_unsafe_blocks)]
5#![allow(clippy::needless_borrowed_reference)]
6#![forbid(unsafe_op_in_unsafe_fn)]
7#![feature(coerce_unsized)]
8#![feature(const_nonnull_new)]
9#![feature(const_option)]
10#![feature(const_trait_impl)]
11#![feature(const_type_id)]
12#![cfg_attr(feature = "dynamic-names", feature(const_type_name))]
13#![feature(doc_auto_cfg)]
14#![feature(ptr_metadata)]
15#![feature(unsize)]
16
17#[cfg(feature = "alloc")]
18extern crate alloc;
19
20mod cast_target;
21mod fat;
22mod table;
23
24#[doc(hidden)]
25pub mod internal;
26
27/// Declares a trait as being a base trait for downcasting.
28///
29/// This macro marks a trait as being a base for dynamic trait object downcasting. All `impl` blocks for this trait will need to use the
30/// [`#[dyn_dyn_impl]`](dyn_dyn_impl) attribute to declare what traits they wish to expose.
31pub use dyn_dyn_macros::dyn_dyn_base;
32
33/// Performs a dynamic downcast of a reference to a trait object where the trait was declared with [`#[dyn_dyn_base]`](dyn_dyn_base).
34///
35/// This macro allows for trying to cast such a reference to a reference to another trait object, returning an [`Option`] containing the
36/// reference to the downcast trait object if the object in question implements that trait.
37///
38/// This macro accepts the following types for a given base trait `B`, with the first matching set of conditions determining how the
39/// dereference will occur:
40///
41/// - A (mutable) reference to a type that implements `B`, returning a (mutable) reference referring to the same object as the original
42///   reference
43/// - A (mutable) reference to a pointer type that implements [`DynDyn<B>`], returning a (mutable) reference referring to the pointee of
44///   that pointer
45/// - A (mutable) reference to a pointer type that implements Deref with a target that implements `B`, returning a (mutable) reference
46///   referring to the pointee of that pointer
47///
48/// # Examples
49///
50/// ```rust
51/// # use dyn_dyn::{dyn_dyn_base, dyn_dyn_cast, dyn_dyn_impl};
52/// #[dyn_dyn_base]
53/// trait Base {}
54/// trait Trait {}
55///
56/// struct Struct;
57///
58/// #[dyn_dyn_impl(Trait)]
59/// impl Base for Struct {}
60/// impl Trait for Struct {}
61///
62/// fn downcast(r: &dyn Base) -> Result<&dyn Trait, &dyn Base> {
63///     dyn_dyn_cast!(Base => Trait, r)
64/// }
65///
66/// fn downcast_mut(r: &mut dyn Base) -> Result<&mut dyn Trait, &mut dyn Base> {
67///     dyn_dyn_cast!(mut Base => Trait, r)
68/// }
69///
70/// # #[cfg(feature = "alloc")]
71/// fn downcast_box(r: Box<dyn Base>) -> Result<Box<dyn Trait>, Box<dyn Base>> {
72///     dyn_dyn_cast!(move Base => Trait, r)
73/// }
74///
75/// fn main() {
76///     let mut s = Struct;
77///
78///     assert!(downcast(&s).is_ok());
79///     assert!(downcast_mut(&mut s).is_ok());
80///     # #[cfg(feature = "alloc")]
81///     assert!(downcast_box(Box::new(s)).is_ok());
82/// }
83/// ```
84pub use dyn_dyn_macros::dyn_dyn_cast;
85
86/// Marks an `impl` block as targeting a trait that was declared with the [`#[dyn_dyn_base]`](dyn_dyn_base) attribute.
87///
88/// This attribute allows the `impl` block to specify what other traits should be exposed for downcasting via the base trait that's being
89/// implemented in this block.
90///
91/// # Examples
92///
93/// ```rust
94/// # use core::fmt::Debug;
95/// # use dyn_dyn::{dyn_dyn_base, dyn_dyn_impl};
96/// #[dyn_dyn_base]
97/// trait Base {}
98///
99/// #[derive(Debug)]
100/// struct Struct;
101///
102/// #[dyn_dyn_impl(Debug)]
103/// impl Base for Struct {}
104/// ```
105///
106/// ```rust
107/// # use dyn_dyn::{dyn_dyn_base, dyn_dyn_impl};
108/// #[dyn_dyn_base]
109/// trait Base {}
110/// trait Trait<T> {}
111///
112/// struct Struct<T>(T);
113///
114/// impl<T> Trait<T> for Struct<T> {}
115///
116/// #[dyn_dyn_impl(Trait<T>)]
117/// impl<T: 'static> Base for Struct<T> {}
118/// ```
119pub use dyn_dyn_macros::dyn_dyn_impl;
120
121pub use cast_target::DynDynCastTarget;
122pub use fat::DynDynFat;
123pub use table::{AnyDynMetadata, DynDynTable, DynDynTableEntry, DynDynTableIterator};
124
125#[cfg(doc)]
126use core::ops::Deref;
127
128use cfg_if::cfg_if;
129use core::marker::{PhantomData, Unsize};
130use core::ops::DerefMut;
131use core::ptr::{self, Pointee};
132use stable_deref_trait::StableDeref;
133
134/// A type that can be dynamically downcast to other traits using the [`dyn_dyn_cast!`] macro.
135///
136/// This trait should not be manually implemented by user code. Instead, this trait should be implemented by using the
137/// [`#[dyn_dyn_base]`](dyn_dyn_base) attribute on the trait in question. The exact shape of this trait is subject to change at any time, so
138/// it generally shouldn't be relied upon in external code except as a trait bound.
139///
140/// # Safety
141///
142/// The result of calling [`DynDynBase::get_dyn_dyn_table`] on an object through a given base must never change for the lifetime of that
143/// object, even if the object itself is mutated.
144pub unsafe trait DynDynBase {
145    /// Gets the [`DynDynTable`] for this object, for traits exposed via this base trait.
146    ///
147    /// In user code, it is generally preferred to use the implementation of [`GetDynDynTable`] for references rather than calling this
148    /// method directly to avoid potential future breakage.
149    fn get_dyn_dyn_table(&self) -> DynDynTable;
150}
151
152/// Wraps a reference to a pointer implementing [`GetDynDynTable<B>`] and which can be dereferenced to perform the downcast.
153///
154/// Using [`dyn_dyn_cast!`] on this struct will call [`GetDynDynTable::get_dyn_dyn_table`] on the pointer itself, then dereference this
155/// pointer to perform the downcast. This allows a pointer implementing [`DynDyn<B>`] to be downcast into a reference without moving the
156/// pointer itself.
157pub struct DynDynRef<'a, B: ?Sized + DynDynBase, T: GetDynDynTable<B> + StableDeref>(
158    &'a T,
159    PhantomData<fn(B) -> B>,
160);
161
162impl<'a, B: ?Sized + DynDynBase, T: GetDynDynTable<B> + StableDeref> DynDynRef<'a, B, T>
163where
164    T::Target: Unsize<B>,
165{
166    /// Creates a new [`DynDynRef`] for the provided reference to a pointer.
167    pub fn new(r: &'a T) -> Self {
168        DynDynRef(r, PhantomData)
169    }
170}
171
172/// Wraps a mutable reference to a pointer implementing [`GetDynDynTable<B>`] and which can be dereferenced to perform the downcast.
173///
174/// Using [`dyn_dyn_cast!`] on this struct will call [`GetDynDynTable::get_dyn_dyn_table`] on the pointer itself, then dereference this
175/// pointer to perform the downcast. This allows a pointer implementing [`DynDyn<B>`] to be downcast into a mutable reference without moving
176/// the pointer itself.
177pub struct DynDynRefMut<'a, B: ?Sized + DynDynBase, T: GetDynDynTable<B> + StableDeref + DerefMut>(
178    &'a mut T,
179    PhantomData<fn(B) -> B>,
180);
181
182impl<'a, B: ?Sized + DynDynBase, T: GetDynDynTable<B> + StableDeref + DerefMut>
183    DynDynRefMut<'a, B, T>
184{
185    /// Creates a new [`DynDynRefMut`] for the provided mutable reference to a pointer.
186    pub fn new(r: &'a mut T) -> Self {
187        DynDynRefMut(r, PhantomData)
188    }
189}
190
191/// A pointer to an object which has a [`DynDynTable`] associated with it.
192///
193/// # Safety
194///
195/// - If this type implements [`Deref`], then the reference returned by calling [`Deref::deref`] must not change for the lifetime of this
196///   pointer unless the pointer itself is mutated.
197/// - If this type implements [`DerefMut`], then the reference returned by calling [`DerefMut::deref_mut`] must not change for the lifetime
198///   of this pointer unless the pointer itself is mutated and must point to the same object as a reference returned by calling
199///   [`Deref::deref`], including having identical metadata. Additionally, calling [`DerefMut::deref_mut`] must not mutate the pointer.
200/// - If this type implements [`Deref`], then the reference returned by calling [`Deref::deref`] must be unsize-coercible to a reference to
201///   [`GetDynDynTable::get_dyn_dyn_table`].
202/// - If this type implements [`Deref`], then the returned table must be equivalent to calling [`GetDynDynTable::get_dyn_dyn_table`] on a
203///   reference returned by calling [`Deref::deref`].
204/// - If this type implements [`DowncastUnchecked`], then the result of calling [`DowncastUnchecked::downcast_unchecked`] with
205///   metadata retrieved from the table returned by calling [`GetDynDynTable::get_dyn_dyn_table`] on this pointer shall be valid and safe to
206///   use.
207pub unsafe trait GetDynDynTable<B: ?Sized + DynDynBase> {
208    /// The actual type that this pointer currently points to. This type is used to allow propagation of auto trait bounds such as `Send`
209    /// and `Sync` in the `dyn_dyn_cast!` macro.
210    type DynTarget: ?Sized + Unsize<B>;
211
212    /// Gets the [`DynDynTable`] for the object that this pointer points to.
213    fn get_dyn_dyn_table(&self) -> DynDynTable;
214}
215
216/// A pointer to an object that can be unsafely downcast to point to another type.
217pub trait DowncastUnchecked<'a> {
218    /// The result of downcasting this pointer to point to the type `D`. Note that this type need not have the same outer wrapper as the
219    /// type implementing `DowncastUnchecked`, since the result of the downcast may involve coercions and dereferences.
220    type DowncastResult<D: ?Sized + 'a>;
221
222    /// Downcasts this pointer into a new pointer pointing to the same object, but having type `D`.
223    ///
224    /// Generally, the result of calling this function should be equivalent to turning this pointer type into a raw pointer, removing its
225    /// metadata, unsafely casting that pointer into a pointer to `D` using the provided metadata, and then turning that raw pointer into
226    /// another pointer type.
227    ///
228    /// As long as the concrete type of the pointee matches the concrete type of the metadata provided, then this is guaranteed to result
229    /// in a pointer which is valid and safe to use.
230    ///
231    /// # Safety
232    ///
233    /// Attaching the provided metadata to a pointer to the same data address as that held by this pointer must be guaranteed to be valid
234    /// and safe to use before this function can be called.
235    unsafe fn downcast_unchecked<D: ?Sized + Pointee>(
236        self,
237        metadata: <D as Pointee>::Metadata,
238    ) -> Self::DowncastResult<D>;
239}
240
241/// A pointer object that can be safely downcast to refer to other trait types by using the `dyn_dyn_cast!` macro.
242pub trait DynDyn<'a, B: ?Sized + DynDynBase>: GetDynDynTable<B> + DowncastUnchecked<'a> {}
243
244impl<'a, B: ?Sized + DynDynBase, T: GetDynDynTable<B> + DowncastUnchecked<'a>> DynDyn<'a, B> for T {}
245
246// SAFETY: The referent of a shared reference will never change unexpectedly and the table returned matches that returned by dereferencing
247//         it by definition. The DowncastUnchecked implementation is also a simple cast via converting to/from a pointer and so should be
248//         correct.
249unsafe impl<'a, B: ?Sized + DynDynBase, T: ?Sized + Unsize<B>> GetDynDynTable<B> for &'a T {
250    type DynTarget = T;
251
252    fn get_dyn_dyn_table(&self) -> DynDynTable {
253        B::get_dyn_dyn_table(*self)
254    }
255}
256
257impl<'a, T: ?Sized> DowncastUnchecked<'a> for &'a T {
258    type DowncastResult<D: ?Sized + 'a> = &'a D;
259
260    unsafe fn downcast_unchecked<D: ?Sized + Pointee>(
261        self,
262        metadata: <D as Pointee>::Metadata,
263    ) -> &'a D {
264        // SAFETY: Safety invariants for this fn require that the provided metadata is valid for self. Since the input reference has the
265        //         lifetime 'a and the returned reference also has lifetime 'a, this dereference does not extend the reference's lifetime
266        //         and only serves to re-attach the metadata.
267        unsafe { &*ptr::from_raw_parts(self as *const T as *const (), metadata) }
268    }
269}
270
271// SAFETY: Since T is StableDeref, the results of its Deref implementation should meet the stability requirements and the table returned is
272//         simply passed through from T's GetDynDynTable<B> implementation, which is unsafe itself and can be assumed to be correct. The
273//         DowncastUnchecked implementation defers to the impl for &T::Target, so it should be correct.
274unsafe impl<'a, B: ?Sized + DynDynBase, T: GetDynDynTable<B> + StableDeref + 'a> GetDynDynTable<B>
275    for DynDynRef<'a, B, T>
276where
277    T::Target: Unsize<B>,
278{
279    type DynTarget = T::DynTarget;
280
281    fn get_dyn_dyn_table(&self) -> DynDynTable {
282        <T as GetDynDynTable<B>>::get_dyn_dyn_table(self.0)
283    }
284}
285
286impl<'a, B: ?Sized + DynDynBase, T: DynDyn<'a, B> + StableDeref + 'a> DowncastUnchecked<'a>
287    for DynDynRef<'a, B, T>
288where
289    T::Target: Unsize<B>,
290{
291    type DowncastResult<D: ?Sized + 'a> = &'a D;
292
293    unsafe fn downcast_unchecked<D: ?Sized + Pointee>(
294        self,
295        metadata: <D as Pointee>::Metadata,
296    ) -> Self::DowncastResult<D> {
297        // SAFETY: Just passing through to the implementation for &'a T.
298        unsafe { <&T::Target as DowncastUnchecked>::downcast_unchecked(&**self.0, metadata) }
299    }
300}
301
302// SAFETY: The referent of a mutable reference will never change unexpectedly and the table is returned by deferring to &T's implementation
303//         and so should be correct. The DowncastUnchecked implementation is also a simple cast via converting to/from a pointer and so
304//         should also be correct.
305unsafe impl<'a, B: ?Sized + DynDynBase, T: ?Sized + Unsize<B>> GetDynDynTable<B> for &'a mut T {
306    type DynTarget = T;
307
308    fn get_dyn_dyn_table(&self) -> DynDynTable {
309        B::get_dyn_dyn_table(*self)
310    }
311}
312
313impl<'a, T: ?Sized> DowncastUnchecked<'a> for &'a mut T {
314    type DowncastResult<D: ?Sized + 'a> = &'a mut D;
315
316    unsafe fn downcast_unchecked<D: ?Sized + Pointee>(
317        self,
318        metadata: <D as Pointee>::Metadata,
319    ) -> &'a mut D {
320        // SAFETY: Safety invariants for this fn require that the provided metadata is valid for self. Since the input reference has the
321        //         lifetime 'a and the returned reference also has lifetime 'a, this dereference does not extend the reference's lifetime
322        //         and only serves to re-attach the metadata.
323        unsafe { &mut *ptr::from_raw_parts_mut(self as *mut T as *mut (), metadata) }
324    }
325}
326
327// SAFETY: Since T is StableDeref, the results of its Deref and DerefMut implementations should meet the stability requirements and the
328//         table returned is simply passed through from T's GetDynDynTable<B> implementation, which is unsafe itself and can be assumed to
329//         be correct. The DowncastUnchecked implementation defers to the impl for &mut T::Target, so it should be correct.
330unsafe impl<'a, B: ?Sized + DynDynBase, T: DynDyn<'a, B> + StableDeref + DerefMut + 'a>
331    GetDynDynTable<B> for DynDynRefMut<'a, B, T>
332where
333    T::Target: Unsize<B>,
334{
335    type DynTarget = T::Target;
336
337    fn get_dyn_dyn_table(&self) -> DynDynTable {
338        <T as GetDynDynTable<B>>::get_dyn_dyn_table(self.0)
339    }
340}
341
342impl<'a, B: ?Sized + DynDynBase, T: DynDyn<'a, B> + StableDeref + DerefMut + 'a>
343    DowncastUnchecked<'a> for DynDynRefMut<'a, B, T>
344where
345    T::Target: Unsize<B>,
346{
347    type DowncastResult<D: ?Sized + 'a> = &'a mut D;
348
349    unsafe fn downcast_unchecked<D: ?Sized + Pointee>(
350        self,
351        metadata: <D as Pointee>::Metadata,
352    ) -> Self::DowncastResult<D> {
353        // SAFETY: Just passing through to the implementation for &'a mut T.
354        unsafe {
355            <&mut T::Target as DowncastUnchecked>::downcast_unchecked(&mut **self.0, metadata)
356        }
357    }
358}
359
360cfg_if! {
361    if #[cfg(feature = "alloc")] {
362        use alloc::boxed::Box;
363        use alloc::sync::Arc;
364        use alloc::rc::Rc;
365
366        // SAFETY: Box<T> meets all Deref/DerefMut stability requirements and the table is retrieved by dereferencing it, which is correct
367        //         by definition. The DowncastUnchecked implementation is also a simple cast via converting to/from a pointer and so should
368        //         be correct.
369        unsafe impl<B: ?Sized + DynDynBase, T: ?Sized + Unsize<B>> GetDynDynTable<B> for Box<T> {
370            type DynTarget = T;
371
372            fn get_dyn_dyn_table(&self) -> DynDynTable {
373                B::get_dyn_dyn_table(&**self)
374            }
375        }
376
377        impl<'a, T: ?Sized + 'a> DowncastUnchecked<'a>
378            for Box<T>
379        {
380            type DowncastResult<D: ?Sized + 'a> = Box<D>;
381
382            unsafe fn downcast_unchecked<D: ?Sized + Pointee>(self, metadata: <D as Pointee>::Metadata) -> Box<D> {
383                // SAFETY: 1) NonNull::new_unchecked is fine since the raw pointer of a Box can never be null.
384                //         2) Box::from_raw is fine since the fat pointer passed in has the same data pointer as what we got from
385                //            Box::into_raw and the metadata pointer is guaranteed to be valid by this fn's safety invariants.
386                unsafe {
387                    Box::from_raw(
388                        ptr::from_raw_parts_mut(Box::into_raw(self) as *mut (), metadata)
389                    )
390                }
391            }
392        }
393
394        // SAFETY: Rc<T> meets all Deref/DerefMut stability requirements and the table is retrieved by dereferencing it, which is correct by
395        //         definition. The DowncastUnchecked implementation is also a simple cast via converting to/from a pointer and so should be
396        //         correct.
397        unsafe impl<B: ?Sized + DynDynBase, T: ?Sized + Unsize<B>> GetDynDynTable<B> for Rc<T> {
398            type DynTarget = T;
399
400            fn get_dyn_dyn_table(&self) -> DynDynTable {
401                B::get_dyn_dyn_table(&**self)
402            }
403        }
404
405        impl<'a, T: ?Sized + 'a> DowncastUnchecked<'a>
406            for Rc<T>
407        {
408            type DowncastResult<D: ?Sized + 'a> = Rc<D>;
409
410            unsafe fn downcast_unchecked<D: ?Sized + Pointee>(self, metadata: <D as Pointee>::Metadata) -> Rc<D> {
411                // SAFETY: 1) NonNull::new_unchecked is fine since the raw pointer of a Box can never be null.
412                //         2) Rc::from_raw is fine since the fat pointer passed in has the same data pointer as what we got from
413                //            Rc::into_raw and the metadata pointer is guaranteed to be valid by this fn's safety invariants.
414                unsafe {
415                    Rc::from_raw(
416                        ptr::from_raw_parts(
417                            Rc::into_raw(self) as *const (),
418                            metadata,
419                        ),
420                    )
421                }
422            }
423        }
424
425        // SAFETY: Arc<T> meets all Deref/DerefMut stability requirements and the table is retrieved by dereferencing it, which is correct
426        //         by definition. The DowncastUnchecked implementation is also a simple cast via converting to/from a pointer and so should
427        //         be correct.
428        unsafe impl<B: ?Sized + DynDynBase, T: ?Sized + Unsize<B>> GetDynDynTable<B> for Arc<T> {
429            type DynTarget = T;
430
431            fn get_dyn_dyn_table(&self) -> DynDynTable {
432                B::get_dyn_dyn_table(&**self)
433            }
434        }
435
436        impl<'a, T: ?Sized + 'a> DowncastUnchecked<'a>
437            for Arc<T>
438        {
439            type DowncastResult<D: ?Sized + 'a> = Arc<D>;
440
441            unsafe fn downcast_unchecked<D: ?Sized + Pointee>(self, metadata: <D as Pointee>::Metadata) -> Arc<D> {
442                // SAFETY: 1) NonNull::new_unchecked is fine since the raw pointer of a Box can never be null.
443                //         2) Arc::from_raw is fine since the fat pointer passed in has the same data pointer as what we got from
444                //            Arc::into_raw and the metadata pointer is guaranteed to be valid by this fn's safety invariants.
445                unsafe {
446                    Arc::from_raw(
447                        ptr::from_raw_parts(Arc::into_raw(self) as *const (), metadata),
448                    )
449                }
450            }
451        }
452    }
453}