abi_stable 0.11.1

For doing Rust-to-Rust ffi,writing libraries loaded at program startup.
Documentation
use super::*;

use std::fmt;

#[allow(unused_imports)]
use core_extensions::SelfOps;

use crate::{
    abi_stability::PrefixStableAbi,
    erased_types::{c_functions::adapt_std_fmt, InterfaceType, MakeRequiredTraits},
    pointer_trait::{
        AsMutPtr, AsPtr, CanTransmuteElement, GetPointerKind, PK_Reference, PK_SmartPointer,
        PointerKind, TransmuteElement,
    },
    sabi_trait::vtable::{BaseVtable_Prefix, BaseVtable_Ref},
    sabi_types::{MaybeCmp, RMut, RRef},
    std_types::UTypeId,
    type_level::{
        impl_enum::{Implemented, Unimplemented},
        trait_marker,
    },
    StableAbi,
};

/// `RObject` implements ffi-safe trait objects, for a minimal selection of traits.
///
/// The main use of `RObject<_>` is as the default backend for `#[sabi_trait]`
/// generated trait objects.
///
/// # Construction
///
/// `RObject<_>` is how `#[sabi_trait]`-based ffi-safe trait objects are implemented,
/// and there's no way to construct it separate from those.
///
/// # Trait object
///
/// `RObject<'borrow, Pointer<()>, Interface, VTable>`
/// can be used as a trait object for any combination of
/// the traits listed below:
///
/// - [`Send`]
///
/// - [`Sync`]
///
/// - [`Unpin`](std::marker::Unpin)
///
/// - [`Debug`]
///
/// - [`Display`]
///
/// - [`Error`](std::error::Error)
///
/// - [`Clone`]
///
/// # Deconstruction
///
/// `RObject<_>` can be unwrapped into a concrete type,
/// within the same dynamic library/executable that constructed it,
/// using these (fallible) conversion methods:
///
/// - [`downcast_into`](#method.downcast_into):
/// Unwraps into a pointer to `T`.Requires `T: 'static`.
///
/// - [`downcast_as`](#method.downcast_as):
/// Unwraps into a `&T`.Requires `T: 'static`.
///
/// - [`downcast_as_mut`](#method.downcast_as_mut):
/// Unwraps into a `&mut T`.Requires `T: 'static`.
///
/// `RObject` can only be converted back if the trait object was constructed to allow it.
///
///
///
///
///
#[repr(C)]
#[derive(StableAbi)]
#[sabi(
    not_stableabi(V),
    bound(V: PrefixStableAbi),
    bound(I: InterfaceType),
    extra_checks = <I as MakeRequiredTraits>::MAKE,
)]
pub struct RObject<'lt, P, I, V>
where
    P: GetPointerKind,
{
    vtable: PrefixRef<V>,
    ptr: ManuallyDrop<P>,
    _marker: PhantomData<(&'lt (), extern "C" fn() -> I)>,
}

mod clone_impl {
    pub trait CloneImpl<PtrKind> {
        fn clone_impl(&self) -> Self;
    }
}
use self::clone_impl::CloneImpl;

/// This impl is for smart pointers.
impl<'lt, P, I, V> CloneImpl<PK_SmartPointer> for RObject<'lt, P, I, V>
where
    P: AsPtr,
    I: InterfaceType<Clone = Implemented<trait_marker::Clone>>,
{
    fn clone_impl(&self) -> Self {
        let ptr =
            unsafe { self.sabi_robject_vtable()._sabi_clone().unwrap()(RRef::new(&self.ptr)) };
        Self {
            vtable: self.vtable,
            ptr: ManuallyDrop::new(ptr),
            _marker: PhantomData,
        }
    }
}

/// This impl is for references.
impl<'lt, P, I, V> CloneImpl<PK_Reference> for RObject<'lt, P, I, V>
where
    P: AsPtr + Copy,
    I: InterfaceType,
{
    fn clone_impl(&self) -> Self {
        Self {
            vtable: self.vtable,
            ptr: ManuallyDrop::new(*self.ptr),
            _marker: PhantomData,
        }
    }
}

/// Clone is implemented for references and smart pointers,
/// using `GetPointerKind` to decide whether `P` is a smart pointer or a reference.
///
/// RObject does not implement Clone if `P` == `&mut ()` :
///
///
/// ```compile_fail
/// use abi_stable::{
///     sabi_trait::{doc_examples::ConstExample_TO, TD_Opaque},
///     std_types::*,
/// };
///
/// let mut object = ConstExample_TO::from_value(10usize, TD_Opaque);
/// let borrow = object.sabi_reborrow_mut();
/// let _ = borrow.clone();
/// ```
///
/// Here is the same example with `sabi_reborrow`
///
/// ```
/// use abi_stable::{
///     sabi_trait::{doc_examples::ConstExample_TO, TD_Opaque},
///     std_types::*,
/// };
///
/// let mut object = ConstExample_TO::from_value(10usize, TD_Opaque);
/// let borrow = object.sabi_reborrow();
/// let _ = borrow.clone();
/// ```
///
///
impl<'lt, P, I, V> Clone for RObject<'lt, P, I, V>
where
    P: AsPtr,
    I: InterfaceType,
    Self: CloneImpl<<P as GetPointerKind>::Kind>,
{
    fn clone(&self) -> Self {
        self.clone_impl()
    }
}

impl<'lt, P, I, V> Debug for RObject<'lt, P, I, V>
where
    P: AsPtr<PtrTarget = ()> + AsPtr,
    I: InterfaceType<Debug = Implemented<trait_marker::Debug>>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        unsafe {
            adapt_std_fmt::<ErasedObject>(
                self.sabi_erased_ref(),
                self.sabi_robject_vtable()._sabi_debug().unwrap(),
                f,
            )
        }
    }
}

impl<'lt, P, I, V> Display for RObject<'lt, P, I, V>
where
    P: AsPtr<PtrTarget = ()>,
    I: InterfaceType<Display = Implemented<trait_marker::Display>>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        unsafe {
            adapt_std_fmt::<ErasedObject>(
                self.sabi_erased_ref(),
                self.sabi_robject_vtable()._sabi_display().unwrap(),
                f,
            )
        }
    }
}

impl<'lt, P, I, V> std::error::Error for RObject<'lt, P, I, V>
where
    P: AsPtr<PtrTarget = ()>,
    I: InterfaceType<
        Display = Implemented<trait_marker::Display>,
        Debug = Implemented<trait_marker::Debug>,
        Error = Implemented<trait_marker::Error>,
    >,
{
}

unsafe impl<'lt, P, I, V> Send for RObject<'lt, P, I, V>
where
    P: GetPointerKind,
    I: InterfaceType<Send = Implemented<trait_marker::Send>>,
{
}

unsafe impl<'lt, P, I, V> Sync for RObject<'lt, P, I, V>
where
    P: GetPointerKind,
    I: InterfaceType<Sync = Implemented<trait_marker::Sync>>,
{
}

impl<'lt, P, I, V> Unpin for RObject<'lt, P, I, V>
where
    // `Unpin` is a property of the referent
    P: GetPointerKind,
    I: InterfaceType<Unpin = Implemented<trait_marker::Unpin>>,
{
}

impl<'lt, P, I, V> RObject<'lt, P, I, V>
where
    P: AsPtr<PtrTarget = ()>,
{
    /// Constructs an RObject from a pointer and an extra vtable.
    ///
    /// This is mostly intended to be called by `#[sabi_trait]` generated trait objects.
    ///
    /// # Safety
    ///
    /// These are the requirements for the caller:
    ///
    /// - `P` must be a pointer to the type that the vtable functions
    ///     take as the first parameter.
    ///
    /// - The vtable must not come from a reborrowed `RObject`
    ///     (created using `RObject::reborrow` or `RObject::reborrow_mut`).
    ///
    /// - The vtable must be the `SomeVTableName` of a struct declared with
    ///     `#[derive(StableAbi)] #[sabi(kind(Prefix(prefix_ref= SomeVTableName)))]`.
    ///
    /// - The vtable must have `RObjectVtable_Ref` as its first declared field
    ///
    pub unsafe fn with_vtable<OrigPtr>(ptr: OrigPtr, vtable: PrefixRef<V>) -> RObject<'lt, P, I, V>
    where
        OrigPtr: CanTransmuteElement<(), TransmutedPtr = P>,
        OrigPtr::PtrTarget: Sized + 'lt,
        P: AsPtr<PtrTarget = ()>,
    {
        RObject {
            vtable,
            ptr: ManuallyDrop::new(unsafe { ptr.transmute_element::<()>() }),
            _marker: PhantomData,
        }
    }
}

impl<'borr, 'a, I, V> RObject<'borr, RRef<'a, ()>, I, V> {
    /// This function allows constructing an RObject in a constant/static.
    ///
    /// This is mostly intended for `#[sabi_trait]`-generated trait objects
    ///
    /// # Safety
    ///
    /// This has the same safety requirements as `RObject::with_vtable`
    ///
    /// # Example
    ///
    /// Because this is intended for `#[sabi_trait]` generated trait objects,
    /// this demonstrates how to construct one in a constant.
    ///
    /// ```
    /// use abi_stable::sabi_trait::{
    ///     doc_examples::ConstExample_CTO,
    ///     prelude::TD_Opaque,
    /// };
    ///
    /// const EXAMPLE0: ConstExample_CTO<'static, 'static> =
    ///     ConstExample_CTO::from_const(&0usize, TD_Opaque);
    ///
    /// ```
    pub const unsafe fn with_vtable_const<T, Downcasting>(ptr: &'a T, vtable: PrefixRef<V>) -> Self
    where
        T: 'borr,
    {
        RObject {
            vtable,
            ptr: {
                let x = unsafe { RRef::new(ptr).transmute::<()>() };
                ManuallyDrop::new(x)
            },
            _marker: PhantomData,
        }
    }
}

impl<'lt, P, I, V> RObject<'lt, P, I, V>
where
    P: GetPointerKind,
{
    /// The uid in the vtable has to be the same as the one for T,
    /// otherwise it was not created from that T in the library that
    /// declared the trait object.
    fn sabi_check_same_utypeid<T>(&self) -> Result<(), UneraseError<()>>
    where
        T: 'static,
    {
        let expected_typeid = self.sabi_robject_vtable()._sabi_type_id()();
        let actual_typeid = UTypeId::new::<T>();
        if expected_typeid == MaybeCmp::Just(actual_typeid) {
            Ok(())
        } else {
            Err(UneraseError {
                robject: (),
                expected_typeid,
                actual_typeid,
            })
        }
    }

    /// Attempts to unerase this trait object into the pointer it was constructed with.
    ///
    /// # Errors
    ///
    /// This will return an error in any of these conditions:
    ///
    /// - It is called in a dynamic library/binary outside
    /// the one from which this RObject was constructed.
    ///
    /// - The trait object wrapping this `RObject` was constructed with a
    /// `TD_CanDowncast` argument.
    ///
    /// - `T` is not the concrete type this `RObject<_>` was constructed with.
    ///
    /// # Example
    ///
    /// ```rust
    /// use abi_stable::{
    ///     sabi_trait::doc_examples::Doer_TO, std_types::RBox,
    ///     type_level::downcasting::TD_CanDowncast,
    /// };
    ///
    /// let to = || Doer_TO::from_value(5usize, TD_CanDowncast);
    ///
    /// // `to.obj` is an RObject
    /// assert_eq!(
    ///     to().obj.downcast_into::<usize>().ok(),
    ///     Some(RBox::new(5usize))
    /// );
    /// assert_eq!(to().obj.downcast_into::<u8>().ok(), None);
    ///
    /// ```
    pub fn downcast_into<T>(self) -> Result<P::TransmutedPtr, UneraseError<Self>>
    where
        T: 'static,
        P: AsPtr<PtrTarget = ()> + CanTransmuteElement<T>,
    {
        check_unerased!(self, self.sabi_check_same_utypeid::<T>());
        unsafe {
            let this = ManuallyDrop::new(self);
            Ok(ptr::read(&*this.ptr).transmute_element::<T>())
        }
    }

    /// Attempts to unerase this trait object into a reference of
    /// the value was constructed with.
    ///
    /// # Errors
    ///
    /// This will return an error in any of these conditions:
    ///
    /// - It is called in a dynamic library/binary outside
    /// the one from which this RObject was constructed.
    ///
    /// - The trait object wrapping this `RObject` was constructed with a
    /// `TD_CanDowncast` argument.
    ///
    /// - `T` is not the concrete type this `RObject<_>` was constructed with.
    ///
    /// # Example
    ///
    /// ```rust
    /// use abi_stable::{
    ///     sabi_trait::doc_examples::Doer_TO, std_types::RArc,
    ///     type_level::downcasting::TD_CanDowncast, RMut, RRef,
    /// };
    ///
    /// {
    ///     let to: Doer_TO<'_, RArc<()>> =
    ///         Doer_TO::from_ptr(RArc::new(8usize), TD_CanDowncast);
    ///
    ///     // `to.obj` is an RObject
    ///     assert_eq!(to.obj.downcast_as::<usize>().ok(), Some(&8usize));
    ///     assert_eq!(to.obj.downcast_as::<u8>().ok(), None);
    /// }
    /// {
    ///     // `#[sabi_trait]` trait objects constructed from `&`
    ///     // use `RRef<'_, ()>` instead of `&'_ ()`
    ///     // since `&T` can't soundly be transmuted back and forth into `&()`
    ///     let to: Doer_TO<'_, RRef<'_, ()>> = Doer_TO::from_ptr(&13usize, TD_CanDowncast);
    ///
    ///     assert_eq!(to.obj.downcast_as::<usize>().ok(), Some(&13usize));
    ///     assert_eq!(to.obj.downcast_as::<u8>().ok(), None);
    /// }
    /// {
    ///     let mmut = &mut 21usize;
    ///     // `#[sabi_trait]` trait objects constructed from `&mut`
    ///     // use `RMut<'_, ()>` instead of `&'_ mut ()`
    ///     // since `&mut T` can't soundly be transmuted back and forth into `&mut ()`
    ///     let to: Doer_TO<'_, RMut<'_, ()>> = Doer_TO::from_ptr(mmut, TD_CanDowncast);
    ///
    ///     assert_eq!(to.obj.downcast_as::<usize>().ok(), Some(&21usize));
    ///     assert_eq!(to.obj.downcast_as::<u8>().ok(), None);
    /// }
    ///
    /// ```
    pub fn downcast_as<T>(&self) -> Result<&T, UneraseError<&Self>>
    where
        T: 'static,
        P: AsPtr<PtrTarget = ()> + CanTransmuteElement<T>,
    {
        check_unerased!(self, self.sabi_check_same_utypeid::<T>());
        unsafe { Ok(&*(self.ptr.as_ptr() as *const T)) }
    }

    /// Attempts to unerase this trait object into a mutable reference of
    /// the value was constructed with.
    ///
    /// # Errors
    ///
    /// This will return an error in any of these conditions:
    ///
    /// - It is called in a dynamic library/binary outside
    /// the one from which this RObject was constructed.
    ///
    /// - The trait object wrapping this `RObject` was constructed with a
    /// `TD_CanDowncast` argument.
    ///
    /// - `T` is not the concrete type this `RObject<_>` was constructed with.
    ///
    ///
    /// # Example
    ///
    /// ```rust
    /// use abi_stable::{
    ///     sabi_trait::doc_examples::Doer_TO, std_types::RBox,
    ///     type_level::downcasting::TD_CanDowncast, RMut, RRef,
    /// };
    ///
    /// {
    ///     let mut to: Doer_TO<'_, RBox<()>> =
    ///         Doer_TO::from_value(34usize, TD_CanDowncast);
    ///
    ///     // `to.obj` is an RObject
    ///     assert_eq!(to.obj.downcast_as_mut::<usize>().ok(), Some(&mut 34usize));
    ///     assert_eq!(to.obj.downcast_as_mut::<u8>().ok(), None);
    /// }
    /// {
    ///     let mmut = &mut 55usize;
    ///     // `#[sabi_trait]` trait objects constructed from `&mut`
    ///     // use `RMut<'_, ()>` instead of `&'_ mut ()`
    ///     // since `&mut T` can't soundly be transmuted back and forth into `&mut ()`
    ///     let mut to: Doer_TO<'_, RMut<'_, ()>> = Doer_TO::from_ptr(mmut, TD_CanDowncast);
    ///
    ///     assert_eq!(to.obj.downcast_as_mut::<usize>().ok(), Some(&mut 55usize));
    ///     assert_eq!(to.obj.downcast_as_mut::<u8>().ok(), None);
    /// }
    ///
    /// ```
    pub fn downcast_as_mut<T>(&mut self) -> Result<&mut T, UneraseError<&mut Self>>
    where
        T: 'static,
        P: AsMutPtr<PtrTarget = ()> + CanTransmuteElement<T>,
    {
        check_unerased!(self, self.sabi_check_same_utypeid::<T>());
        unsafe { Ok(&mut *(self.ptr.as_mut_ptr() as *mut T)) }
    }

    /// Unwraps the `RObject<_>` into a pointer to T,
    /// without checking whether `T` is the type that the RObject was constructed with.
    ///
    /// # Safety
    ///
    /// You must check that `T` is the type that RObject was constructed
    /// with through other means.
    ///
    /// # Example
    ///
    /// ```rust
    /// use abi_stable::{
    ///     sabi_trait::doc_examples::Doer_TO, std_types::RBox,
    ///     type_level::downcasting::TD_Opaque,
    /// };
    ///
    /// let to = || Doer_TO::from_value(5usize, TD_Opaque);
    ///
    /// unsafe {
    ///     // `to.obj` is an RObject
    ///     assert_eq!(
    ///         to().obj.unchecked_downcast_into::<usize>(),
    ///         RBox::new(5usize)
    ///     );
    /// }
    /// ```
    #[inline]
    pub unsafe fn unchecked_downcast_into<T>(self) -> P::TransmutedPtr
    where
        P: AsPtr<PtrTarget = ()> + CanTransmuteElement<T>,
    {
        let this = ManuallyDrop::new(self);
        unsafe { ptr::read(&*this.ptr).transmute_element::<T>() }
    }

    /// Unwraps the `RObject<_>` into a reference to T,
    /// without checking whether `T` is the type that the RObject was constructed with.
    ///
    /// # Safety
    ///
    /// You must check that `T` is the type that RObject was constructed
    /// with through other means.
    ///
    /// # Example
    ///
    /// ```rust
    /// use abi_stable::{
    ///     sabi_trait::doc_examples::Doer_TO, std_types::RArc,
    ///     type_level::downcasting::TD_Opaque, RMut, RRef,
    /// };
    ///
    /// {
    ///     let to: Doer_TO<'_, RArc<()>> = Doer_TO::from_ptr(RArc::new(8usize), TD_Opaque);
    ///
    ///     unsafe {
    ///         // `to.obj` is an RObject
    ///         assert_eq!(to.obj.unchecked_downcast_as::<usize>(), &8usize);
    ///     }
    /// }
    /// {
    ///     // `#[sabi_trait]` trait objects constructed from `&`
    ///     // use `RRef<'_, ()>` instead of `&'_ ()`
    ///     // since `&T` can't soundly be transmuted back and forth into `&()`
    ///     let to: Doer_TO<'_, RRef<'_, ()>> = Doer_TO::from_ptr(&13usize, TD_Opaque);
    ///
    ///     unsafe {
    ///         assert_eq!(to.obj.unchecked_downcast_as::<usize>(), &13usize);
    ///     }
    /// }
    /// {
    ///     let mmut = &mut 21usize;
    ///     // `#[sabi_trait]` trait objects constructed from `&mut`
    ///     // use `RMut<'_, ()>` instead of `&'_ mut ()`
    ///     // since `&mut T` can't soundly be transmuted back and forth into `&mut ()`
    ///     let to: Doer_TO<'_, RMut<'_, ()>> = Doer_TO::from_ptr(mmut, TD_Opaque);
    ///
    ///     unsafe {
    ///         assert_eq!(to.obj.unchecked_downcast_as::<usize>(), &21usize);
    ///     }
    /// }
    ///
    /// ```
    #[inline]
    pub unsafe fn unchecked_downcast_as<T>(&self) -> &T
    where
        P: AsPtr<PtrTarget = ()>,
    {
        unsafe { &*(self.ptr.as_ptr() as *const T) }
    }

    /// Unwraps the `RObject<_>` into a mutable reference to T,
    /// without checking whether `T` is the type that the RObject was constructed with.
    ///
    /// # Safety
    ///
    /// You must check that `T` is the type that RObject was constructed
    /// with through other means.
    ///
    /// # Example
    ///
    /// ```rust
    /// use abi_stable::{
    ///     sabi_trait::doc_examples::Doer_TO, std_types::RBox,
    ///     type_level::downcasting::TD_Opaque, RMut, RRef,
    /// };
    ///
    /// {
    ///     let mut to: Doer_TO<'_, RBox<()>> = Doer_TO::from_value(34usize, TD_Opaque);
    ///
    ///     unsafe {
    ///         // `to.obj` is an RObject
    ///         assert_eq!(to.obj.unchecked_downcast_as_mut::<usize>(), &mut 34usize);
    ///     }
    /// }
    /// {
    ///     let mmut = &mut 55usize;
    ///     // `#[sabi_trait]` trait objects constructed from `&mut`
    ///     // use `RMut<'_, ()>` instead of `&'_ mut ()`
    ///     // since `&mut T` can't soundly be transmuted back and forth into `&mut ()`
    ///     let mut to: Doer_TO<'_, RMut<'_, ()>> = Doer_TO::from_ptr(mmut, TD_Opaque);
    ///
    ///     unsafe {
    ///         assert_eq!(to.obj.unchecked_downcast_as_mut::<usize>(), &mut 55usize);
    ///     }
    /// }
    ///
    /// ```
    #[inline]
    pub unsafe fn unchecked_downcast_as_mut<T>(&mut self) -> &mut T
    where
        P: AsMutPtr<PtrTarget = ()>,
    {
        unsafe { &mut *(self.ptr.as_mut_ptr() as *mut T) }
    }
}

mod private_struct {
    pub struct PrivStruct;
}
use self::private_struct::PrivStruct;

/// This is used to make sure that reborrowing does not change
/// the Send-ness or Sync-ness of the pointer.
pub trait ReborrowBounds<SendNess, SyncNess> {}

// If it's reborrowing, it must have either both Sync+Send or neither.
impl ReborrowBounds<Unimplemented<trait_marker::Send>, Unimplemented<trait_marker::Sync>>
    for PrivStruct
{
}

impl ReborrowBounds<Implemented<trait_marker::Send>, Implemented<trait_marker::Sync>>
    for PrivStruct
{
}

impl<'lt, P, I, V> RObject<'lt, P, I, V>
where
    P: GetPointerKind,
    I: InterfaceType,
{
    /// Creates a shared reborrow of this RObject.
    ///
    /// This is only callable if `RObject` is either `Send + Sync` or `!Send + !Sync`.
    ///
    /// # Example
    ///
    /// ```rust
    /// use abi_stable::{
    ///     sabi_trait::doc_examples::Doer_TO, std_types::RBox,
    ///     type_level::downcasting::TD_Opaque, RMut, RRef,
    /// };
    ///
    /// let mut to: Doer_TO<'_, RBox<()>> = Doer_TO::from_value(13usize, TD_Opaque);
    ///
    /// // `to.obj` is an RObject
    /// assert_eq!(debug_string(to.obj.reborrow()), "13");
    /// assert_eq!(debug_string(to.obj.reborrow()), "13");
    ///
    /// // `#[sabi_trait]` trait objects have an equivalent `sabi_reborrow` method.
    /// assert_eq!(debug_string(to.sabi_reborrow()), "13");
    /// assert_eq!(debug_string(to.sabi_reborrow()), "13");
    ///
    /// fn debug_string<T>(to: T) -> String
    /// where
    ///     T: std::fmt::Debug,
    /// {
    ///     format!("{:?}", to)
    /// }
    ///
    /// ```
    pub fn reborrow<'re>(&'re self) -> RObject<'lt, RRef<'re, ()>, I, V>
    where
        P: AsPtr<PtrTarget = ()>,
        PrivStruct: ReborrowBounds<I::Send, I::Sync>,
    {
        // Reborrowing will break if I add extra functions that operate on `P`.
        RObject {
            vtable: self.vtable,
            ptr: ManuallyDrop::new(self.ptr.as_rref()),
            _marker: PhantomData,
        }
    }

    /// Creates a mutable reborrow of this RObject.
    ///
    /// The reborrowed RObject cannot use these methods:
    ///
    /// - RObject::clone
    ///
    /// This is only callable if `RObject` is either `Send + Sync` or `!Send + !Sync`.
    ///
    /// # Example
    ///
    /// ```rust
    /// use abi_stable::{
    ///     sabi_trait::doc_examples::{Doer, Doer_TO},
    ///     std_types::RBox,
    ///     type_level::downcasting::TD_Opaque,
    ///     RMut, RRef,
    /// };
    ///
    /// let mut to: Doer_TO<'_, RBox<()>> = Doer_TO::from_value(2usize, TD_Opaque);
    ///
    /// // `#[sabi_trait]` trait objects have an equivalent `sabi_reborrow_mut` method,
    /// // which delegate to this method.
    /// assert_eq!(increment(to.sabi_reborrow_mut()).value(), 3);
    /// assert_eq!(increment(to.sabi_reborrow_mut()).value(), 4);
    ///
    /// fn increment<T>(mut to: T) -> T
    /// where
    ///     T: Doer,
    /// {
    ///     to.add_into(1);
    ///     to
    /// }
    ///
    /// ```
    pub fn reborrow_mut<'re>(&'re mut self) -> RObject<'lt, RMut<'re, ()>, I, V>
    where
        P: AsMutPtr<PtrTarget = ()>,
        PrivStruct: ReborrowBounds<I::Send, I::Sync>,
    {
        // Reborrowing will break if I add extra functions that operate on `P`.
        RObject {
            vtable: self.vtable,
            ptr: ManuallyDrop::new(self.ptr.as_rmut()),
            _marker: PhantomData,
        }
    }
}

impl<'lt, P, I, V> RObject<'lt, P, I, V>
where
    P: GetPointerKind,
{
    /// Gets the vtable.
    #[inline]
    pub const fn sabi_et_vtable(&self) -> PrefixRef<V> {
        self.vtable
    }

    /// The vtable common to all `#[sabi_trait]` generated trait objects.
    #[inline]
    pub fn sabi_robject_vtable(&self) -> RObjectVtable_Ref<(), P, I> {
        unsafe { BaseVtable_Ref(self.vtable.cast::<BaseVtable_Prefix<(), P, I>>())._sabi_vtable() }
    }

    #[inline]
    fn sabi_into_erased_ptr(self) -> ManuallyDrop<P> {
        let __this = ManuallyDrop::new(self);
        unsafe { ptr::read(&__this.ptr) }
    }

    /// Gets an `RRef` pointing to the erased object.
    pub fn sabi_erased_ref(&self) -> RRef<'_, ErasedObject<()>>
    where
        P: AsPtr<PtrTarget = ()>,
    {
        unsafe { RRef::from_raw(self.ptr.as_ptr() as *const _) }
    }

    /// Gets an `RMut` pointing to the erased object.
    pub fn sabi_erased_mut(&mut self) -> RMut<'_, ErasedObject<()>>
    where
        P: AsMutPtr<PtrTarget = ()>,
    {
        unsafe { RMut::from_raw(self.ptr.as_mut_ptr() as *mut _) }
    }

    /// Gets an `RRef` pointing to the erased object.
    pub fn sabi_as_rref(&self) -> RRef<'_, ()>
    where
        P: AsPtr<PtrTarget = ()>,
    {
        self.ptr.as_rref()
    }

    /// Gets an `RMut` pointing to the erased object.
    pub fn sabi_as_rmut(&mut self) -> RMut<'_, ()>
    where
        P: AsMutPtr<PtrTarget = ()>,
    {
        self.ptr.as_rmut()
    }

    /// Calls the `f` callback with an `MovePtr` pointing to the erased object.
    #[inline]
    pub fn sabi_with_value<F, R>(self, f: F) -> R
    where
        P: OwnedPointer<PtrTarget = ()>,
        F: FnOnce(MovePtr<'_, ()>) -> R,
    {
        OwnedPointer::with_move_ptr(self.sabi_into_erased_ptr(), f)
    }
}

impl<P, I, V> Drop for RObject<'_, P, I, V>
where
    P: GetPointerKind,
{
    fn drop(&mut self) {
        // This condition is necessary because if the RObject was reborrowed,
        // the destructor function would take a different pointer type.
        if <P as GetPointerKind>::KIND == PointerKind::SmartPointer {
            let destructor = self.sabi_robject_vtable()._sabi_drop();
            unsafe {
                destructor(RMut::<P>::new(&mut self.ptr));
            }
        }
    }
}

//////////////////////////////////////////////////////////////////

/// Error for `RObject<_>` being downcasted into the wrong type
/// with one of the `*downcast*` methods.
#[derive(Copy, Clone)]
pub struct UneraseError<T> {
    robject: T,
    expected_typeid: MaybeCmp<UTypeId>,
    actual_typeid: UTypeId,
}

#[allow(clippy::missing_const_for_fn)]
impl<T> UneraseError<T> {
    fn map<F, U>(self, f: F) -> UneraseError<U>
    where
        F: FnOnce(T) -> U,
    {
        UneraseError {
            robject: f(self.robject),
            expected_typeid: self.expected_typeid,
            actual_typeid: self.actual_typeid,
        }
    }

    /// Extracts the RObject, to handle the failure to unerase it.
    #[must_use]
    pub fn into_inner(self) -> T {
        self.robject
    }
}

impl<D> fmt::Debug for UneraseError<D> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("UneraseError")
            .field("dyn_trait", &"<not shown>")
            .field("expected_typeid", &self.expected_typeid)
            .field("actual_typeid", &self.actual_typeid)
            .finish()
    }
}

impl<D> fmt::Display for UneraseError<D> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

impl<D> ::std::error::Error for UneraseError<D> {}

//////////////////////////////////////////////////////////////////