use chrono::{DateTime, Utc};
use std::mem::size_of;
use std::time::Duration;
use crate::Raw;
use crate::policy::EntityPolicyConfig;
use crate::response::CacheState;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CacheValue<T> {
data: T,
expire: Option<DateTime<Utc>>,
stale: Option<DateTime<Utc>>,
}
impl<T> CacheValue<T> {
pub fn new(data: T, expire: Option<DateTime<Utc>>, stale: Option<DateTime<Utc>>) -> Self {
CacheValue {
data,
expire,
stale,
}
}
pub fn from_config(data: T, config: &EntityPolicyConfig) -> Self {
Self::new(
data,
config.ttl.map(|d| Utc::now() + d),
config.stale_ttl.map(|d| Utc::now() + d),
)
}
#[inline]
pub fn data(&self) -> &T {
&self.data
}
#[inline]
pub fn expire(&self) -> Option<DateTime<Utc>> {
self.expire
}
#[inline]
pub fn stale(&self) -> Option<DateTime<Utc>> {
self.stale
}
pub fn into_inner(self) -> T {
self.data
}
pub fn into_parts(self) -> (CacheMeta, T) {
(CacheMeta::new(self.expire, self.stale), self.data)
}
pub fn ttl(&self) -> Option<Duration> {
self.expire.and_then(|expire| {
let duration = expire.signed_duration_since(Utc::now());
if duration.num_seconds() > 0 {
Some(Duration::from_secs(duration.num_seconds() as u64))
} else {
None
}
})
}
}
impl<T> CacheValue<T> {
pub fn cache_state(self) -> CacheState<Self> {
let now = Utc::now();
if let Some(expire) = self.expire
&& expire <= now
{
CacheState::Expired(self)
} else if let Some(stale) = self.stale
&& stale <= now
{
CacheState::Stale(self)
} else {
CacheState::Actual(self)
}
}
}
pub struct CacheMeta {
pub expire: Option<DateTime<Utc>>,
pub stale: Option<DateTime<Utc>>,
}
impl CacheMeta {
pub fn new(expire: Option<DateTime<Utc>>, stale: Option<DateTime<Utc>>) -> CacheMeta {
CacheMeta { expire, stale }
}
}
impl CacheValue<Raw> {
pub fn memory_size(&self) -> usize {
let fixed_overhead = size_of::<Self>();
let content = self.data.len();
fixed_overhead + content
}
}