use core::fmt;
#[cfg(feature = "unsize")]
use core::marker::Unsize;
use core::num::NonZeroUsize;
use core::ptr;
use core::ptr::{NonNull, Pointee};
pub trait Handle {
type Addr: Copy + Eq + PartialOrd;
type Target: ?Sized + Pointee;
type This<U: ?Sized>: Handle<Target = U>;
fn from_raw_parts(handle: Self::This<()>, meta: <Self::Target as Pointee>::Metadata) -> Self;
fn addr(self) -> Self::Addr;
fn metadata(self) -> <Self::Target as Pointee>::Metadata;
fn cast<U>(self) -> Self::This<U>;
fn cast_unsized<U>(self) -> Self::This<U>
where
U: ?Sized + Pointee<Metadata = <Self::Target as Pointee>::Metadata>;
#[cfg(feature = "unsize")]
fn coerce<U: ?Sized>(self) -> Self::This<U>
where
Self::Target: Unsize<U>;
}
impl<T: ?Sized + Pointee> Handle for *const T {
type Addr = usize;
type Target = T;
type This<U: ?Sized> = *const U;
fn from_raw_parts(handle: Self::This<()>, meta: T::Metadata) -> Self {
ptr::from_raw_parts(handle, meta)
}
fn addr(self) -> usize {
self.cast::<()>() as usize
}
fn metadata(self) -> T::Metadata {
ptr::metadata(self)
}
fn cast<U>(self) -> Self::This<U> {
self.cast()
}
fn cast_unsized<U>(self) -> Self::This<U>
where
U: ?Sized + Pointee<Metadata = T::Metadata>,
{
let meta = ptr::metadata(self);
ptr::from_raw_parts(self.cast::<()>(), meta)
}
#[cfg(feature = "unsize")]
fn coerce<U: ?Sized>(self) -> Self::This<U>
where
T: Unsize<U>,
{
self as *const U
}
}
impl<T: ?Sized + Pointee> Handle for *mut T {
type Addr = usize;
type Target = T;
type This<U: ?Sized> = *mut U;
fn from_raw_parts(handle: Self::This<()>, meta: T::Metadata) -> Self {
ptr::from_raw_parts_mut(handle, meta)
}
fn addr(self) -> usize {
self.cast::<()>() as usize
}
fn metadata(self) -> T::Metadata {
ptr::metadata(self)
}
fn cast<U>(self) -> Self::This<U> {
self.cast()
}
fn cast_unsized<U>(self) -> Self::This<U>
where
U: ?Sized + Pointee<Metadata = T::Metadata>,
{
let meta = ptr::metadata(self);
ptr::from_raw_parts_mut(self.cast::<()>(), meta)
}
#[cfg(feature = "unsize")]
fn coerce<U: ?Sized>(self) -> Self::This<U>
where
T: Unsize<U>,
{
self as *mut U
}
}
impl<T: ?Sized + Pointee> Handle for NonNull<T> {
type Addr = usize;
type Target = T;
type This<U: ?Sized> = NonNull<U>;
fn from_raw_parts(handle: Self::This<()>, meta: T::Metadata) -> Self {
NonNull::from_raw_parts(handle, meta)
}
fn addr(self) -> usize {
self.cast::<()>().as_ptr() as usize
}
fn metadata(self) -> T::Metadata {
ptr::metadata(self.as_ptr())
}
fn cast<U>(self) -> Self::This<U> {
self.cast()
}
fn cast_unsized<U>(self) -> Self::This<U>
where
U: ?Sized + Pointee<Metadata = T::Metadata>,
{
let meta = ptr::metadata(self.as_ptr());
NonNull::from_raw_parts(self.cast(), meta)
}
#[cfg(feature = "unsize")]
fn coerce<U: ?Sized>(self) -> Self::This<U>
where
T: Unsize<U>,
{
self as NonNull<U>
}
}
pub struct MetaHandle<T: ?Sized + Pointee>(T::Metadata);
impl<T: ?Sized + Pointee> MetaHandle<T> {
#[inline]
pub const fn from_metadata(meta: T::Metadata) -> MetaHandle<T> {
MetaHandle(meta)
}
#[inline]
pub const fn metadata(self) -> T::Metadata {
self.0
}
#[inline]
pub const fn cast<U>(self) -> MetaHandle<U> {
MetaHandle::from_metadata(())
}
#[inline]
pub const fn cast_unsized<U>(self) -> MetaHandle<U>
where
T: Pointee<Metadata = <U as Pointee>::Metadata>,
U: ?Sized,
{
MetaHandle::from_metadata(self.metadata())
}
#[cfg(feature = "unsize")]
pub const fn coerce<U: ?Sized>(self) -> MetaHandle<U>
where
T: Unsize<U>,
{
let ptr: *const T = ptr::from_raw_parts(ptr::null::<()>(), self.metadata());
let meta = ptr::metadata(ptr as *const U);
MetaHandle::from_metadata(meta)
}
}
impl<T: ?Sized + Pointee> Handle for MetaHandle<T> {
type Addr = ();
type Target = T;
type This<U: ?Sized> = MetaHandle<U>;
fn from_raw_parts(_: Self::This<()>, meta: T::Metadata) -> Self {
MetaHandle::from_metadata(meta)
}
fn addr(self) {}
fn metadata(self) -> T::Metadata {
MetaHandle::metadata(self)
}
fn cast<U>(self) -> Self::This<U> {
MetaHandle::from_metadata(())
}
fn cast_unsized<U>(self) -> Self::This<U>
where
U: ?Sized + Pointee<Metadata = T::Metadata>,
{
MetaHandle::from_metadata(self.metadata())
}
#[cfg(feature = "unsize")]
fn coerce<U: ?Sized>(self) -> Self::This<U>
where
T: Unsize<U>,
{
let ptr = ptr::from_raw_parts::<T>(ptr::null::<()>(), self.metadata()) as *const U;
let meta = ptr::metadata(ptr);
MetaHandle::from_metadata(meta)
}
}
impl<T: ?Sized> Copy for MetaHandle<T> {}
impl<T: ?Sized> Clone for MetaHandle<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> PartialEq for MetaHandle<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T> fmt::Debug for MetaHandle<T>
where
T: ?Sized + Pointee,
T::Metadata: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("MetaHandle").field(&self.0).finish()
}
}
pub struct OffsetMetaHandle<T: ?Sized + Pointee>(NonZeroUsize, T::Metadata);
impl<T: ?Sized + Pointee> OffsetMetaHandle<T> {
#[inline]
pub const fn from_offset_meta(offset: usize, meta: T::Metadata) -> OffsetMetaHandle<T> {
assert!(
offset != usize::MAX,
"OffsetMetaHandle reserves usize::MAX for niche optimization"
);
OffsetMetaHandle(unsafe { NonZeroUsize::new_unchecked(offset + 1) }, meta)
}
#[inline]
pub const fn offset(self) -> usize {
self.0.get() - 1
}
#[inline]
pub const fn metadata(self) -> T::Metadata {
self.1
}
#[inline]
pub const fn add(self, offset: usize) -> OffsetMetaHandle<T> {
OffsetMetaHandle::from_offset_meta(self.offset() + offset, self.metadata())
}
#[inline]
pub const fn sub(self, offset: usize) -> OffsetMetaHandle<T> {
OffsetMetaHandle::from_offset_meta(self.offset() - offset, self.metadata())
}
pub const fn offset_by(self, offset: isize) -> OffsetMetaHandle<T> {
let abs = offset.unsigned_abs();
if offset.is_negative() {
self.sub(abs)
} else {
self.add(abs)
}
}
#[inline]
pub const fn cast<U>(self) -> OffsetMetaHandle<U> {
OffsetMetaHandle::from_offset_meta(self.offset(), ())
}
#[inline]
pub const fn cast_unsized<U>(self) -> OffsetMetaHandle<U>
where
T: Pointee<Metadata = <U as Pointee>::Metadata>,
U: ?Sized,
{
OffsetMetaHandle::from_offset_meta(self.offset(), self.metadata())
}
#[cfg(feature = "unsize")]
pub const fn coerce<U: ?Sized>(self) -> OffsetMetaHandle<U>
where
T: Unsize<U>,
{
let ptr: *const T = ptr::from_raw_parts(ptr::null::<()>(), self.metadata());
let meta = ptr::metadata(ptr as *const U);
OffsetMetaHandle(self.0, meta)
}
}
impl<T: ?Sized + Pointee> Handle for OffsetMetaHandle<T> {
type Addr = usize;
type Target = T;
type This<U: ?Sized> = OffsetMetaHandle<U>;
fn from_raw_parts(handle: Self::This<()>, meta: T::Metadata) -> Self {
OffsetMetaHandle::from_offset_meta(handle.offset(), meta)
}
fn addr(self) -> usize {
self.offset()
}
fn metadata(self) -> T::Metadata {
OffsetMetaHandle::metadata(self)
}
fn cast<U>(self) -> Self::This<U> {
OffsetMetaHandle::from_offset_meta(self.offset(), ())
}
fn cast_unsized<U>(self) -> Self::This<U>
where
U: ?Sized + Pointee<Metadata = T::Metadata>,
{
OffsetMetaHandle::from_offset_meta(self.offset(), self.metadata())
}
#[cfg(feature = "unsize")]
fn coerce<U: ?Sized>(self) -> Self::This<U>
where
T: Unsize<U>,
{
let ptr = ptr::from_raw_parts::<T>(ptr::null::<()>(), self.metadata()) as *const U;
let meta = ptr::metadata(ptr);
OffsetMetaHandle::from_offset_meta(self.offset(), meta)
}
}
impl<T: ?Sized> Copy for OffsetMetaHandle<T> {}
impl<T: ?Sized> Clone for OffsetMetaHandle<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> PartialEq for OffsetMetaHandle<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0 && self.1 == other.1
}
}
impl<T> fmt::Debug for OffsetMetaHandle<T>
where
T: ?Sized + Pointee,
T::Metadata: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OffsetMetaHandle")
.field("offset", &self.offset())
.field("metadata", &self.metadata())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_meta_handle() {
let h1 = MetaHandle::<str>::from_metadata(1);
assert_eq!(h1.metadata(), 1);
let h2 = h1.cast::<()>();
assert_eq!(h2.metadata(), ());
let h3 = h1.cast_unsized::<[u8]>();
assert_eq!(h3.metadata(), 1);
assert_eq!(h1, MetaHandle::from_raw_parts(h2, 1));
assert_eq!(h3, MetaHandle::from_raw_parts(h2, 1));
}
}