use core::any::{Any, TypeId};
use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
use core::fmt::{Debug, Display, Formatter, Pointer, Result as FmtResult};
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::{mem, ptr};
use crate::Miny;
macro_rules! impl_refs {
($method:ident $trait:ident $($kw:tt)?) => {
impl<T: ?Sized> $trait<T> for Miny<T> {
#[inline]
fn $method(&$($kw)? self) -> &$($kw)? T {
self
}
}
};
}
impl_refs!(as_ref AsRef);
impl_refs!(as_mut AsMut mut);
impl_refs!(borrow Borrow);
impl_refs!(borrow_mut BorrowMut mut);
impl<T: Clone> Clone for Miny<T> {
#[inline]
fn clone(&self) -> Self { Self::new((**self).clone()) }
#[inline]
fn clone_from(&mut self, source: &Self) { (**self).clone_from(source); }
}
impl<T: Default> Default for Miny<T> {
#[inline]
fn default() -> Self { Self::new(T::default()) }
}
impl<T: ?Sized + Debug> Debug for Miny<T> {
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> FmtResult { Debug::fmt(&**self, fmt) }
}
impl<T: ?Sized + Display> Display for Miny<T> {
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> FmtResult { Display::fmt(&**self, fmt) }
}
impl<T: ?Sized> Pointer for Miny<T> {
fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
if Self::on_stack(self) {
fmt.write_str("<stack>")
} else {
Pointer::fmt(&core::ptr::addr_of!(**self), fmt)
}
}
}
impl<T: ?Sized + PartialEq> PartialEq for Miny<T> {
#[inline]
fn eq(&self, other: &Self) -> bool { (**self).eq(&**other) }
}
impl<T: ?Sized + Eq> Eq for Miny<T> {}
impl<T: ?Sized + PartialOrd> PartialOrd for Miny<T> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { (**self).partial_cmp(&**other) }
}
impl<T: ?Sized + Ord> Ord for Miny<T> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering { (**self).cmp(&**other) }
}
impl<T: ?Sized + Hash> Hash for Miny<T> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) { (**self).hash(state); }
}
unsafe impl<T: ?Sized + Sync> Sync for Miny<T> {}
unsafe impl<T: ?Sized + Send> Send for Miny<T> {}
impl<T: ?Sized + Any> Miny<T> {
#[inline]
pub fn is<V: Any>(&self) -> bool { TypeId::of::<V>() == (**self).type_id() }
pub unsafe fn downcast_ref_unchecked<V: Any>(&self) -> &V {
debug_assert!(self.is::<V>(), "unchecked cast was wrong!");
&*ptr::from_ref(self.as_ref()).cast::<V>()
}
pub unsafe fn downcast_mut_unchecked<V: Any>(&mut self) -> &mut V {
debug_assert!(self.is::<V>(), "unchecked cast was wrong!");
&mut *ptr::from_mut(self.as_mut()).cast::<V>()
}
pub unsafe fn downcast_unchecked<V: Any>(self) -> V {
debug_assert!(self.is::<V>(), "unchecked cast was wrong!");
let data = self.data;
mem::forget(self);
Miny::into_inner(Miny::<V> {
data,
meta: (),
marker: PhantomData,
})
}
pub fn downcast_ref<V: Any>(&self) -> Option<&V> {
self.is::<V>().then(||
unsafe { self.downcast_ref_unchecked() })
}
pub fn downcast_mut<V: Any>(&mut self) -> Option<&mut V> {
self.is::<V>().then(||
unsafe { self.downcast_mut_unchecked() })
}
#[expect(clippy::missing_errors_doc, reason = "obvious implementation")]
pub fn downcast<V: Any>(self) -> Result<V, Self> {
if self.is::<V>() {
Ok(unsafe { self.downcast_unchecked() })
} else {
Err(self)
}
}
}
#[cfg(feature = "allocative")]
impl<T> allocative::Allocative for Miny<T>
where
T: ?Sized + allocative::Allocative,
{
fn visit<'visitor, 'contents: 'visitor>(
&self,
visitor: &'visitor mut allocative::Visitor<'contents>,
) {
use core::ptr::Pointee;
let mut visitor = visitor.enter_self_sized::<Self>();
let meta_size = mem::size_of::<<T as Pointee>::Metadata>();
if meta_size > 0 {
visitor.visit_field_with(allocative::Key::new("meta"), meta_size, |_| {});
}
if Self::on_stack(self) {
visitor.visit_field(allocative::Key::new("inline"), &**self);
} else {
let mut visitor =
visitor.enter_unique(allocative::Key::new("ptr"), mem::size_of::<*mut ()>());
T::visit(self, &mut visitor);
}
visitor.exit();
}
}