use std::alloc::Layout;
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::convert::{AsMut, AsRef};
use std::fmt::{Debug, Formatter, Pointer};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use crate::{RefCounter, UniquePointee};
pub struct UniquePointer<T: UniquePointee> {
mut_addr: usize,
mut_ptr: *mut T,
refs: RefCounter,
alloc: bool,
is_copy: bool,
written: bool,
}
impl<'c, T: UniquePointee + 'c> UniquePointer<T> {
pub fn null() -> UniquePointer<T> {
UniquePointer {
mut_addr: 0,
mut_ptr: std::ptr::null_mut::<T>(),
refs: RefCounter::new(),
written: false,
alloc: false,
is_copy: false,
}
}
pub fn from_ref(src: &T) -> UniquePointer<T> {
let mut up = UniquePointer::<T>::null();
up.write_ref(src);
up
}
pub fn from_ref_mut(src: &mut T) -> UniquePointer<T> {
let mut up = UniquePointer::<T>::null();
up.write_ref_mut(src);
up
}
fn copy() -> UniquePointer<T> {
let mut up = UniquePointer::<T>::null();
up.is_copy = true;
up
}
pub unsafe fn propagate(&self) -> UniquePointer<T> {
self.incr_ref();
let mut back_node = UniquePointer::<T>::null();
back_node.set_mut_ptr(self.mut_ptr, false);
back_node.refs = self.refs.clone();
back_node.alloc = self.alloc;
back_node.written = self.written;
back_node
}
pub fn read_only(data: &T) -> UniquePointer<T> {
UniquePointer::copy_from_ref(data, 1)
}
pub fn copy_from_ref(data: &T, refs: usize) -> UniquePointer<T> {
let ptr = (data as *const T).cast_mut();
UniquePointer::copy_from_mut_ptr(ptr, refs)
}
pub fn copy_from_mut_ptr(ptr: *mut T, refs: usize) -> UniquePointer<T> {
let addr = UniquePointer::provenance_of_mut_ptr(ptr);
let refs = RefCounter::from(refs);
UniquePointer {
mut_addr: addr,
mut_ptr: ptr,
refs: refs,
written: true,
alloc: true,
is_copy: true,
}
}
pub fn addr(&self) -> usize {
self.mut_addr
}
pub fn refs(&self) -> usize {
*self.refs
}
pub fn is_null(&self) -> bool {
let mut_is_null = self.mut_ptr.is_null();
if mut_is_null {
assert!(self.mut_addr == 0);
} else {
assert!(self.mut_addr != 0);
}
let is_null = mut_is_null;
is_null
}
pub fn is_not_null(&self) -> bool {
!self.is_null()
}
pub fn is_not_copy(&self) -> bool {
!self.is_copy
}
pub fn can_dealloc(&self) -> bool {
self.alloc && self.is_not_copy() && self.is_not_null()
}
pub fn is_allocated(&self) -> bool {
let is_allocated = self.is_not_null() && self.alloc;
is_allocated
}
pub fn is_written(&self) -> bool {
let is_written = self.is_allocated() && self.written;
is_written
}
pub fn is_copy(&self) -> bool {
self.is_copy
}
pub fn alloc(&mut self) {
if self.is_allocated() {
return;
}
let layout = Layout::new::<T>();
let mut_ptr = unsafe {
let ptr = std::alloc::alloc_zeroed(layout);
if ptr.is_null() {
std::alloc::handle_alloc_error(layout);
}
ptr as *mut T
};
self.set_mut_ptr(mut_ptr, false);
self.alloc = true;
}
pub fn cast_mut(&self) -> *mut T {
if self.is_null() {
panic!("{:#?}", self);
} else {
self.mut_ptr
}
}
pub fn cast_const(&self) -> *const T {
if self.is_null() {
panic!("{:#?}", self);
} else {
self.mut_ptr.cast_const()
}
}
pub fn write(&mut self, data: T) {
self.alloc();
unsafe {
self.mut_ptr.write(data);
}
self.written = true;
}
pub fn write_ref_mut(&mut self, data: &mut T) {
self.alloc();
unsafe {
let ptr = data as *mut T;
ptr.copy_to(self.mut_ptr, 1);
};
self.written = true;
}
pub fn write_ref(&mut self, data: &T) {
self.alloc();
unsafe {
let ptr = data as *const T;
ptr.copy_to(self.mut_ptr, 1);
};
self.written = true;
}
pub fn swap(&mut self, other: &mut Self) {
if self.is_null() && other.is_null() {
return;
}
if self.mut_ptr.is_null() {
self.alloc();
}
if other.mut_ptr.is_null() {
other.alloc();
}
unsafe {
self.mut_ptr.swap(other.mut_ptr);
}
}
pub fn read(&self) -> T {
if !self.is_written() {
panic!("{:#?} not written", self);
}
let ptr = self.cast_const();
unsafe { ptr.read() }
}
pub fn try_read(&self) -> Option<T> {
if self.is_written() {
Some(self.read())
} else {
None
}
}
pub fn inner_ref(&self) -> &'c T {
if self.mut_ptr.is_null() {
panic!("NULL POINTER: {:#?}", self);
}
unsafe { std::mem::transmute::<&T, &'c T>(&*self.cast_const()) }
}
pub fn inner_mut(&mut self) -> &'c mut T {
if self.mut_ptr.is_null() {
panic!("NULL POINTER: {:#?}", self);
}
unsafe { std::mem::transmute::<&mut T, &'c mut T>(&mut *self.mut_ptr) }
}
pub fn as_ref(&self) -> Option<&'c T> {
if self.is_written() {
Some(self.inner_ref())
} else {
None
}
}
pub fn as_mut(&mut self) -> Option<&'c mut T> {
if self.is_written() {
Some(self.inner_mut())
} else {
None
}
}
pub fn dealloc(&mut self, soft: bool) {
if self.is_null() {
return;
}
if soft && self.refs > 0 {
self.decr_ref();
} else {
self.free();
}
}
fn set_mut_ptr(&mut self, ptr: *mut T, dealloc: bool) {
if ptr.is_null() {
if dealloc && self.is_allocated() {
self.alloc = false;
self.written = false;
self.mut_addr = 0;
let layout = Layout::new::<T>();
unsafe {
std::alloc::dealloc(self.mut_ptr as *mut u8, layout);
};
self.mut_ptr = std::ptr::null_mut::<T>();
}
self.set_mut_addr(0);
} else {
self.set_mut_addr(UniquePointer::<T>::provenance_of_mut_ptr(ptr));
}
self.mut_ptr = ptr;
}
pub fn drop_in_place(&mut self) {
self.dealloc(true);
}
fn set_mut_addr(&mut self, addr: usize) {
self.mut_addr = addr;
}
fn free(&mut self) {
if !self.can_dealloc() {
return;
}
if !self.is_null() {
self.set_mut_ptr(std::ptr::null_mut::<T>(), false);
self.refs.drain();
}
self.alloc = false;
self.written = false;
}
pub fn extend_lifetime<'t>(&self) -> &'t T {
unsafe { std::mem::transmute::<&T, &'t T>(self.inner_ref()) }
}
pub fn extend_lifetime_mut<'t>(&mut self) -> &'t mut T {
unsafe { std::mem::transmute::<&mut T, &'t mut T>(self.inner_mut()) }
}
}
impl<T: UniquePointee> UniquePointer<T> {
pub fn provenance_of_const_ptr(ptr: *const T) -> usize {
ptr.expose_provenance()
}
pub fn provenance_of_mut_ptr(ptr: *mut T) -> usize {
ptr.expose_provenance()
}
pub fn provenance_of_ref(ptr: &T) -> usize {
(&raw const ptr).expose_provenance()
}
pub fn provenance_of_mut(mut ptr: &mut T) -> usize {
(&raw mut ptr).expose_provenance()
}
}
#[allow(unused)]
impl<'c, T: UniquePointee + 'c> UniquePointer<T> {
unsafe fn meta_mut(&'c self) -> &'c mut UniquePointer<T> {
unsafe {
let ptr = self.meta_mut_ptr();
let up = &mut *ptr;
std::mem::transmute::<&mut UniquePointer<T>, &'c mut UniquePointer<T>>(up)
}
}
unsafe fn meta_mut_ptr(&self) -> *mut UniquePointer<T> {
let ptr = self as *const UniquePointer<T>;
unsafe {
let ptr: *mut UniquePointer<T> =
std::mem::transmute::<*const UniquePointer<T>, *mut UniquePointer<T>>(ptr);
ptr
}
}
}
#[allow(invalid_reference_casting)]
impl<T: UniquePointee> UniquePointer<T> {
fn incr_ref(&self) {
if self.is_null() {
return;
}
unsafe {
let ptr = self.meta_mut_ptr();
let up = &mut *ptr;
up.refs.incr();
}
}
fn decr_ref(&self) {
if self.refs == 0 {
return;
}
unsafe {
let ptr = self.meta_mut_ptr();
let up = &mut *ptr;
up.refs.decr();
}
}
}
impl<T: UniquePointee> AsRef<T> for UniquePointer<T> {
fn as_ref(&self) -> &T {
if self.is_null() {
panic!("null pointer: {:#?}", self);
}
self.inner_ref()
}
}
impl<T: UniquePointee> AsMut<T> for UniquePointer<T> {
fn as_mut(&mut self) -> &mut T {
if self.is_null() {
panic!("null pointer: {:#?}", self);
}
self.inner_mut()
}
}
impl<T: UniquePointee> Deref for UniquePointer<T> {
type Target = T;
fn deref(&self) -> &T {
self.inner_ref()
}
}
impl<T: UniquePointee> DerefMut for UniquePointer<T> {
fn deref_mut(&mut self) -> &mut T {
self.inner_mut()
}
}
impl<T: UniquePointee> Drop for UniquePointer<T>
where
T: Debug,
{
fn drop(&mut self) {
self.drop_in_place();
}
}
impl<T: UniquePointee> From<&T> for UniquePointer<T>
where
T: Debug,
{
fn from(data: &T) -> UniquePointer<T> {
UniquePointer::<T>::from_ref(data)
}
}
impl<T: UniquePointee> From<&mut T> for UniquePointer<T>
where
T: Debug,
{
fn from(data: &mut T) -> UniquePointer<T> {
UniquePointer::<T>::from_ref_mut(data)
}
}
impl<T: UniquePointee> From<T> for UniquePointer<T>
where
T: Debug,
{
fn from(data: T) -> UniquePointer<T> {
UniquePointer::from_ref(&data)
}
}
impl<T: UniquePointee> Clone for UniquePointer<T>
where
T: Debug,
{
fn clone(&self) -> UniquePointer<T> {
self.incr_ref();
let mut clone = UniquePointer::<T>::copy();
clone.set_mut_ptr(self.mut_ptr, false);
clone.refs = self.refs.clone();
clone.alloc = self.alloc;
clone.written = self.written;
clone
}
}
impl<T: UniquePointee> Pointer for UniquePointer<T>
where
T: Debug,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "{:016x}", self.addr())
}
}
impl<T: UniquePointee> Debug for UniquePointer<T>
where
T: Debug,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(
f,
"UniquePointer{}",
[
format!("{:016x}", self.addr()),
if self.is_not_null() {
[
format!("[src={:#?}]", self.inner_ref()),
format!("[refs={}]", self.refs),
]
.join("")
} else {
[
format!("[refs={}]", self.refs),
format!("[alloc={}]", self.alloc),
format!("[written={}]", self.written),
]
.join("")
},
format!("[is_copy={}]", self.is_copy),
]
.join("")
)
}
}
impl<T: UniquePointee + PartialEq> PartialEq<UniquePointer<T>> for UniquePointer<T> {
fn eq(&self, fles: &UniquePointer<T>) -> bool {
if self.addr() == fles.addr() {
return true;
}
if self.is_null() {
let eq = fles.is_null();
return eq;
}
self.inner_ref().eq(fles.inner_ref())
}
}
impl<T: UniquePointee + Eq> Eq for UniquePointer<T> {}
impl<T: UniquePointee + PartialOrd> PartialOrd<UniquePointer<T>> for UniquePointer<T> {
fn partial_cmp(&self, other: &UniquePointer<T>) -> Option<Ordering> {
if self.is_null() {
return None;
}
if self.addr() == other.addr() {
return Some(Ordering::Equal);
}
self.inner_ref().partial_cmp(other.inner_ref())
}
}
impl<T: UniquePointee + PartialOrd> PartialOrd<T> for UniquePointer<T> {
fn partial_cmp(&self, other: &T) -> Option<Ordering> {
if self.is_null() {
return None;
}
self.inner_ref().partial_cmp(other)
}
}
impl<T: UniquePointee + PartialEq> PartialEq<T> for UniquePointer<T> {
fn eq(&self, other: &T) -> bool {
if self.is_null() {
return false;
}
self.inner_ref().eq(other)
}
}
impl<T: UniquePointee + Ord> Ord for UniquePointer<T> {
fn cmp(&self, other: &Self) -> Ordering {
if self.is_null() {
return Ordering::Less;
}
self.inner_ref().cmp(other.inner_ref())
}
}
impl<T: UniquePointee + Hash> Hash for UniquePointer<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner_ref().hash(state)
}
}