wrc 0.4.2

A thread-safe weighted reference counting smart-pointer for Rust.
Documentation
use crate::weight::Weight;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::sync::atomic;

// The WRC `Inner` value uses `AtomicUsize` to store the total weight value,
// meaning that mutations of the weight are thread-safe.
pub struct Inner<T: ?Sized> {
    weight: atomic::AtomicUsize,
    data: T,
}

impl<T> Inner<T> {
    #[inline]
    pub fn new(data: T, starting_weight: usize) -> Inner<T> {
        Inner {
            weight: atomic::AtomicUsize::new(starting_weight),
            data,
        }
    }
}

unsafe impl<T: ?Sized + Sync + Send> Send for Inner<T> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for Inner<T> {}

impl<T: ?Sized> Weight for Inner<T> {
    fn add_weight(&self, weight: usize) -> Option<usize> {
        let existing_weight = self.weight.load(atomic::Ordering::Acquire);
        let new_weight = existing_weight.checked_add(weight);
        match new_weight {
            Some(weight) => {
                self.weight.store(weight, atomic::Ordering::Release);
                Some(weight)
            }
            None => None,
        }
    }

    fn drop_weight(&self, weight: usize) -> Option<usize> {
        let existing_weight = self.weight.load(atomic::Ordering::Acquire);
        let new_weight = existing_weight.checked_sub(weight);
        match new_weight {
            Some(weight) => {
                self.weight.store(weight, atomic::Ordering::Release);
                Some(weight)
            }
            None => None,
        }
    }

    fn get_weight(&self) -> usize {
        self.weight.load(atomic::Ordering::Relaxed)
    }
}

impl<T> Deref for Inner<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        &self.data
    }
}

impl<T> DerefMut for Inner<T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        &mut self.data
    }
}

impl<T> fmt::Display for Inner<T>
where
    T: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.data, f)
    }
}

impl<T> fmt::Debug for Inner<T>
where
    T: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.data, f)
    }
}

impl<T: ?Sized + PartialEq> PartialEq for Inner<T> {
    fn eq(&self, other: &Inner<T>) -> bool {
        self.data == other.data
    }
}

impl<T: PartialOrd> PartialOrd for Inner<T> {
    fn partial_cmp(&self, other: &Inner<T>) -> Option<Ordering> {
        self.data.partial_cmp(&other.data)
    }

    fn lt(&self, other: &Inner<T>) -> bool {
        self.data < other.data
    }

    fn le(&self, other: &Inner<T>) -> bool {
        self.data <= other.data
    }

    fn gt(&self, other: &Inner<T>) -> bool {
        self.data > other.data
    }

    fn ge(&self, other: &Inner<T>) -> bool {
        self.data >= other.data
    }
}

impl<T: Ord> Ord for Inner<T> {
    fn cmp(&self, other: &Inner<T>) -> Ordering {
        self.data.cmp(&other.data)
    }
}

impl<T: Eq> Eq for Inner<T> {}

impl<T: Hash> Hash for Inner<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.data.hash(state)
    }
}