froodi 1.0.0-beta.18

An ergonomic Rust IoC container
Documentation
#![allow(dead_code)]

use alloc::collections::BTreeMap;
use core::any::TypeId;
use parking_lot::{Mutex, RwLock};

use crate::utils::thread_safety::RcThreadSafety;

#[derive(Clone)]
pub(crate) struct PerTypeLocks {
    locks: RcThreadSafety<RwLock<BTreeMap<TypeId, RcThreadSafety<Mutex<()>>>>>,
}

impl PerTypeLocks {
    #[inline]
    #[must_use]
    fn new() -> Self {
        Self {
            locks: RcThreadSafety::new(RwLock::new(BTreeMap::new())),
        }
    }
}

impl PerTypeLocks {
    #[inline]
    #[must_use]
    pub(crate) fn get(&self, type_id: TypeId) -> RcThreadSafety<Mutex<()>> {
        if let Some(lock) = self.locks.read().get(&type_id) {
            return lock.clone();
        }

        self.locks
            .write()
            .entry(type_id)
            .or_insert_with(|| RcThreadSafety::new(Mutex::new(())))
            .clone()
    }

    #[inline]
    pub(crate) fn cleanup_unused(&self) {
        self.locks.write().retain(|_, lock| RcThreadSafety::strong_count(lock) > 1);
    }
}

impl Default for PerTypeLocks {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(feature = "async")]
mod async_impl {
    use tokio::sync::Mutex;

    use super::{BTreeMap, RcThreadSafety, RwLock, TypeId};

    #[derive(Clone)]
    pub(crate) struct PerTypeSharedLocks {
        locks: RcThreadSafety<RwLock<BTreeMap<TypeId, RcThreadSafety<Mutex<()>>>>>,
    }

    impl PerTypeSharedLocks {
        #[inline]
        #[must_use]
        fn new() -> Self {
            Self {
                locks: RcThreadSafety::new(RwLock::new(BTreeMap::new())),
            }
        }
    }

    impl PerTypeSharedLocks {
        #[inline]
        #[must_use]
        pub(crate) fn get(&self, type_id: TypeId) -> RcThreadSafety<Mutex<()>> {
            if let Some(lock) = self.locks.read().get(&type_id) {
                return lock.clone();
            }

            self.locks
                .write()
                .entry(type_id)
                .or_insert_with(|| RcThreadSafety::new(Mutex::new(())))
                .clone()
        }

        #[inline]
        pub(crate) fn cleanup_unused(&self) {
            self.locks.write().retain(|_, lock| RcThreadSafety::strong_count(lock) > 1);
        }
    }

    impl Default for PerTypeSharedLocks {
        #[inline]
        fn default() -> Self {
            Self::new()
        }
    }
}

#[cfg(feature = "async")]
pub(crate) use async_impl::PerTypeSharedLocks;