use core::sync::atomic;
use std::sync::atomic::Ordering::{Relaxed, Release};
use std::sync::atomic::{AtomicUsize, Ordering};
pub trait RcCounter {
fn new() -> Self;
fn decrement(&mut self) -> RcDecResult;
fn increment(&mut self);
}
#[derive(Copy, Clone)]
pub enum RcDecResult {
Zero,
More,
}
#[repr(transparent)]
pub struct NsRcCounter(usize);
const FINISHED_MARKER: usize = usize::MAX;
impl RcCounter for NsRcCounter {
#[inline]
fn new() -> Self {
Self(0)
}
#[inline]
fn decrement(&mut self) -> RcDecResult {
let current = self.0;
if current == 0 {
self.0 = FINISHED_MARKER;
RcDecResult::Zero
} else if current == FINISHED_MARKER {
panic!("Some implementation error. Reference counter has invalid state.")
} else {
self.0 = current - 1;
RcDecResult::More
}
}
#[inline]
fn increment(&mut self) {
let current = self.0;
if current == FINISHED_MARKER {
panic!(
"Too many reference counts or implementation error (reference counter has \
invalid state)."
)
}
self.0 = current + 1;
}
}
#[repr(transparent)]
pub struct SyncRcCounter(AtomicUsize);
impl RcCounter for SyncRcCounter {
#[inline]
fn new() -> Self {
Self(AtomicUsize::new(0))
}
#[inline]
fn decrement(&mut self) -> RcDecResult {
let previous_value = self.0.fetch_sub(1, Release);
if previous_value == 0 {
atomic::fence(Ordering::Acquire);
RcDecResult::Zero
} else {
RcDecResult::More
}
}
#[inline]
fn increment(&mut self) {
let previous_value = self.0.fetch_add(1, Relaxed);
if previous_value == core::usize::MAX {
self.0.fetch_sub(1, Release);
panic!("Too many reference counts or implementation error (too many rc decrements).")
}
}
}