use std::cmp::Eq;
use std::marker::PhantomData;
use std::ops;
pub trait PositionType: std::fmt::Debug + Copy + Clone + PartialEq + Eq + PartialOrd + Ord
where
Self: ops::Add<usize, Output = Self>,
Self: ops::Sub<usize, Output = Self>,
Self: ops::Sub<Self, Output = usize>,
Self: ops::AddAssign<usize>,
Self: ops::SubAssign<usize>,
{
}
#[cfg(feature = "index-positions")]
pub type DefPosition<'a> = IndexPosition<'a>;
#[cfg(not(feature = "index-positions"))]
pub type DefPosition<'a> = RefPosition<'a>;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct IndexPosition<'a>(usize, PhantomData<&'a ()>);
#[allow(dead_code)]
impl<'a> IndexPosition<'a> {
#[inline(always)]
pub fn check_size() {}
#[inline(always)]
pub fn new(pos: usize) -> Self {
Self(pos, PhantomData)
}
}
impl ops::Add<usize> for IndexPosition<'_> {
type Output = Self;
#[inline(always)]
fn add(self, rhs: usize) -> Self::Output {
debug_assert!(self.0 + rhs >= self.0, "Overflow");
IndexPosition(self.0 + rhs, PhantomData)
}
}
impl ops::AddAssign<usize> for IndexPosition<'_> {
#[inline(always)]
fn add_assign(&mut self, rhs: usize) {
*self = *self + rhs;
}
}
impl ops::SubAssign<usize> for IndexPosition<'_> {
#[inline(always)]
fn sub_assign(&mut self, rhs: usize) {
*self = *self - rhs;
}
}
impl<'a> ops::Sub<IndexPosition<'a>> for IndexPosition<'a> {
type Output = usize;
#[inline(always)]
fn sub(self, rhs: Self) -> Self::Output {
debug_assert!(self.0 >= rhs.0, "Underflow");
self.0 - rhs.0
}
}
impl ops::Sub<usize> for IndexPosition<'_> {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: usize) -> Self::Output {
debug_assert!(self.0 >= rhs, "Underflow");
IndexPosition(self.0 - rhs, PhantomData)
}
}
impl PositionType for IndexPosition<'_> {}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct RefPosition<'a>(std::ptr::NonNull<u8>, PhantomData<&'a ()>);
#[allow(dead_code)]
impl RefPosition<'_> {
#[inline(always)]
pub fn check_size() {
if std::mem::size_of::<Option<Self>>() > std::mem::size_of::<*const u8>() {
panic!("Option<RefPosition> should be pointer sized")
}
}
#[inline(always)]
pub fn ptr(self) -> *const u8 {
self.0.as_ptr()
}
#[inline(always)]
pub fn new(ptr: *const u8) -> Self {
debug_assert!(!ptr.is_null(), "Pointer cannot be null");
let mutp = ptr as *mut u8;
let nonnullp = if cfg!(feature = "prohibit-unsafe") {
std::ptr::NonNull::new(mutp).expect("Pointer was null")
} else {
unsafe { std::ptr::NonNull::new_unchecked(mutp) }
};
Self(nonnullp, PhantomData)
}
}
impl PositionType for RefPosition<'_> {}
impl ops::Add<usize> for RefPosition<'_> {
type Output = Self;
#[inline(always)]
fn add(self, rhs: usize) -> Self::Output {
Self::new(unsafe { self.ptr().add(rhs) })
}
}
impl<'a> ops::Sub<RefPosition<'a>> for RefPosition<'a> {
type Output = usize;
#[inline(always)]
fn sub(self, rhs: Self) -> Self::Output {
debug_assert!(self.0 >= rhs.0, "Underflow");
unsafe { self.ptr().offset_from(rhs.ptr()) as usize }
}
}
impl ops::Sub<usize> for RefPosition<'_> {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: usize) -> Self::Output {
debug_assert!(self.ptr() as usize >= rhs, "Underflow");
Self::new(unsafe { self.ptr().sub(rhs) })
}
}
impl ops::AddAssign<usize> for RefPosition<'_> {
#[inline(always)]
fn add_assign(&mut self, rhs: usize) {
*self = *self + rhs;
}
}
impl ops::SubAssign<usize> for RefPosition<'_> {
#[inline(always)]
fn sub_assign(&mut self, rhs: usize) {
*self = *self - rhs;
}
}