use crate::hkt::ImpliedBound; use super::{erased::Erased, type_name, WithLtTypeId}; /// Type erased borrow of a unsized type. /// /// This type acts like a `&'a dyn Trait<'ctx> + 'lt` with the `Trait` part erased. /// This type exists to get a borrow of an arbitrary trait object out of a object safe method. /// However, it is not limited to storing borrows of trait objects. It can be /// used to store a borrow to any type including sized ones. pub struct RefAnyUnsized<'r, 'lt> { /// As shown in the table at https://doc.rust-lang.org/nomicon/subtyping.html#variance /// borrows are covariant over their lifetime, so we are also. _b: ImpliedBound<'r, 'lt>, /// The type erased borrow. /// /// This should be able to store any unsized type in current Rust as all of /// them are 2 usize in width. borrow: Erased<{ core::mem::size_of::<&dyn core::any::Any>() }>, /// We would prefer to be covariant over 'lt and 'ctx to match borrows, /// but this would break the safety requirements of transmuting the type. /// So instead they are invariant as given by WithLtTypeId. /// /// We use a function here to reduce the size down to one usize. /// This makes a RefAnyUnsized only 3 usize wide. type_name_id: fn() -> WithLtTypeId<'lt>, } impl<'r, 'lt> RefAnyUnsized<'r, 'lt> { /// Create from a borrow. pub fn new>(borrow: &'r T) -> Self { Self { _b: ImpliedBound::NEW, borrow: Erased::new::<&'r T>(borrow), type_name_id: || WithLtTypeId::of::(), } } /// Downcast the type erased value back to its original type. pub fn downcast>(self) -> Result<&'r T, Self> { if (self.type_name_id)() == WithLtTypeId::of::() { #[allow(unsafe_code)] Ok(unsafe { self.borrow.into_inner::<&'r T>() }) } else { Err(self) } } }