Skip to main content

rs_utilities/
cached_value.rs

1use 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}