use crate::hkt::ImpliedBound; use super::{erased::Erased, type_name, WithLtTypeId}; /// Type erased mutable borrow of a unsized type. /// /// This type acts like a `&'a mut dyn Trait<'ctx> + 'lt` with the `Trait` part erased. /// This type exists to get a mutable borrow of an arbitrary trait object out of a object safe method. /// However, it is not limited to storing mutable borrows of trait objects. It can be /// used to store a mutable borrow to any type including sized ones. pub struct MutAnyUnsized<'r, 'lt> { /// As shown in the table at https://doc.rust-lang.org/nomicon/subtyping.html#variance /// mutable 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::<&mut dyn core::any::Any>() }>, /// 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> MutAnyUnsized<'r, 'lt> { /// Create from a borrow. pub fn new>(borrow: &'r mut T) -> Self { Self { _b: ImpliedBound::NEW, borrow: Erased::new::<&'r mut T>(borrow), type_name_id: || WithLtTypeId::of::(), } } /// Downcast the type erased value back to its original type. pub fn downcast>(self) -> Result<&'r mut T, Self> { if (self.type_name_id)() == WithLtTypeId::of::() { #[allow(unsafe_code)] Ok(unsafe { self.borrow.into_inner::<&'r mut T>() }) } else { Err(self) } } }