timedmap/
value.rs

1use crate::time::TimeSource;
2use std::time::Duration;
3
4/// Wraps a map value with a specified
5/// expiry [`TimeSource`].
6#[derive(Debug, Clone)]
7pub struct Value<V, TS> {
8    value: V,
9    expires: TS,
10}
11
12impl<V, TS> Value<V, TS>
13where
14    V: Clone,
15    TS: TimeSource,
16{
17    /// Creates a new [`Value`] with the given inner
18    /// value and lifetime as [`Duration`].
19    ///
20    /// The values expiry is calculated by adding the
21    /// specified lifetime to the result of `TS:now()`.
22    pub fn new(value: V, lifetime: Duration) -> Self {
23        Self {
24            value,
25            expires: TS::now() + lifetime,
26        }
27    }
28
29    /// Returns `true` when the specified expiry is
30    /// after the current time.
31    pub fn is_expired(&self) -> bool {
32        self.is_expired_at(&TS::now())
33    }
34
35    /// Returns `true` when the specified expiry is
36    /// after the given time `at`.
37    pub fn is_expired_at(&self, at: &TS) -> bool {
38        at > &self.expires
39    }
40
41    /// Returns a reference to the values expiry
42    /// [`TimeSource`].
43    pub fn expires(&self) -> &TS {
44        &self.expires
45    }
46
47    /// Sets the expiry of the value to now plus the
48    /// given lifetime.
49    pub fn set_expiry(&mut self, lifetime: Duration) {
50        self.expires = TS::now() + lifetime;
51    }
52
53    /// Adds the given duration to the values
54    /// expiry.
55    pub fn add_expiry(&mut self, lifetime: Duration) {
56        self.expires += lifetime;
57    }
58
59    /// Returns a copy of the inner value.
60    pub fn value(&self) -> V {
61        self.value.clone()
62    }
63
64    /// Returns a reference to the inner value.
65    pub fn value_ref(&self) -> &V {
66        &self.value
67    }
68
69    /// Returns a copy of the inner value if
70    /// the expiry has not yet exceeded.
71    pub fn value_checked(&self) -> Option<V> {
72        if self.is_expired() {
73            None
74        } else {
75            Some(self.value())
76        }
77    }
78
79    /// Returns a reference to the inner value if
80    /// the expiry has not yet exceeded.
81    pub fn value_ref_checked(&self) -> Option<&V> {
82        if self.is_expired() {
83            None
84        } else {
85            Some(self.value_ref())
86        }
87    }
88}
89
90#[cfg(test)]
91mod test {
92    use super::*;
93    use mock_instant::{Instant, MockClock};
94
95    #[test]
96    fn expiry() {
97        let v: Value<_, Instant> = Value::new("foo", Duration::from_millis(100));
98        assert_eq!(v.expires(), &(Instant::now() + Duration::from_millis(100)));
99        assert!(!v.is_expired());
100        assert_eq!(v.value_checked(), Some("foo"));
101
102        MockClock::advance(Duration::from_millis(100));
103
104        assert!(!v.is_expired());
105        assert_eq!(v.value_checked(), Some("foo"));
106
107        MockClock::advance(Duration::from_millis(1));
108
109        assert!(v.is_expired());
110        assert_eq!(v.value_checked(), None);
111    }
112}