use crate::inner::Inner;
use crate::weight::Weight;
use std::cell::Cell;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
const DEFAULT_WEIGHT: usize = 1 << 16;
pub struct WRC<T: ?Sized> {
weight: Cell<usize>,
ptr: NonNull<Inner<T>>,
}
impl<T> WRC<T> {
#[inline]
pub fn new(data: T) -> WRC<T> {
let ptr = Box::new(Inner::new(data, DEFAULT_WEIGHT));
WRC {
weight: Cell::new(DEFAULT_WEIGHT),
ptr: NonNull::new(Box::into_raw(ptr)).unwrap(),
}
}
pub fn total_weight(wrc: &WRC<T>) -> usize {
wrc.inner().get_weight()
}
#[inline]
fn inner(&self) -> &Inner<T> {
unsafe { self.ptr.as_ref() }
}
#[inline]
pub fn clone(wrc: &WRC<T>) -> WRC<T> {
let existing_weight = wrc.get_weight();
if existing_weight > 1 {
let new_weight = existing_weight >> 1;
wrc.drop_weight(new_weight);
WRC {
weight: Cell::new(new_weight),
ptr: wrc.ptr,
}
} else {
let ptr = wrc.inner();
ptr.add_weight(DEFAULT_WEIGHT)
.unwrap_or_else(|| panic!("Unable to add {:?} to WRC", existing_weight));
WRC {
weight: Cell::new(DEFAULT_WEIGHT),
ptr: wrc.ptr,
}
}
}
}
unsafe impl<T: ?Sized + Sync + Send> Send for WRC<T> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for WRC<T> {}
impl<T: ?Sized> Weight for WRC<T> {
fn add_weight(&self, weight: usize) -> Option<usize> {
let existing_weight = self.weight.get();
let new_weight = existing_weight.checked_add(weight);
match new_weight {
Some(weight) => {
self.weight.set(weight);
Some(weight)
}
None => None,
}
}
fn drop_weight(&self, weight: usize) -> Option<usize> {
let existing_weight = self.weight.get();
let new_weight = existing_weight.checked_sub(weight);
match new_weight {
Some(weight) => {
self.weight.set(weight);
Some(weight)
}
None => None,
}
}
fn get_weight(&self) -> usize {
self.weight.get()
}
}
impl<T> Clone for WRC<T> {
fn clone(&self) -> Self {
WRC::clone(self)
}
}
impl<T: ?Sized> Drop for WRC<T> {
fn drop(&mut self) {
let ptr = unsafe { self.ptr.as_ref() };
let existing_weight = self.get_weight();
let new_weight = ptr
.drop_weight(existing_weight)
.unwrap_or_else(|| panic!("Unable to drop {:?} from to WRC", existing_weight));
if new_weight > 0 {
return;
}
let ptr = self.ptr.as_ptr();
let data = unsafe { Box::from_raw(ptr) };
drop(data);
}
}
impl<T> Deref for WRC<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.inner().deref()
}
}
impl<T> DerefMut for WRC<T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { self.ptr.as_mut() }.deref_mut()
}
}
impl<T: fmt::Display> fmt::Display for WRC<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self.inner(), f)
}
}
impl<T: fmt::Debug> fmt::Debug for WRC<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self.inner(), f)
}
}
impl<T: PartialEq> PartialEq for WRC<T> {
fn eq(&self, other: &WRC<T>) -> bool {
self.inner() == other.inner()
}
}
impl<T: PartialOrd> PartialOrd for WRC<T> {
fn partial_cmp(&self, other: &WRC<T>) -> Option<Ordering> {
self.inner().partial_cmp(other.inner())
}
fn lt(&self, other: &WRC<T>) -> bool {
self.inner() < other.inner()
}
fn le(&self, other: &WRC<T>) -> bool {
self.inner() <= other.inner()
}
fn gt(&self, other: &WRC<T>) -> bool {
self.inner() > other.inner()
}
fn ge(&self, other: &WRC<T>) -> bool {
self.inner() >= other.inner()
}
}
impl<T: Ord> Ord for WRC<T> {
fn cmp(&self, other: &WRC<T>) -> Ordering {
self.inner().cmp(other.inner())
}
}
impl<T: Eq> Eq for WRC<T> {}
impl<T: Default> Default for WRC<T> {
fn default() -> WRC<T> {
WRC::new(Default::default())
}
}
impl<T: Hash> Hash for WRC<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().hash(state)
}
}