#![no_std]
#![feature(extern_types)]
#![feature(layout_for_ptr)]
#![feature(ptr_metadata)]
#![feature(unsize)]
#[cfg(test)]
mod tests;
use core::alloc::Layout;
use core::any::type_name;
use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
use core::fmt::{self, Debug, Display, Formatter};
use core::hash::{Hash, Hasher};
use core::iter::IntoIterator;
use core::marker::{PhantomData, Unsize};
use core::ops::{Deref, DerefMut, Index, IndexMut};
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::ptr::{self, NonNull, Pointee};
#[repr(transparent)]
struct Metadata<T: ?Sized>(<T as Pointee>::Metadata);
impl<T: ?Sized> Clone for Metadata<T> {
fn clone(&self) -> Self {
Self(self.0)
}
}
impl<T: ?Sized> Debug for Metadata<T>
where <T as Pointee>::Metadata: Debug
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: ?Sized> Copy for Metadata<T> {}
impl<T: ?Sized> UnwindSafe for Metadata<T> {}
impl<T: ?Sized> RefUnwindSafe for Metadata<T> {}
extern "C" {
pub type Erased;
}
impl Debug for Erased {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Erased")
}
}
impl RefUnwindSafe for Erased {}
impl UnwindSafe for Erased {}
impl Unpin for Erased {}
unsafe impl Send for Erased {}
unsafe impl Sync for Erased {}
#[repr(C)]
pub struct Fat<T: ?Sized, U: ?Sized = Erased> {
_phantom: PhantomData<T>,
metadata: Metadata<T>,
data: U,
}
impl<T: ?Sized, U: Unsize<T>> Fat<T, U> {
#[must_use]
pub fn new(value: U) -> Self {
Self { _phantom: PhantomData, metadata: Metadata(ptr::metadata(&value as &T)), data: value }
}
}
impl<T: ?Sized, U> Fat<T, U> {
#[must_use]
pub fn into_inner(fat: Self) -> U {
fat.data
}
#[must_use]
pub fn inner_ref(fat: &Self) -> &U {
&fat.data
}
#[must_use]
pub fn inner_mut(fat: &mut Self) -> &mut U {
&mut fat.data
}
}
impl<T: ?Sized> Fat<T> {
#[must_use]
pub unsafe fn container_of(referent: *const T) -> NonNull<Self> {
let offset = unsafe { Self::layout_for(&ptr::metadata(referent)).1 };
unsafe { NonNull::new_unchecked((referent as *const u8).sub(offset) as *mut Self) }
}
}
impl<T: ?Sized, U: ?Sized> Fat<T, U> {
#[inline(always)] #[must_use]
pub fn erase_ref(fat: &Self) -> &Fat<T> {
unsafe { &*(fat as *const Self as *const Fat<T>) }
}
#[inline(always)] #[must_use]
pub fn erase_mut(fat: &mut Self) -> &mut Fat<T> {
unsafe { &mut *(fat as *mut Self as *mut Fat<T>) }
}
#[must_use]
pub fn data_addr(fat: &Self) -> NonNull<()> {
let base = fat as *const Self as *const u8;
let offset = Self::layout_of(fat).1;
unsafe { NonNull::new_unchecked(base.add(offset) as *mut ()) }
}
#[must_use]
pub fn data_addr_mut(fat: &mut Self) -> NonNull<()> {
let base = fat as *mut Self as *mut u8;
let offset = Self::layout_of(fat).1;
unsafe { NonNull::new_unchecked(base.add(offset) as *mut ()) }
}
#[inline(always)] #[must_use]
pub fn metadata(fat: &Self) -> &<T as Pointee>::Metadata {
&fat.metadata.0
}
#[inline(always)] #[must_use]
pub fn layout_of(fat: &Self) -> (Layout, usize) {
unsafe { Self::layout_for(&fat.metadata.0) }
}
#[must_use]
pub unsafe fn layout_for(metadata: &<T as Pointee>::Metadata) -> (Layout, usize) {
let layout_ptr = ptr::from_raw_parts::<T>(ptr::null(), *metadata);
let data_layout = unsafe { Layout::for_value_raw(layout_ptr) };
let (layout, data_offset) =
unsafe { Layout::new::<Metadata<T>>().extend(data_layout).unwrap_unchecked() };
(layout.pad_to_align(), data_offset)
}
}
impl<T: ?Sized, U: ?Sized> AsRef<Fat<T>> for Fat<T, U> {
fn as_ref(&self) -> &Fat<T> {
Self::erase_ref(self)
}
}
impl<T: ?Sized, U: ?Sized> AsMut<Fat<T>> for Fat<T, U> {
fn as_mut(&mut self) -> &mut Fat<T> {
Self::erase_mut(self)
}
}
impl<T: ?Sized, U: ?Sized> AsRef<T> for Fat<T, U> {
fn as_ref(&self) -> &T {
self
}
}
impl<T: ?Sized, U: ?Sized> AsMut<T> for Fat<T, U> {
fn as_mut(&mut self) -> &mut T {
self
}
}
impl<T: ?Sized, U> Borrow<Fat<T>> for Fat<T, U> {
fn borrow(&self) -> &Fat<T> {
Self::erase_ref(self)
}
}
impl<T: ?Sized, U: ?Sized> Borrow<T> for Fat<T, U> {
fn borrow(&self) -> &T {
self
}
}
impl<T: ?Sized, U: ?Sized> BorrowMut<T> for Fat<T, U> {
fn borrow_mut(&mut self) -> &mut T {
self
}
}
impl<T: ?Sized, U> BorrowMut<Fat<T>> for Fat<T, U> {
fn borrow_mut(&mut self) -> &mut Fat<T> {
Self::erase_mut(self)
}
}
impl<T: ?Sized, U: Unsize<T> + Clone> Clone for Fat<T, U> {
fn clone(&self) -> Self {
Self::new(self.data.clone())
}
}
impl<T: ?Sized, U: Unsize<T> + Copy> Copy for Fat<T, U> {}
impl<T: ?Sized, U: ?Sized> Debug for Fat<T, U>
where <T as Pointee>::Metadata: Debug
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct(type_name::<Self>())
.field("metadata", &self.metadata)
.field("data_addr", &Self::data_addr(self).as_ptr())
.field("layout", &Self::layout_of(self))
.finish()
}
}
impl<T: ?Sized, U: Default + Unsize<T>> Default for Fat<T, U> {
fn default() -> Self {
Self::new(U::default())
}
}
impl<T: ?Sized, U: ?Sized> Deref for Fat<T, U> {
type Target = T;
fn deref(&self) -> &T {
let ptr = NonNull::from_raw_parts(Self::data_addr(self), self.metadata.0);
unsafe { ptr.as_ref() }
}
}
impl<T: ?Sized, U: ?Sized> DerefMut for Fat<T, U> {
fn deref_mut(&mut self) -> &mut T {
let mut ptr = NonNull::from_raw_parts(Self::data_addr_mut(self), self.metadata.0);
unsafe { ptr.as_mut() }
}
}
impl<T: Display + ?Sized, U: ?Sized> Display for Fat<T, U> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Deref::deref(self).fmt(f)
}
}
impl<T: Eq + ?Sized, U: ?Sized> Eq for Fat<T, U> {}
impl<T: ?Sized, U: Unsize<T>> From<U> for Fat<T, U> {
fn from(value: U) -> Self {
Self::new(value)
}
}
impl<T: Hash + ?Sized, U: ?Sized> Hash for Fat<T, U> {
fn hash<H: Hasher>(&self, h: &mut H) {
Deref::deref(self).hash(h)
}
}
impl<'a, T: ?Sized, U: ?Sized> IntoIterator for &'a Fat<T, U>
where &'a T: IntoIterator
{
type Item = <&'a T as IntoIterator>::Item;
type IntoIter = <&'a T as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
Deref::deref(self).into_iter()
}
}
impl<'a, T: ?Sized, U: ?Sized> IntoIterator for &'a mut Fat<T, U>
where &'a mut T: IntoIterator
{
type Item = <&'a mut T as IntoIterator>::Item;
type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
DerefMut::deref_mut(self).into_iter()
}
}
impl<T: Index<Idx> + ?Sized, U: ?Sized, Idx> Index<Idx> for Fat<T, U> {
type Output = T::Output;
fn index(&self, index: Idx) -> &Self::Output {
Deref::deref(self).index(index)
}
}
impl<T: IndexMut<Idx> + ?Sized, U: ?Sized, Idx> IndexMut<Idx> for Fat<T, U> {
fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
DerefMut::deref_mut(self).index_mut(index)
}
}
impl<T: Ord + ?Sized, U: ?Sized> Ord for Fat<T, U> {
fn cmp(&self, other: &Self) -> Ordering {
Deref::deref(self).cmp(other)
}
}
impl<T: PartialEq + ?Sized, U: ?Sized, V: ?Sized> PartialEq<Fat<T, V>> for Fat<T, U> {
fn eq(&self, other: &Fat<T, V>) -> bool {
Deref::deref(self).eq(other)
}
}
impl<T: PartialEq + ?Sized, U: ?Sized> PartialEq<T> for Fat<T, U> {
fn eq(&self, other: &T) -> bool {
Deref::deref(self).eq(other)
}
}
impl<T: PartialOrd + ?Sized, U: ?Sized, V: ?Sized> PartialOrd<Fat<T, V>> for Fat<T, U> {
fn partial_cmp(&self, other: &Fat<T, V>) -> Option<Ordering> {
Deref::deref(self).partial_cmp(other)
}
}
impl<T: PartialOrd + ?Sized, U: ?Sized> PartialOrd<T> for Fat<T, U> {
fn partial_cmp(&self, other: &T) -> Option<Ordering> {
Deref::deref(self).partial_cmp(other)
}
}