#![no_std]
#![allow(unstable_name_collisions)]
#[cfg(feature="alloc")]
extern crate alloc;
#[cfg(feature="alloc")]
use alloc::boxed::Box;
use core::hash::*;
use core::marker::PhantomData;
use core::mem::align_of;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
#[cfg(not(feature="sptr"))]
mod sptr;
use sptr::Strict as _;
#[derive(Debug)]
#[repr(transparent)]
pub struct Ointer<T, const A: u8, const S: bool, const V: u8> {
ptr: *mut T,
}
impl<T, const A: u8, const S: bool, const V: u8> Hash for Ointer<T, A, S, V> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.ptr.hash(state)
}
}
impl<T, const A: u8, const S: bool, const V: u8> PartialEq<Self> for Ointer<T, A, S, V> {
fn eq(&self, other: &Self) -> bool { self.ptr == other.ptr }
}
impl<T, const A: u8, const S: bool, const V: u8> Eq for Ointer<T, A, S, V> {}
impl<T, const A: u8, const S: bool, const V: u8> Clone for Ointer<T, A, S, V> {
fn clone(&self) -> Self { *self }
}
impl<T, const A: u8, const S: bool, const V: u8> Copy for Ointer<T, A, S, V> {}
impl<T, const A: u8, const S: bool, const V: u8> Ointer<T, A, S, V> {
pub unsafe fn new(ptr: *mut T) -> Self {
Ointer { ptr: pack(ptr, A, S, V) }
}
pub unsafe fn new_stealing(ptr: *mut T, bits: usize) -> Self {
let mask = asv_mask(A, S, V);
let ptr = ptr.with_addr((bits & mask) | (ptr.addr() & !mask));
Self { ptr }
}
pub fn stolen(self) -> usize { self.ptr.addr() & asv_mask(A, S, V) }
pub fn steal(self, bits: usize) -> Self {
let mask = asv_mask(A, S, V);
let ptr = self.ptr.with_addr((bits & mask) | (self.ptr.addr() & !mask));
Self { ptr }
}
pub fn as_ptr(self) -> *mut T {
unsafe { unpack(self.ptr, A, S, V) }
}
pub fn raw(self) -> usize { self.ptr.expose_addr() }
}
#[derive(Debug)]
#[repr(transparent)]
pub struct NotNull<T, const A: u8, const S: bool, const V: u8>(NonNull<u8>, PhantomData<T>);
impl<T: Sized, const A: u8, const S: bool, const V: u8> Clone for NotNull<T, A, S, V> {
fn clone(&self) -> Self { *self }
}
impl<T: Sized, const A: u8, const S: bool, const V: u8> Copy for NotNull<T, A, S, V> {}
impl<T, const A: u8, const S: bool, const V: u8> PartialEq<Self> for NotNull<T, A, S, V> {
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}
impl<T, const A: u8, const S: bool, const V: u8> Eq for NotNull<T, A, S, V> {}
impl<T, const A: u8, const S: bool, const V: u8> Hash for NotNull<T, A, S, V> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state)
}
}
impl<T: Sized, const A: u8, const S: bool, const V: u8> NotNull<T, A, S, V> {
pub unsafe fn new(ptr: NonNull<T>) -> Self {
let ptr = pack(ptr.as_ptr(), A, S, V) as *mut u8;
NotNull(NonNull::new_unchecked(ptr), PhantomData)
}
pub unsafe fn new_stealing(ptr: NonNull<T>, bits: usize) -> Self {
let mask = asv_mask(A, S, V);
let ptr = (bits & mask) | (ptr.as_ptr().addr() & !mask);
NotNull(NonNull::new_unchecked(ptr as *mut u8), PhantomData)
}
pub fn stolen(self) -> usize { self.0.as_ptr().addr() & asv_mask(A, S, V) }
pub fn steal(self, bits: usize) -> Self {
let mask = asv_mask(A, S, V);
let bits = bits & mask;
let ptr = self.0.as_ptr();
let addr = ptr.addr() & !mask;
Self(unsafe { NonNull::new_unchecked(ptr.with_addr(addr | bits)) }, PhantomData)
}
pub fn as_non_null(self) -> NonNull<T> {
unsafe { NonNull::new_unchecked(unpack(self.0.as_ptr().cast(), A, S, V)) }
}
pub fn raw(self) -> usize { self.0.as_ptr().expose_addr() }
}
#[derive(Debug)]
#[repr(transparent)]
#[cfg(feature="alloc")]
pub struct Ox<T, const A: u8, const S: bool, const V: u8>(NonNull<u8>, PhantomData<T>);
#[cfg(feature="alloc")]
impl<T, const A: u8, const S: bool, const V: u8> Clone for Ox<T, A, S, V> {
fn clone(&self) -> Self { Ox(self.0, PhantomData) }
}
impl<T, const A: u8, const S: bool, const V: u8> PartialEq<Self> for Ox<T, A, S, V> {
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}
impl<T, const A: u8, const S: bool, const V: u8> Eq for Ox<T, A, S, V> {}
impl<T, const A: u8, const S: bool, const V: u8> Hash for Ox<T, A, S, V> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state)
}
}
#[cfg(feature="alloc")]
impl<T, const A: u8, const S: bool, const V: u8> Ox<T, A, S, V> {
pub unsafe fn new(boxed: Box<T>) -> Self {
let ptr = Box::into_raw(boxed);
let ptr = pack(ptr, A, S, V) as *mut u8;
Ox(NonNull::new_unchecked(ptr), PhantomData)
}
pub unsafe fn new_stealing(boxed: Box<T>, bits: usize) -> Self {
let mask = asv_mask(A, S, V);
let orig_ptr = Box::into_raw(boxed);
let ptr = orig_ptr.with_addr((bits & mask) | (orig_ptr.addr() & !mask));
Self(NonNull::new_unchecked(ptr as *mut u8), PhantomData)
}
pub fn stolen(&self) -> usize { self.0.as_ptr().addr() & asv_mask(A, S, V) }
pub fn steal(&mut self, bits: usize) {
let mask = asv_mask(A, S, V);
let bits = bits & mask;
let ptr = self.raw() & !mask;
self.0 = unsafe { NonNull::new_unchecked((ptr | bits) as *mut u8) };
}
pub fn into_box(self) -> Box<T> {
unsafe { Box::from_raw(unpack(self.as_ptr(), A, S, V)) }
}
pub fn as_ptr(&self) -> *mut T { self.0.as_ptr().cast() }
pub fn raw(&self) -> usize { self.0.as_ptr().expose_addr() }
}
#[cfg(feature="alloc")]
impl<T, const A: u8, const S: bool, const V: u8> Deref for Ox<T, A, S, V> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.0.as_ptr().cast() }
}
}
#[cfg(feature="alloc")]
impl<T, const A: u8, const S: bool, const V: u8> DerefMut for Ox<T, A, S, V> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.0.as_ptr().cast() }
}
}
#[cfg(feature="alloc")]
impl<T, const A: u8, const S: bool, const V: u8> Drop for Ox<T, A, S, V> {
fn drop(&mut self) {
drop(unsafe { Box::from_raw(self.0.as_ptr()) })
}
}
pub unsafe fn pack<T: Sized>(ptr: *mut T, a: u8, s: bool, v: u8) -> *mut T {
let sv = asv_mask(0, s, v);
#[cfg(debug_assertions)]
{
debug_assert!((1 << a) <= align_of::<T>());
#[cfg(all(not(target_pointer_width="64"), not(feature="i_know_what_im_doing")))]
debug_assert!(v == 0);
debug_assert!(v <= 25);
if s {
let ptr = ptr.addr();
let stack = (&ptr as *const usize).addr();
debug_assert!((sv & ptr) == (sv & stack));
}
}
ptr.with_addr((ptr.addr() & !sv) >> a as usize)
}
pub unsafe fn unpack<T: Sized>(packed: *mut T, a: u8, s: bool, v: u8) -> *mut T {
let asv = asv_mask(a, s, v);
let masked = packed.addr() & !asv;
let base = masked << a;
if s {
let sv = asv_mask(0, s, v);
let base = base & !sv;
let stack = (&base as *const usize).addr() & sv;
packed.with_addr(stack | base)
} else {
packed.with_addr((((base << v as usize) as isize) >> v as usize) as usize)
}
}
pub const fn asv_mask(a: u8, s: bool, v: u8) -> usize { mask(a + s as u8 + v) }
pub const fn mask(bits: u8) -> usize { (isize::MIN >> (max(bits as usize,1) - 1)) as usize }
const fn max(x: usize, y: usize) -> usize {
if x <= y { y } else { x }
}