junkdrawer 0.1.0

A crate for all kinds of utilities.
Documentation
use std::sync::{Arc, RwLock, Weak};

/// An alternative to [`std::sync::LazyLock`] that only keeps data alive for as long as it it needed.
///
/// While [`std::sync::LazyLock`] is fine in most situations it does have some drawbacks:
/// - The lifetime of references is tied to self.
/// - As long as the (initialized) `LazyLock` is alive the data is alive.
///   If you have a static `LazyLock` this means data is never dropped.
///
/// [`LazyReLock`] tries to resolve this, by (potentially) initializing the data multiple times, but also dropping it, when it is not needed.
/// When you get the value from a [`LazyReLock`], you get an [`std::sync::Arc`] and the `LazyReLock` gets a corresponding [`std::sync::Weak`].
/// If the element is requested again, then it checks if the `Weak` can be upgraded. If the Arc was deallocated, then a new value is created, otherwise the old value is returned.
///
/// This requires the function to be callable multiple times, however, as such [`std::ops::FnOnce`] is no longer valid.
///
///
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
            }
        }
    }

    /// Forces a new value to be calculated, even if the existing one still exists
    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
    }

    /// Creates an empty [`Weak`] to replace the currently remembered weak.
    ///
    /// This forces the execution of the function. This will also clear any poison on the inner state.
    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();
            }
        }
    }

    /// Gets the value from the [`LazyReLock`] but only if it is still remembered.
    ///
    /// If the value was deallocated, then nothing will be returned and the function will not be executed.
    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()))
    }
}