#![doc = include_str!("../README.md")]
#![doc(html_root_url = "https://docs.rs/reference-counted-singleton/0.1.5")]
#![warn(unsafe_op_in_unsafe_fn)]
#[cfg(test)]
mod tests;
use std::error::Error;
use std::hash::{Hash, Hasher};
use std::mem::ManuallyDrop;
use std::ops::Deref;
use std::sync::{Arc, Mutex};
#[derive(Debug)]
pub struct RefCountedSingleton<T>(Mutex<Option<Arc<T>>>);
impl<T> Default for RefCountedSingleton<T> {
fn default() -> Self {
Self(Mutex::new(None))
}
}
impl<T> RefCountedSingleton<T> {
pub fn get_or_init<E: Error>(
&'_ self,
creator: impl FnOnce() -> Result<T, E>,
) -> Result<RCSRef<'_, T>, Option<E>> {
if let Ok(mut value) = self.0.lock() {
match *value {
None => match creator() {
Ok(data) => {
let data = Arc::new(data);
let data_ref = Arc::clone(&data);
*value = Some(data);
Ok(RCSRef {
data: ManuallyDrop::new(data_ref),
rcs: self,
})
}
Err(err) => Err(Some(err)),
},
Some(ref data) => Ok(RCSRef {
data: ManuallyDrop::new(Arc::clone(data)),
rcs: self,
}),
}
} else {
Err(None) }
}
pub fn get(&'_ self) -> Option<RCSRef<'_, T>> {
self.0.lock().ok().and_then(|value| {
value.as_ref().map(|data| RCSRef {
data: ManuallyDrop::new(Arc::clone(data)),
rcs: self,
})
})
}
}
#[derive(Debug)]
pub struct RCSRef<'t, T> {
data: ManuallyDrop<Arc<T>>,
rcs: &'t RefCountedSingleton<T>,
}
impl<'t, T: PartialEq> PartialEq for RCSRef<'t, T> {
fn eq(&self, other: &Self) -> bool {
Arc::as_ref(&self.data).eq(Arc::as_ref(&other.data))
}
}
impl<'t, T: Eq> Eq for RCSRef<'t, T> {}
impl<'t, T: PartialOrd> PartialOrd for RCSRef<'t, T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Arc::as_ref(&self.data).partial_cmp(Arc::as_ref(&other.data))
}
}
impl<'t, T: Ord> Ord for RCSRef<'t, T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
Arc::as_ref(&self.data).cmp(Arc::as_ref(&other.data))
}
}
impl<'t, T: Hash> Hash for RCSRef<'t, T> {
fn hash<H: Hasher>(&self, state: &mut H) {
Arc::as_ref(&self.data).hash(state)
}
}
impl<'t, T> Deref for RCSRef<'t, T> {
type Target = T;
fn deref(&self) -> &T {
Arc::as_ref(&self.data)
}
}
impl<'t, T> Clone for RCSRef<'t, T> {
fn clone(&self) -> Self {
Self {
data: ManuallyDrop::new(Arc::clone(&self.data)),
rcs: self.rcs,
}
}
}
impl<'t, T> Drop for RCSRef<'t, T> {
fn drop(&mut self) {
unsafe { ManuallyDrop::drop(&mut self.data) };
if let Ok(mut value) = self.rcs.0.lock() {
if let Some(data) = value.take() {
match Arc::try_unwrap(data) {
Ok(data) => drop(data),
Err(data) => *value = Some(data),
}
}
}
}
}