#![cfg_attr(feature = "no_std", no_std)]
#![cfg_attr(feature = "nightly", feature(const_fn, raw))]
#![forbid(missing_docs)]
#[cfg(feature = "no_std")]
extern crate core as std;
#[cfg(test)]
mod tests;
#[cfg(feature = "nightly")]
mod nightly;
mod traits;
mod error;
mod fmt;
mod maybe_uninit;
mod unreachable;
#[cfg(feature = "nightly")]
pub use self::nightly::*;
pub use self::traits::*;
pub use self::error::*;
use self::maybe_uninit::*;
use crate::unreachable::UncheckedOptionExt as _;
use std::marker::PhantomData;
use std::ptr::NonNull;
use core::num::*;
macro_rules! impl_delta_zeroable {
($($type:ty),* $(,)?) => {$(
unsafe impl Delta for $type {
type Error = IntegerDeltaError;
fn sub(a: *mut u8, b: *mut u8) -> Result<Self, Self::Error> {
let del = match isize::checked_sub(a as usize as _, b as usize as _) {
Some(del) => del,
None => return Err(IntegerDeltaError(IntegerDeltaErrorImpl::Sub(a as usize, b as usize)))
};
if std::mem::size_of::<Self>() < std::mem::size_of::<isize>() && (
(Self::min_value() as isize) > del ||
(Self::max_value() as isize) < del
)
{
Err(IntegerDeltaError(IntegerDeltaErrorImpl::Conversion(del)))
} else {
Ok(del as _)
}
}
unsafe fn sub_unchecked(a: *mut u8, b: *mut u8) -> Self {
isize::checked_sub(a as usize as _, b as usize as _).unchecked_unwrap() as _
}
unsafe fn add(self, a: *const u8) -> *mut u8 {
<*const u8>::offset(a, self as isize) as *mut u8
}
}
impl Nullable for $type {
const NULL: Self = 0;
}
)*};
}
impl_delta_zeroable! { i8, i16, i32, i64, i128, isize }
macro_rules! impl_delta_nonzero {
($($type:ident $base:ident),* $(,)?) => {$(
unsafe impl Delta for $type {
type Error = IntegerDeltaError;
fn sub(a: *mut u8, b: *mut u8) -> Result<Self, Self::Error> {
let del = match isize::checked_sub(a as usize as _, b as usize as _) {
None => return Err(IntegerDeltaError(IntegerDeltaErrorImpl::Sub(a as usize, b as usize))),
Some(0) => return Err(IntegerDeltaError(IntegerDeltaErrorImpl::InvalidNonZero)),
Some(del) => del,
};
if std::mem::size_of::<Self>() < std::mem::size_of::<isize>() && (
($base::min_value() as isize) > del ||
($base::max_value() as isize) < del
)
{
Err(IntegerDeltaError(IntegerDeltaErrorImpl::Conversion(del)))
} else {
unsafe { Ok(Self::new_unchecked(del as _)) }
}
}
unsafe fn sub_unchecked(a: *mut u8, b: *mut u8) -> Self {
Self::new_unchecked(isize::checked_sub(a as usize as _, b as usize as _).unchecked_unwrap() as _)
}
unsafe fn add(self, a: *const u8) -> *mut u8 {
<*mut u8>::offset(a as _, self.get() as isize) as *mut u8
}
}
)*};
}
impl_delta_nonzero! { NonZeroI8 i8, NonZeroI16 i16, NonZeroI32 i32, NonZeroI64 i64, NonZeroI128 i128, NonZeroIsize isize }
#[inline(always)]
fn nn_to_ptr<T: ?Sized>(nn: Ptr<T>) -> *mut T {
unsafe { std::mem::transmute(nn) }
}
pub struct RelPtr<T: ?Sized + MetaData, I: Delta = isize>(I, MaybeUninit<T::Data>, PhantomData<*mut T>);
impl<T: ?Sized + MetaData, I: Delta> Copy for RelPtr<T, I> {}
impl<T: ?Sized + MetaData, I: Delta> Clone for RelPtr<T, I> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized + MetaData, I: Delta> Eq for RelPtr<T, I> {}
impl<T: ?Sized + MetaData, I: Delta> PartialEq for RelPtr<T, I> {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self, other)
}
}
impl<T: ?Sized + MetaData, I: Delta> From<I> for RelPtr<T, I> {
fn from(i: I) -> Self {
Self(i, MaybeUninit::null(), PhantomData)
}
}
impl<T: ?Sized + MetaData, I: Nullable> RelPtr<T, I> {
#[inline(always)]
pub fn null() -> Self {
Self(I::NULL, MaybeUninit::null(), PhantomData)
}
#[inline(always)]
pub fn is_null(&self) -> bool {
self.0 == I::NULL
}
}
impl<T: ?Sized + MetaData, I: Delta> RelPtr<T, I> {
#[inline]
pub fn set(&mut self, value: &mut T) -> Result<(), I::Error> {
self.0 = I::sub(value as *mut T as _, self as *mut Self as _)?;
self.1.set(T::data(value));
Ok(())
}
#[inline]
pub unsafe fn set_unchecked(&mut self, value: *mut T) {
self.0 = I::sub_unchecked(value as *mut T as _, self as *mut Self as _);
self.1.set(T::data(&*value));
}
#[inline]
unsafe fn as_raw_unchecked_impl(&self) -> *const T {
nn_to_ptr(T::compose(
NonNull::new(self.0.add(self as *const Self as *const u8)),
self.1.get()
))
}
#[inline]
pub unsafe fn as_raw_unchecked(&mut self) -> *mut T {
self.as_raw_unchecked_impl() as _
}
#[inline]
pub unsafe fn as_non_null_unchecked(&mut self) -> NonNull<T> {
T::compose(
NonNull::new(self.0.add(self as *mut Self as *mut u8)),
self.1.get()
).unchecked_unwrap()
}
#[inline]
pub unsafe fn as_ref_unchecked(&self) -> &T {
&*self.as_raw_unchecked_impl()
}
#[inline]
pub unsafe fn as_mut_unchecked(&mut self) -> &mut T {
&mut *self.as_raw_unchecked()
}
}
impl<T: ?Sized + MetaData, I: Nullable> RelPtr<T, I> {
#[inline]
unsafe fn as_non_null_impl(&self) -> Ptr<T> {
if self.is_null() {
None
} else {
T::compose(
NonNull::new(self.0.add(self as *const Self as *const u8)),
self.1.get()
)
}
}
#[inline]
pub unsafe fn as_raw(&mut self) -> *mut T {
nn_to_ptr(self.as_non_null())
}
#[inline]
pub unsafe fn as_non_null(&mut self) -> Ptr<T> {
self.as_non_null_impl()
}
#[inline]
pub unsafe fn as_ref(&self) -> Option<&T> {
Some(&*self.as_non_null_impl()?.as_ptr())
}
#[inline]
pub unsafe fn as_mut(&mut self) -> Option<&mut T> {
Some(&mut *self.as_non_null()?.as_ptr())
}
}