#![warn(missing_docs, missing_debug_implementations)]
#![no_std]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, rc, sync};
use core::{
cmp::Ordering,
fmt::{self, Debug, Display, Formatter, Pointer},
future::Future,
hash::{Hash, Hasher},
iter::{FromIterator, FusedIterator},
marker::PhantomData,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
pin::Pin,
ptr,
task::{Context, Poll},
};
pub type ErasedPtr = ptr::NonNull<Erased>;
#[cfg(not(has_extern_type))]
pub(crate) use priv_in_pub::Erased;
#[cfg(not(has_extern_type))]
mod priv_in_pub {
pub struct Erased; }
#[cfg(has_extern_type)]
extern "Rust" {
pub type Erased;
}
impl Debug for Erased {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Erased").finish()
}
}
pub unsafe trait ErasablePtr {
fn erase(this: Self) -> ErasedPtr;
unsafe fn unerase(this: ErasedPtr) -> Self;
}
pub unsafe trait Erasable {
#[inline(always)]
fn erase(this: ptr::NonNull<Self>) -> ErasedPtr {
erase(this)
}
unsafe fn unerase(this: ErasedPtr) -> ptr::NonNull<Self>;
#[cfg(not(enforce_1_1_0_semantics))]
const ACK_1_1_0: bool = false;
#[cfg(enforce_1_1_0_semantics)]
const ACK_1_1_0: bool;
}
#[inline(always)]
pub fn erase<T: ?Sized>(ptr: ptr::NonNull<T>) -> ErasedPtr {
unsafe { ptr::NonNull::new_unchecked(ptr.as_ptr() as *mut Erased) }
}
#[repr(transparent)]
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> {
#[inline(always)]
fn from(this: P) -> Self {
Thin::<P> {
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,
{
let mut this = unsafe {
scopeguard::guard(P::unerase(this.ptr), |unerased| {
ptr::write(this, Thin::from(unerased))
})
};
f(&mut this)
}
pub fn ptr_eq<Q: ErasablePtr>(this: &Self, that: &Thin<Q>) -> bool {
this.ptr == that.ptr
}
}
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> Clone for Thin<P>
where
P: Clone,
{
fn clone(&self) -> Self {
Thin::with(self, |this| this.clone()).into()
}
}
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::deref(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::deref_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, A> FromIterator<A> for Thin<P>
where
P: FromIterator<A>,
{
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
P::from_iter(iter).into()
}
}
impl<P: ErasablePtr> FusedIterator for Thin<P> where P: FusedIterator {}
impl<P: ErasablePtr> Future for Thin<P>
where
P: Future,
{
type Output = P::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
unsafe {
Thin::with_mut(self.get_unchecked_mut(), |this| {
Pin::new_unchecked(this).poll(cx)
})
}
}
}
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: Sized> Erasable for T {
unsafe fn unerase(this: ErasedPtr) -> ptr::NonNull<T> {
this.cast()
}
const ACK_1_1_0: bool = true;
}
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<P: ErasablePtr> ErasablePtr for Thin<P> {
fn erase(this: Self) -> ErasedPtr {
ManuallyDrop::new(this).ptr
}
unsafe fn unerase(this: ErasedPtr) -> Self {
Thin {
ptr: this,
marker: PhantomData,
}
}
}
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()
}
}
unsafe impl<P> ErasablePtr for Pin<P>
where
P: ErasablePtr + Deref,
{
fn erase(this: Self) -> ErasedPtr {
unsafe { P::erase(Pin::into_inner_unchecked(this)) }
}
unsafe fn unerase(this: ErasedPtr) -> Self {
Pin::new_unchecked(P::unerase(this))
}
}
#[cfg(feature = "alloc")]
macro_rules! impl_erasable {
(for<$T:ident> $($(#[$meta:meta])* $ty:ty),* $(,)?) => {$(
$(#[$meta])*
unsafe impl<$T: ?Sized> ErasablePtr for $ty
where
T: Erasable,
{
#[inline]
fn erase(this: Self) -> ErasedPtr {
let ptr = unsafe { ptr::NonNull::new_unchecked(<$ty>::into_raw(this) as *mut _) };
T::erase(ptr)
}
#[inline]
unsafe fn unerase(this: ErasedPtr) -> Self {
Self::from_raw(T::unerase(this).as_ptr())
}
}
)*}
}
#[cfg(feature = "alloc")]
impl_erasable!(
for<T> Box<T>,
sync::Arc<T>,
sync::Weak<T>,
rc::Rc<T>,
rc::Weak<T>,
);
#[cfg(has_never)]
unsafe impl ErasablePtr for ! {
#[inline(always)]
fn erase(this: !) -> ErasedPtr {
this
}
#[rustfmt::skip]
#[inline(always)]
unsafe fn unerase(_this: ErasedPtr) -> Self {
#[cfg(debug_assertions)] {
panic!("attempted to unerase erased pointer to !")
}
#[cfg(not(debug_assertions))] {
core::hint::unreachable_unchecked()
}
}
}
#[inline(always)]
#[allow(clippy::needless_lifetimes)]
unsafe fn erase_lt<'a, 'b, T: ?Sized>(this: &'a T) -> &'b T {
&*(this as *const T)
}
#[inline(always)]
#[allow(clippy::needless_lifetimes)]
unsafe fn erase_lt_mut<'a, 'b, T: ?Sized>(this: &'a mut T) -> &'b mut T {
&mut *(this as *mut T)
}