flect 0.1.1

Rust reflection [WIP]
Documentation
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
    }

    /// # Safety
    /// See [byte_add](NonNull::byte_add) and [add](NonNull::add)
    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
    }

    /// # Safety
    /// See [byte_add](NonNull::byte_add) and [add](NonNull::add)
    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()
    }

    /// Casts `self` as a reference of `T`.
    ///
    /// This is a shortcut for `self.cast::<T>().as_ref().unwrap()`
    ///
    /// # Safety
    /// The specified T must be valid for reads for this ptr
    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 }
    }
}