use crate::{ err::ConfigLock, macros::cfg_log, source::{memory::HashSource, ConfigSource, ConfigSourceBuilder}, ConfigError, Mutex, }; #[macro_export] #[doc(hidden)] macro_rules! impl_cache { ($x:ident) => { thread_local! { static BUF: RefCell<$x> = RefCell::new($x::new()); } impl $x { #[inline] #[allow(dead_code)] pub(crate) fn with_key Result>( f: F, ) -> Result { BUF.with(move |buf| Self::with_key_buf(buf, f)) } #[allow(dead_code)] fn with_key_buf Result>( buf: &RefCell<$x>, mut f: F, ) -> Result { let borrow = buf.try_borrow_mut(); let mut a; let mut b; let buf = match borrow { Ok(buf) => { a = buf; &mut *a } _ => { b = $x::new(); &mut b } }; (f)(buf) } } }; } /// Cacheable source. pub(crate) struct CacheConfigSource { cache: Mutex<(Option, bool)>, origin: L, } impl CacheConfigSource { pub(crate) fn new(origin: L) -> Self { Self { cache: Mutex::new((None, false)), origin, } } } impl ConfigSource for CacheConfigSource { fn name(&self) -> &str { self.origin.name() } fn load(&self, builder: &mut ConfigSourceBuilder<'_>) -> Result<(), ConfigError> { let mut g = self.cache.lock_c()?; let _c = builder.count(); if g.1 || g.0.is_none() { let mut source = HashSource::new(format!("cache:{}", self.origin.name())); self.origin.load(&mut source.prefixed())?; *g = (Some(source), false); } let v = g.0.as_ref().expect("NP").load(builder); cfg_log!( builder.count() > _c => log::Level::Info, "Config source {} loaded.", self.name() ); v } fn allow_refresh(&self) -> bool { self.origin.allow_refresh() } fn refreshable(&self) -> Result { if !self.allow_refresh() { return Ok(false); } let flag = self.origin.refreshable()?; self.cache.lock_c()?.1 = flag; Ok(flag) } }