roc/crates/roc_std/src/storage.rs
2022-08-06 19:05:29 +02:00

66 lines
1.9 KiB
Rust

use core::num::NonZeroIsize;
/// # Safety
///
/// isize::MIN is definitely not zero. This can become
/// https://doc.rust-lang.org/std/num/struct.NonZeroIsize.html#associatedconstant.MIN
/// once it has been stabilized.
const REFCOUNT_1: NonZeroIsize = unsafe { NonZeroIsize::new_unchecked(isize::MIN) };
const _ASSERT_STORAGE_SIZE: () =
assert!(core::mem::size_of::<isize>() == core::mem::size_of::<Storage>());
#[derive(Clone, Copy, Debug)]
pub enum Storage {
Readonly,
ReferenceCounted(NonZeroIsize),
}
impl Storage {
pub fn new_reference_counted() -> Self {
Self::ReferenceCounted(REFCOUNT_1)
}
/// Increment the reference count.
pub fn increment_reference_count(&mut self) {
match self {
Storage::Readonly => {
// Do nothing.
}
Storage::ReferenceCounted(rc) => {
let new_rc = rc.get() + 1;
if let Some(new_rc) = NonZeroIsize::new(new_rc) {
*self = Storage::ReferenceCounted(new_rc);
} else {
*self = Storage::Readonly;
}
}
}
}
/// Decrease the reference count.
///
/// Returns `true` once there are no more references left.
pub fn decrease(&mut self) -> bool {
match self {
Storage::Readonly => false,
Storage::ReferenceCounted(rc) => {
if *rc == REFCOUNT_1 {
true
} else {
*rc = NonZeroIsize::new(rc.get() - 1).expect("A reference count was decremented all the way to zero, which should never happen.");
false
}
}
}
}
pub fn is_readonly(&self) -> bool {
matches!(self, Self::Readonly)
}
pub fn is_unique(&self) -> bool {
matches!(self, Self::ReferenceCounted(REFCOUNT_1))
}
}