use core::marker::PhantomData;
use core::mem;
use core::ptr::NonNull;
#[derive(Clone, Copy)]
pub struct OpaqueThin {
raw: NonNull<u8>,
}
impl OpaqueThin {
#[allow(clippy::missing_safety_doc)]
pub const unsafe fn new<T: ?Sized>(data: *mut T) -> Self {
debug_assert!(
mem::size_of_val(&data) ==
mem::size_of::<NonNull<u8>>(),
);
Self {
raw: unsafe { NonNull::new_unchecked(data).cast() },
}
}
pub const fn as_byte_ptr(&self) -> *mut u8 { self.raw.cast().as_ptr() }
pub const fn cast<T: ?Sized>(&self) -> *mut T {
let raw = self.raw.as_ptr();
let raw_ref = &raw;
let transmuted = unsafe {
mem::transmute::<&*mut u8, &*mut T>(raw_ref)
};
*transmuted
}
pub const unsafe fn byte_add(&mut self, count: usize) {
unsafe { self.raw = self.raw.byte_add(count); }
}
}
#[derive(Clone, Copy)]
pub struct OpaqueWide {
raw: NonNull<[u8]>,
}
impl OpaqueWide {
pub const fn new<T: ?Sized>(data: *mut T) -> Self {
debug_assert!(
mem::size_of_val(&data) ==
mem::size_of::<NonNull<[u8]>>(),
);
let transmuted = unsafe {
let data_ref = &data;
mem::transmute::<&*mut T,&*mut [u8]>(data_ref)
};
Self {
raw: unsafe { NonNull::new_unchecked(*transmuted) },
}
}
pub const fn as_byte_ptr(&self) -> *mut u8 { self.raw.cast().as_ptr() }
pub const fn as_non_null(&self) -> NonNull<u8> { self.raw.cast() }
pub const fn cast<T: ?Sized>(&self) -> *mut T {
let raw = self.raw.as_ptr();
let raw_ref = &raw;
let transmuted = unsafe {
mem::transmute::<&*mut [u8], &*mut T>(raw_ref)
};
*transmuted
}
pub const unsafe fn byte_add(&mut self, count: usize) {
unsafe { self.raw = self.raw.byte_add(count); }
}
pub const fn len(&self) -> usize {
self.raw.len()
}
pub const fn is_empty(&self) -> bool {
self.raw.is_empty()
}
}
#[derive(Clone, Copy)]
enum OpaqueKind {
Thin(OpaqueThin),
Wide(OpaqueWide),
}
impl OpaqueKind {
pub const fn new<T: ?Sized>(data: *mut T) -> Self {
if mem::size_of_val(&data) == mem::size_of::<&u8>() {
Self::Thin(unsafe { OpaqueThin::new(data) })
} else if mem::size_of_val(&data) == mem::size_of::<&[u8]>() {
Self::Wide(OpaqueWide::new(data))
} else {
panic!("Couldn't determine if data is a thin or a wide pointer.")
}
}
pub const fn as_byte_ptr(&self) -> *mut u8 {
match self {
OpaqueKind::Thin(t) => t.as_byte_ptr(),
OpaqueKind::Wide(w) => w.as_byte_ptr(),
}
}
pub const fn cast<T: ?Sized>(&self) -> *mut T {
match self {
OpaqueKind::Thin(ptr) => ptr.cast(),
OpaqueKind::Wide(wide) => wide.cast(),
}
}
pub const fn byte_add(&mut self, n: usize) {
unsafe {
match self {
OpaqueKind::Thin(t) => t.byte_add(n),
OpaqueKind::Wide(w) => w.byte_add(n),
}
}
}
}
#[derive(Clone, Copy)]
pub struct OpaqueConst<'ptr> {
raw: OpaqueKind,
_m: PhantomData<&'ptr ()>,
}
impl<'ptr> OpaqueConst<'ptr> {
pub fn new<T: ?Sized>(ptr: &'ptr T) -> Self {
Self {
raw: OpaqueKind::new(ptr as *const _ as *mut T),
_m: PhantomData
}
}
pub const fn from_raw<T: ?Sized>(raw: *const T) -> Self {
Self {
raw: OpaqueKind::new(raw as *const _ as *mut T),
_m: PhantomData
}
}
pub const fn as_byte_ptr(&self) -> *const u8 {
self.raw.as_byte_ptr()
}
pub const fn cast<T: ?Sized>(&self) -> *const T {
self.raw.cast()
}
pub const unsafe fn cast_ref<T: ?Sized>(&self) -> &T {
unsafe { self.cast::<T>().as_ref().unwrap() }
}
pub const fn byte_add(mut self, n: usize) -> Self {
self.raw.byte_add(n);
self
}
pub const fn as_wide(&self) -> Option<OpaqueWide> {
match self.raw {
OpaqueKind::Thin(_) => None,
OpaqueKind::Wide(w) => Some(w),
}
}
}
#[derive(Clone, Copy)]
pub struct OpaqueMut<'ptr> {
raw: OpaqueKind,
_m: PhantomData<&'ptr mut ()>,
}
impl<'ptr> OpaqueMut<'ptr> {
pub fn new<T: ?Sized>(ptr: &'ptr mut T) -> Self {
Self {
raw: OpaqueKind::new(ptr as *mut T),
_m: PhantomData
}
}
pub const fn as_byte_ptr(&self) -> *const u8 {
self.raw.as_byte_ptr()
}
pub const fn cast<T: ?Sized>(&self) -> *const T {
self.raw.cast()
}
pub const fn as_mut_byte_ptr(&mut self) -> *mut u8 {
self.raw.as_byte_ptr()
}
pub const fn cast_mut<T: ?Sized>(&mut self) -> *mut T {
self.raw.cast()
}
pub fn as_const(&self) -> OpaqueConst {
OpaqueConst { raw: self.raw, _m: PhantomData }
}
}