wildbird 0.0.11

Rust Framework 🐦
Documentation
use crate::inject::InjectStack;
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::Deref;
use std::panic::Location;
use std::sync::{Arc, OnceLock};

#[doc(hidden)]
pub struct Lazy<T> {
    instance: OnceLock<Arc<T>>,
    init: fn() -> T,
    id: (&'static str, u32),
}

impl<T> Deref for Lazy<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self._get().as_ref()
    }
}

impl<T: Display> Display for Lazy<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        if let Some(inner) = self._get_opt() {
            return Display::fmt(inner, f);
        };
        Display::fmt("(Not initialized)", f)
    }
}

impl<T: Debug> Debug for Lazy<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        if let Some(inner) = self._get_opt() {
            return Debug::fmt(inner, f);
        };
        Debug::fmt("(Not initialized) - use to_ref()", f)
    }
}

impl<T> Lazy<T> {
    #[track_caller]
    pub const fn new(init: fn() -> T) -> Lazy<T> {
        let caller = Location::caller();
        let file = caller.file();
        let line = caller.line();

        Self {
            instance: OnceLock::new(),
            init,
            id: (file, line),
        }
    }

    fn _get(&self) -> &Arc<T> {
        match self._get_opt() {
            Some(instance) => instance,
            None => {
                let id = self.id();
                if InjectStack::has_id(&id) {
                    panic!("{}", InjectStack::cilcuar_error(id))
                }
                InjectStack::push_id(id.clone());
                let instance = self.instance.get_or_init(|| Arc::new((self.init)()));
                InjectStack::remove(&id);
                instance
            }
        }
    }

    fn id(&self) -> String {
        format!("{}:{}", self.id.0, self.id.1)
    }

    fn _get_opt(&self) -> Option<&Arc<T>> {
        self.instance.get()
    }

    pub fn clone_lazy(&self) -> Self {
        let instance = self.instance();
        Self {
            instance: OnceLock::from(instance),
            init: self.init.clone(),
            id: self.id.clone(),
        }
    }

    pub fn instance(&self) -> Arc<T> {
        self._get().clone()
    }

    pub fn to_ref(&self) -> &T {
        self._get().as_ref()
    }
}