rs_utilities/
cached_value.rs1use anyhow::Result;
2use std::time::{Duration, Instant};
3
4pub struct CachedValue<T, E, F>
5where
6 F: Fn() -> Result<T, E>,
7{
8 value: Option<T>,
9 fetched_at: Option<Instant>,
10 ttl: Duration,
11 fetcher: F,
12}
13
14impl<T: Clone, E, F: Fn() -> Result<T, E>> CachedValue<T, E, F> {
15 pub fn new(ttl: Duration, fetcher: F) -> Self {
16 Self {
17 value: None,
18 fetched_at: None,
19 ttl,
20 fetcher,
21 }
22 }
23
24 pub fn get(&mut self) -> Result<T, E> {
25 let expired = self.fetched_at.is_none_or(|t| t.elapsed() >= self.ttl);
26 if expired {
27 let new_value = (self.fetcher)()?;
28 self.value = Some(new_value);
29 self.fetched_at = Some(Instant::now());
30 }
31
32 Ok(self.value.as_ref().unwrap().clone())
33 }
34
35 pub fn invalidate(&mut self) {
36 self.fetched_at = None;
37 }
38}