#![no_std]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, rc::Rc, sync::Arc};
use core::{
cmp::Ordering,
fmt::{self, Debug, Display, Formatter, Pointer},
hash::{Hash, Hasher},
iter::FusedIterator,
marker::PhantomData,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
ptr,
};
pub type ErasedPtr = ptr::NonNull<Erased>;
pub(crate) use priv_in_pub::Erased;
mod priv_in_pub {
pub struct Erased;
}
pub unsafe trait ErasablePtr {
fn erase(this: Self) -> ErasedPtr;
unsafe fn unerase(this: ErasedPtr) -> Self;
}
pub unsafe trait Erasable {
fn erase(this: ptr::NonNull<Self>) -> ErasedPtr { erase(this) }
unsafe fn unerase(this: ErasedPtr) -> ptr::NonNull<Self>;
}
pub fn erase<T: ?Sized>(ptr: ptr::NonNull<T>) -> ErasedPtr {
unsafe { ptr::NonNull::new_unchecked(ptr.as_ptr() as *mut Erased) }
}
pub struct Thin<P: ErasablePtr> {
ptr: ErasedPtr,
marker: PhantomData<P>,
}
unsafe impl<P: ErasablePtr> Send for Thin<P> where P: Send {}
unsafe impl<P: ErasablePtr> Sync for Thin<P> where P: Sync {}
impl<P: ErasablePtr> From<P> for Thin<P> {
fn from(this: P) -> Self {
Thin {
ptr: P::erase(this),
marker: PhantomData,
}
}
}
impl<P: ErasablePtr> Thin<P> {
fn inner(this: &Self) -> ManuallyDrop<P> {
unsafe { ManuallyDrop::new(P::unerase(this.ptr)) }
}
pub fn into_inner(this: Self) -> P {
unsafe { P::unerase(ManuallyDrop::new(this).ptr) }
}
pub fn with<F, T>(this: &Self, f: F) -> T
where
F: FnOnce(&P) -> T,
{
f(&Thin::inner(this))
}
pub fn with_mut<F, T>(this: &mut Self, f: F) -> T
where
F: FnOnce(&mut P) -> T,
{
f(&mut Thin::inner(this))
}
}
impl<P: ErasablePtr> Drop for Thin<P> {
fn drop(&mut self) {
unsafe { P::unerase(self.ptr) };
}
}
impl<P: ErasablePtr, T: ?Sized> AsMut<T> for Thin<P>
where
P: AsMut<T>,
{
fn as_mut(&mut self) -> &mut T {
unsafe { Thin::with_mut(self, |p| erase_lt_mut(p.as_mut())) }
}
}
impl<P: ErasablePtr, T: ?Sized> AsRef<T> for Thin<P>
where
P: AsRef<T>,
{
fn as_ref(&self) -> &T {
unsafe { Thin::with(self, |p| erase_lt(p.as_ref())) }
}
}
impl<P: ErasablePtr> Debug for Thin<P>
where
P: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Thin::with(self, |p| p.fmt(f))
}
}
impl<P: ErasablePtr> Deref for Thin<P>
where
P: Deref,
{
type Target = P::Target;
fn deref(&self) -> &P::Target {
unsafe { Thin::with(self, |p| erase_lt(p)) }
}
}
impl<P: ErasablePtr> DerefMut for Thin<P>
where
P: DerefMut,
{
fn deref_mut(&mut self) -> &mut P::Target {
unsafe { Thin::with_mut(self, |p| erase_lt_mut(p)) }
}
}
impl<P: ErasablePtr> Display for Thin<P>
where
P: Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Thin::with(self, |p| p.fmt(f))
}
}
impl<P: ErasablePtr> DoubleEndedIterator for Thin<P>
where
P: DoubleEndedIterator,
{
fn next_back(&mut self) -> Option<Self::Item> {
Thin::with_mut(self, |p| p.next_back())
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
Thin::with_mut(self, |p| p.nth_back(n))
}
}
impl<P: ErasablePtr> Eq for Thin<P> where P: Eq {}
impl<P: ErasablePtr> ExactSizeIterator for Thin<P> where P: ExactSizeIterator {}
impl<P: ErasablePtr> FusedIterator for Thin<P> where P: FusedIterator {}
impl<P: ErasablePtr> Hash for Thin<P>
where
P: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
Thin::with(self, |p| p.hash(state))
}
}
impl<P: ErasablePtr> Hasher for Thin<P>
where
P: Hasher,
{
fn finish(&self) -> u64 {
Thin::with(self, |p| p.finish())
}
fn write(&mut self, bytes: &[u8]) {
Thin::with_mut(self, |p| p.write(bytes))
}
fn write_u8(&mut self, i: u8) {
Thin::with_mut(self, |p| p.write_u8(i))
}
fn write_u16(&mut self, i: u16) {
Thin::with_mut(self, |p| p.write_u16(i))
}
fn write_u32(&mut self, i: u32) {
Thin::with_mut(self, |p| p.write_u32(i))
}
fn write_u64(&mut self, i: u64) {
Thin::with_mut(self, |p| p.write_u64(i))
}
fn write_u128(&mut self, i: u128) {
Thin::with_mut(self, |p| p.write_u128(i))
}
fn write_usize(&mut self, i: usize) {
Thin::with_mut(self, |p| p.write_usize(i))
}
fn write_i8(&mut self, i: i8) {
Thin::with_mut(self, |p| p.write_i8(i))
}
fn write_i16(&mut self, i: i16) {
Thin::with_mut(self, |p| p.write_i16(i))
}
fn write_i32(&mut self, i: i32) {
Thin::with_mut(self, |p| p.write_i32(i))
}
fn write_i64(&mut self, i: i64) {
Thin::with_mut(self, |p| p.write_i64(i))
}
fn write_i128(&mut self, i: i128) {
Thin::with_mut(self, |p| p.write_i128(i))
}
fn write_isize(&mut self, i: isize) {
Thin::with_mut(self, |p| p.write_isize(i))
}
}
impl<P: ErasablePtr> Iterator for Thin<P>
where
P: Iterator,
{
type Item = P::Item;
fn next(&mut self) -> Option<Self::Item> {
Thin::with_mut(self, |p| p.next())
}
fn size_hint(&self) -> (usize, Option<usize>) {
Thin::with(self, |p| p.size_hint())
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
Thin::with_mut(self, |p| p.nth(n))
}
}
impl<P: ErasablePtr> Ord for Thin<P>
where
P: Ord,
{
fn cmp(&self, other: &Thin<P>) -> Ordering {
Thin::with(self, |p| Thin::with(other, |other| p.cmp(other)))
}
}
impl<P: ErasablePtr> PartialEq for Thin<P>
where
P: PartialEq,
{
fn eq(&self, other: &Thin<P>) -> bool {
Thin::with(self, |p| Thin::with(other, |other| p.eq(other)))
}
}
impl<P: ErasablePtr> PartialOrd for Thin<P>
where
P: PartialOrd,
{
fn partial_cmp(&self, other: &Thin<P>) -> Option<Ordering> {
Thin::with(self, |p| Thin::with(other, |other| p.partial_cmp(other)))
}
}
impl<P: ErasablePtr> Pointer for Thin<P>
where
P: Pointer,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Thin::with(self, |p| p.fmt(f))
}
}
unsafe impl<T> Erasable for T {
unsafe fn unerase(this: ErasedPtr) -> ptr::NonNull<T> {
this.cast()
}
}
unsafe impl<T: ?Sized> ErasablePtr for ptr::NonNull<T>
where
T: Erasable,
{
fn erase(this: Self) -> ErasedPtr {
T::erase(this)
}
unsafe fn unerase(this: ErasedPtr) -> Self {
T::unerase(this)
}
}
unsafe impl<T: ?Sized> ErasablePtr for &'_ T
where
T: Erasable,
{
fn erase(this: Self) -> ErasedPtr {
T::erase(this.into())
}
unsafe fn unerase(this: ErasedPtr) -> Self {
&*T::unerase(this).as_ptr()
}
}
unsafe impl<T: ?Sized> ErasablePtr for &'_ mut T
where
T: Erasable,
{
fn erase(this: Self) -> ErasedPtr {
T::erase(this.into())
}
unsafe fn unerase(this: ErasedPtr) -> Self {
&mut *T::unerase(this).as_ptr()
}
}
#[cfg(feature = "alloc")]
macro_rules! impl_erasable {
(for<$T:ident> $($ty:ty),* $(,)?) => {$(
unsafe impl<$T: ?Sized> ErasablePtr for $ty
where
T: Erasable,
{
fn erase(this: Self) -> ErasedPtr {
let ptr = unsafe { ptr::NonNull::new_unchecked(<$ty>::into_raw(this) as *mut _) };
T::erase(ptr)
}
unsafe fn unerase(this: ErasedPtr) -> Self {
Self::from_raw(T::unerase(this).as_ptr())
}
}
)*}
}
#[cfg(feature = "alloc")]
#[rustfmt::skip]
impl_erasable!(for<T>
Box<T>,
Arc<T>,
Rc<T>,
);
unsafe fn erase_lt<'a, 'b, T: ?Sized>(this: &'a T) -> &'b T {
&*(this as *const T)
}
unsafe fn erase_lt_mut<'a, 'b, T: ?Sized>(this: &'a mut T) -> &'b mut T {
&mut *(this as *mut T)
}