use std::sync::{Arc, RwLock, Weak};
pub struct LazyReLock<F, T> where F: Fn() -> T {
func: F,
data: RwLock<Weak<T>>
}
impl<F, T> LazyReLock<F, T> where F: Fn() -> T {
#[must_use = "An unused LazyReLock is just a wasteful container for a function"]
pub fn new(func: F) -> Self {
Self {
func,
data: RwLock::new(Weak::new())
}
}
pub fn get(&self) -> Arc<T> {
match self.data.write() {
Ok(mut guard) => {
let weak = &mut *guard;
weak.upgrade().map_or_else(
|| {
let arc = Arc::new((self.func)());
*weak = Arc::downgrade(&arc);
arc
},
|graph| graph,
)
}
Err(mut e) => {
let arc = Arc::new((self.func)());
self.data.clear_poison();
**e.get_mut() = Arc::downgrade(&arc);
arc
}
}
}
pub fn force_new(self) -> Arc<T> {
let arc = Arc::new((self.func)());
let weak = Arc::downgrade(&arc);
match self.data.write() {
Ok(mut guard) => {
*guard = weak;
}
Err(mut e) => {
self.data.clear_poison();
**e.get_mut() = weak;
}
}
arc
}
pub fn forget(&self) {
match self.data.write() {
Ok(mut guard) => {
*guard = Weak::new();
},
Err(mut e) => {
self.data.clear_poison();
**e.get_mut() = Weak::new();
}
}
}
pub fn get_if_present(self) -> Option<Arc<T>> {
self.data.read().ok().and_then(|guard| guard.upgrade())
}
pub fn get_function(&self) -> &F {
&self.func
}
pub fn into_inner(self) -> (F, Weak<T>) {
(self.func, self.data.into_inner().unwrap_or_else(|_| Weak::new()))
}
}