use core::{
cmp,
convert::TryFrom,
fmt::{
self,
Debug,
Display,
Formatter,
Pointer,
},
hash::{
Hash,
Hasher,
},
ptr::NonNull,
};
use tap::Pipe;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Const;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Mut;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Frozen<Inner>
where Inner: Mutability
{
inner: Inner,
}
pub trait Mutability: 'static + Copy + Sized + seal::Sealed {
const CONTAINS_MUTABILITY: bool = false;
const PEANO_NUMBER: usize = 0;
const SELF: Self;
const RENDER: &'static str;
fn freeze(self) -> Frozen<Self> {
Frozen { inner: self }
}
fn thaw(Frozen { inner }: Frozen<Self>) -> Self {
inner
}
}
impl Mutability for Const {
const RENDER: &'static str = "*const";
const SELF: Self = Self;
}
impl seal::Sealed for Const {
}
impl<Inner> Mutability for Frozen<Inner>
where Inner: Mutability + Sized
{
const CONTAINS_MUTABILITY: bool = Inner::CONTAINS_MUTABILITY;
const PEANO_NUMBER: usize = 1 + Inner::PEANO_NUMBER;
const RENDER: &'static str = Inner::RENDER;
const SELF: Self = Self { inner: Inner::SELF };
}
impl<Inner> seal::Sealed for Frozen<Inner> where Inner: Mutability + Sized
{
}
impl Mutability for Mut {
const CONTAINS_MUTABILITY: bool = true;
const RENDER: &'static str = "*mut";
const SELF: Self = Self;
}
impl seal::Sealed for Mut {
}
pub struct Address<M, T>
where M: Mutability
{
inner: NonNull<T>,
comu: M,
}
impl<M, T> Address<M, T>
where M: Mutability
{
pub const DANGLING: Self = Self {
inner: NonNull::dangling(),
comu: M::SELF,
};
#[inline(always)]
pub fn new(addr: NonNull<T>) -> Self {
Self {
inner: addr,
comu: M::SELF,
}
}
#[inline(always)]
pub fn immut(self) -> Address<Const, T> {
Address {
inner: self.inner,
..Address::DANGLING
}
}
#[inline(always)]
pub unsafe fn assert_mut(self) -> Address<Mut, T> {
Address {
inner: self.inner,
..Address::DANGLING
}
}
#[inline(always)]
pub fn freeze(self) -> Address<Frozen<M>, T> {
let Self { inner, comu } = self;
Address {
inner,
comu: comu.freeze(),
}
}
#[inline(always)]
pub fn into_inner(self) -> NonNull<T> {
self.inner
}
#[inline]
pub unsafe fn offset(mut self, count: isize) -> Self {
self.inner = self
.inner
.as_ptr()
.offset(count)
.pipe(NonNull::new)
.unwrap();
self
}
#[inline]
pub fn wrapping_offset(mut self, count: isize) -> Self {
self.inner = self
.inner
.as_ptr()
.wrapping_offset(count)
.pipe(NonNull::new)
.unwrap();
self
}
#[inline(always)]
pub fn to_const(self) -> *const T {
self.inner.as_ptr() as *const T
}
#[inline(always)]
pub fn cast<U>(self) -> Address<M, U> {
let Self { inner, comu } = self;
Address {
inner: inner.cast::<U>(),
comu,
}
}
}
impl<T> Address<Mut, T> {
#[inline(always)]
#[allow(clippy::clippy::wrong_self_convention)]
pub fn to_mut(self) -> *mut T {
self.inner.as_ptr()
}
}
impl<M, T> Address<Frozen<M>, T>
where M: Mutability
{
#[inline(always)]
pub fn thaw(self) -> Address<M, T> {
let Self { inner, comu } = self;
Address {
inner,
comu: Mutability::thaw(comu),
}
}
}
impl<M, T> Clone for Address<M, T>
where M: Mutability
{
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<T> TryFrom<*const T> for Address<Const, T> {
type Error = NullPtrError;
#[inline(always)]
fn try_from(elem: *const T) -> Result<Self, Self::Error> {
NonNull::new(elem as *mut T)
.ok_or(NullPtrError)
.map(Self::new)
}
}
impl<T> From<&T> for Address<Const, T> {
#[inline(always)]
fn from(elem: &T) -> Self {
Self::new(elem.into())
}
}
impl<T> TryFrom<*mut T> for Address<Mut, T> {
type Error = NullPtrError;
#[inline(always)]
fn try_from(elem: *mut T) -> Result<Self, Self::Error> {
NonNull::new(elem).ok_or(NullPtrError).map(Self::new)
}
}
impl<T> From<&mut T> for Address<Mut, T> {
#[inline(always)]
fn from(elem: &mut T) -> Self {
Self::new(elem.into())
}
}
impl<M, T> Eq for Address<M, T> where M: Mutability
{
}
impl<M1, M2, T1, T2> PartialEq<Address<M2, T2>> for Address<M1, T1>
where
M1: Mutability,
M2: Mutability,
{
#[inline]
fn eq(&self, other: &Address<M2, T2>) -> bool {
self.inner.as_ptr() as usize == other.inner.as_ptr() as usize
}
}
impl<M, T> Ord for Address<M, T>
where M: Mutability
{
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.partial_cmp(&other)
.expect("Addresses have a total ordering")
}
}
impl<M1, M2, T1, T2> PartialOrd<Address<M2, T2>> for Address<M1, T1>
where
M1: Mutability,
M2: Mutability,
{
#[inline]
fn partial_cmp(&self, other: &Address<M2, T2>) -> Option<cmp::Ordering> {
(self.inner.as_ptr() as usize)
.partial_cmp(&(other.inner.as_ptr() as usize))
}
}
impl<M, T> Debug for Address<M, T>
where M: Mutability
{
#[inline(always)]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
Debug::fmt(&self.to_const(), fmt)
}
}
impl<M, T> Pointer for Address<M, T>
where M: Mutability
{
#[inline(always)]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
Pointer::fmt(&self.to_const(), fmt)
}
}
impl<M, T> Hash for Address<M, T>
where M: Mutability
{
#[inline(always)]
fn hash<H>(&self, state: &mut H)
where H: Hasher {
self.inner.hash(state)
}
}
impl<M, T> Copy for Address<M, T> where M: Mutability
{
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NullPtrError;
impl Display for NullPtrError {
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(fmt, "wyz::Address cannot contain a null pointer")
}
}
#[cfg(feature = "std")]
impl std::error::Error for NullPtrError {
}
#[doc(hidden)]
mod seal {
#[doc(hidden)]
pub trait Sealed {}
}