blob: b96a217c6237698b0fb4d19654615e93ac4e5094 [file] [log] [blame]
use std::ptr;
use std::rc::Rc;
use std::sync::Arc;
/// A trait describing smart reference counted pointers.
///
/// Note that in a way [`Option<Arc<T>>`][Option] is also a smart reference counted pointer, just
/// one that can hold NULL.
///
/// The trait is unsafe, because a wrong implementation will break the [ArcSwapAny]
/// implementation and lead to UB.
///
/// This is not actually expected for downstream crate to implement, this is just means to reuse
/// code for [Arc] and [`Option<Arc>`][Option] variants. However, it is theoretically possible (if
/// you have your own [Arc] implementation).
///
/// It is also implemented for [Rc], but that is not considered very useful (because the
/// [ArcSwapAny] is not `Send` or `Sync`, therefore there's very little advantage for it to be
/// atomic).
///
/// # Safety
///
/// Aside from the obvious properties (like that incrementing and decrementing a reference count
/// cancel each out and that having less references tracked than how many things actually point to
/// the value is fine as long as the count doesn't drop to 0), it also must satisfy that if two
/// pointers have the same value, they point to the same object. This is specifically not true for
/// ZSTs, but it is true for `Arc`s of ZSTs, because they have the reference counts just after the
/// value. It would be fine to point to a type-erased version of the same object, though (if one
/// could use this trait with unsized types in the first place).
///
/// Furthermore, the type should be Pin (eg. if the type is cloned or moved, it should still
/// point/deref to the same place in memory).
///
/// [Arc]: std::sync::Arc
/// [Rc]: std::rc::Rc
/// [ArcSwapAny]: ::ArcSwapAny
pub unsafe trait RefCnt: Clone {
/// The base type the pointer points to.
type Base;
/// Converts the smart pointer into a raw pointer, without affecting the reference count.
///
/// This can be seen as kind of freezing the pointer ‒ it'll be later converted back using
/// [`from_ptr`](#method.from_ptr).
///
/// The pointer must point to the value stored (and the value must be the same as one returned
/// by [`as_ptr`](#method.as_ptr).
fn into_ptr(me: Self) -> *mut Self::Base;
/// Provides a view into the smart pointer as a raw pointer.
///
/// This must not affect the reference count ‒ the pointer is only borrowed.
fn as_ptr(me: &Self) -> *mut Self::Base;
/// Converts a raw pointer back into the smart pointer, without affecting the reference count.
///
/// This is only called on values previously returned by [`into_ptr`](#method.into_ptr).
/// However, it is not guaranteed to be 1:1 relation ‒ `from_ptr` may be called more times than
/// `into_ptr` temporarily provided the reference count never drops under 1 during that time
/// (the implementation sometimes owes a reference). These extra pointers will either be
/// converted back using `into_ptr` or forgotten.
///
/// # Safety
///
/// This must not be called by code outside of this crate.
unsafe fn from_ptr(ptr: *const Self::Base) -> Self;
/// Increments the reference count by one.
fn inc(me: &Self) {
Self::into_ptr(Self::clone(me));
}
/// Decrements the reference count by one.
///
/// Note this is called on a raw pointer (one previously returned by
/// [`into_ptr`](#method.into_ptr). This may lead to dropping of the reference count to 0 and
/// destruction of the internal pointer.
///
/// # Safety
///
/// This must not be called by code outside of this crate.
unsafe fn dec(ptr: *const Self::Base) {
drop(Self::from_ptr(ptr));
}
}
unsafe impl<T> RefCnt for Arc<T> {
type Base = T;
fn into_ptr(me: Arc<T>) -> *mut T {
Arc::into_raw(me) as *mut T
}
fn as_ptr(me: &Arc<T>) -> *mut T {
me as &T as *const T as *mut T
}
unsafe fn from_ptr(ptr: *const T) -> Arc<T> {
Arc::from_raw(ptr)
}
}
unsafe impl<T> RefCnt for Rc<T> {
type Base = T;
fn into_ptr(me: Rc<T>) -> *mut T {
Rc::into_raw(me) as *mut T
}
fn as_ptr(me: &Rc<T>) -> *mut T {
me as &T as *const T as *mut T
}
unsafe fn from_ptr(ptr: *const T) -> Rc<T> {
Rc::from_raw(ptr)
}
}
unsafe impl<T: RefCnt> RefCnt for Option<T> {
type Base = T::Base;
fn into_ptr(me: Option<T>) -> *mut T::Base {
me.map(T::into_ptr).unwrap_or_else(ptr::null_mut)
}
fn as_ptr(me: &Option<T>) -> *mut T::Base {
me.as_ref().map(T::as_ptr).unwrap_or_else(ptr::null_mut)
}
unsafe fn from_ptr(ptr: *const T::Base) -> Option<T> {
if ptr.is_null() {
None
} else {
Some(T::from_ptr(ptr))
}
}
}