1pub use self::imp::{Cached, CachedGuard};
12
13#[cfg(feature = "perf-cache")]
14mod imp {
15 use thread_local::CachedThreadLocal;
16
17 #[derive(Debug)]
18 pub struct Cached<T: Send>(CachedThreadLocal<T>);
19
20 #[derive(Debug)]
21 pub struct CachedGuard<'a, T: 'a>(&'a T);
22
23 impl<T: Send> Cached<T> {
24 pub fn new() -> Cached<T> {
25 Cached(CachedThreadLocal::new())
26 }
27
28 pub fn get_or(&self, create: impl FnOnce() -> T) -> CachedGuard<T> {
29 CachedGuard(self.0.get_or(|| Box::new(create())))
30 }
31 }
32
33 impl<'a, T: Send> CachedGuard<'a, T> {
34 pub fn value(&self) -> &T {
35 self.0
36 }
37 }
38}
39
40#[cfg(not(feature = "perf-cache"))]
41mod imp {
42 use std::marker::PhantomData;
43 use std::panic::UnwindSafe;
44 use std::sync::Mutex;
45
46 #[derive(Debug)]
47 pub struct Cached<T: Send> {
48 stack: Mutex<Vec<T>>,
49 _phantom: PhantomData<Box<dyn Send + Sync + UnwindSafe>>,
60 }
61
62 #[derive(Debug)]
63 pub struct CachedGuard<'a, T: 'a + Send> {
64 cache: &'a Cached<T>,
65 value: Option<T>,
66 }
67
68 impl<T: Send> Cached<T> {
69 pub fn new() -> Cached<T> {
70 Cached { stack: Mutex::new(vec![]), _phantom: PhantomData }
71 }
72
73 pub fn get_or(&self, create: impl FnOnce() -> T) -> CachedGuard<T> {
74 let mut stack = self.stack.lock().unwrap();
75 match stack.pop() {
76 None => CachedGuard { cache: self, value: Some(create()) },
77 Some(value) => CachedGuard { cache: self, value: Some(value) },
78 }
79 }
80
81 fn put(&self, value: T) {
82 let mut stack = self.stack.lock().unwrap();
83 stack.push(value);
84 }
85 }
86
87 impl<'a, T: Send> CachedGuard<'a, T> {
88 pub fn value(&self) -> &T {
89 self.value.as_ref().unwrap()
90 }
91 }
92
93 impl<'a, T: Send> Drop for CachedGuard<'a, T> {
94 fn drop(&mut self) {
95 if let Some(value) = self.value.take() {
96 self.cache.put(value);
97 }
98 }
99 }
100}