use crate::time::TimeSource;
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct Value<V, TS> {
value: V,
expires: TS,
}
impl<V, TS> Value<V, TS>
where
V: Clone,
TS: TimeSource,
{
pub fn new(value: V, lifetime: Duration) -> Self {
Self {
value,
expires: TS::now() + lifetime,
}
}
pub fn is_expired(&self) -> bool {
self.is_expired_at(&TS::now())
}
pub fn is_expired_at(&self, at: &TS) -> bool {
at > &self.expires
}
pub fn expires(&self) -> &TS {
&self.expires
}
pub fn set_expiry(&mut self, lifetime: Duration) {
self.expires = TS::now() + lifetime;
}
pub fn add_expiry(&mut self, lifetime: Duration) {
self.expires += lifetime;
}
pub fn value(&self) -> V {
self.value.clone()
}
pub fn value_ref(&self) -> &V {
&self.value
}
pub fn value_checked(&self) -> Option<V> {
if self.is_expired() {
None
} else {
Some(self.value())
}
}
pub fn value_ref_checked(&self) -> Option<&V> {
if self.is_expired() {
None
} else {
Some(self.value_ref())
}
}
}
#[cfg(test)]
mod test {
use super::*;
use mock_instant::{Instant, MockClock};
#[test]
fn expiry() {
let v: Value<_, Instant> = Value::new("foo", Duration::from_millis(100));
assert_eq!(v.expires(), &(Instant::now() + Duration::from_millis(100)));
assert!(!v.is_expired());
assert_eq!(v.value_checked(), Some("foo"));
MockClock::advance(Duration::from_millis(100));
assert!(!v.is_expired());
assert_eq!(v.value_checked(), Some("foo"));
MockClock::advance(Duration::from_millis(1));
assert!(v.is_expired());
assert_eq!(v.value_checked(), None);
}
}