#![no_std]
#![allow(unstable_name_collisions)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
use core::hash::*;
#[cfg(feature = "alloc")]
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
#[derive(Debug)]
#[repr(transparent)]
pub struct Ointer<T: ?Sized, const A: u8, const S: bool, const V: u8> {
ptr: *mut T,
}
impl<T: ?Sized, 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: ?Sized, const A: u8, const S: bool, const V: u8> PartialEq<Self> for Ointer<T, A, S, V> {
#![allow(
ambiguous_wide_pointer_comparisons,
reason = "mirroring the behaviour of rust ptrs"
)]
fn eq(&self, other: &Self) -> bool {
self.ptr == other.ptr
}
}
impl<T: ?Sized, const A: u8, const S: bool, const V: u8> Eq for Ointer<T, A, S, V> {}
impl<T: ?Sized, const A: u8, const S: bool, const V: u8> Clone for Ointer<T, A, S, V> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized, const A: u8, const S: bool, const V: u8> Copy for Ointer<T, A, S, V> {}
impl<T: ?Sized, 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_provenance()
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct NotNull<T: ?Sized, const A: u8, const S: bool, const V: u8>(NonNull<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: ?Sized, const A: u8, const S: bool, const V: u8> PartialEq<Self> for NotNull<T, A, S, V> {
#![allow(
ambiguous_wide_pointer_comparisons,
reason = "mirroring the behaviour of NonNull<T>"
)]
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T: ?Sized, const A: u8, const S: bool, const V: u8> Eq for NotNull<T, A, S, V> {}
impl<T: ?Sized, 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);
NotNull(NonNull::new_unchecked(ptr))
}
pub unsafe fn new_stealing(ptr: NonNull<T>, bits: usize) -> Self {
let mask = asv_mask(A, S, V);
let ptr = ptr.as_ptr().map_addr(|addr| (bits & mask) | (addr & !mask));
NotNull(NonNull::new_unchecked(ptr))
}
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)) })
}
pub fn as_non_null(self) -> NonNull<T> {
unsafe { NonNull::new_unchecked(unpack(self.0.as_ptr(), A, S, V)) }
}
pub fn raw(self) -> usize {
self.0.as_ptr().expose_provenance()
}
}
#[derive(Debug)]
#[repr(transparent)]
#[cfg(feature = "alloc")]
pub struct Ox<T: ?Sized, const A: u8, const S: bool, const V: u8>(NotNull<T, A, S, V>);
#[cfg(feature = "alloc")]
impl<T: ?Sized, const A: u8, const S: bool, const V: u8> Clone for Ox<T, A, S, V>
where
Box<T>: Clone,
{
fn clone(&self) -> Self {
let old = core::mem::ManuallyDrop::new(unsafe { Box::from_raw(self.as_ptr()) });
let boxed = core::mem::ManuallyDrop::into_inner(old.clone());
unsafe { Ox::new_stealing(boxed, self.stolen()) }
}
}
#[cfg(feature = "alloc")]
impl<T: ?Sized, 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
}
}
#[cfg(feature = "alloc")]
impl<T: ?Sized, const A: u8, const S: bool, const V: u8> Eq for Ox<T, A, S, V> {}
#[cfg(feature = "alloc")]
impl<T: ?Sized, 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: ?Sized, 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);
Ox(NotNull::new(NonNull::new_unchecked(ptr)))
}
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.map_addr(|addr| (bits & mask) | (addr & !mask));
Self(NotNull::new(NonNull::new_unchecked(ptr)))
}
pub fn stolen(&self) -> usize {
self.0.stolen()
}
pub fn steal(&mut self, bits: usize) {
let mask = asv_mask(A, S, V);
let bits = bits & mask;
let ptr = self.as_ptr().map_addr(|addr| (addr & !mask) | bits);
self.0 = unsafe { NotNull::new(NonNull::new_unchecked(ptr)) };
}
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_non_null().as_ptr()
}
pub fn raw(&self) -> usize {
self.0.as_non_null().as_ptr().expose_provenance()
}
}
#[cfg(feature = "alloc")]
impl<T: ?Sized, 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_non_null().as_ref() }
}
}
#[cfg(feature = "alloc")]
impl<T: ?Sized, const A: u8, const S: bool, const V: u8> DerefMut for Ox<T, A, S, V> {
fn deref_mut(&mut self) -> &mut T {
unsafe { self.0.as_non_null().as_mut() }
}
}
#[cfg(feature = "alloc")]
impl<T: ?Sized, 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_non_null().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)]
{
if let Some(p) = ptr.as_ref() {
debug_assert!((1 << a) <= core::mem::align_of_val(p));
}
#[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
}
}