use std::{
sync::Arc,
time::{Duration, Instant},
};
#[derive(Clone, Debug)]
pub struct Policy {
max_capacity: Option<u64>,
num_segments: usize,
time_to_live: Option<Duration>,
time_to_idle: Option<Duration>,
}
impl Policy {
pub(crate) fn new(
max_capacity: Option<u64>,
num_segments: usize,
time_to_live: Option<Duration>,
time_to_idle: Option<Duration>,
) -> Self {
Self {
max_capacity,
num_segments,
time_to_live,
time_to_idle,
}
}
pub fn max_capacity(&self) -> Option<u64> {
self.max_capacity
}
#[cfg(feature = "sync")]
pub(crate) fn set_max_capacity(&mut self, capacity: Option<u64>) {
self.max_capacity = capacity;
}
pub fn num_segments(&self) -> usize {
self.num_segments
}
#[cfg(feature = "sync")]
pub(crate) fn set_num_segments(&mut self, num: usize) {
self.num_segments = num;
}
pub fn time_to_live(&self) -> Option<Duration> {
self.time_to_live
}
pub fn time_to_idle(&self) -> Option<Duration> {
self.time_to_idle
}
}
pub trait Expiry<K, V> {
#[allow(unused_variables)]
fn expire_after_create(&self, key: &K, value: &V, current_time: Instant) -> Option<Duration> {
None
}
#[allow(unused_variables)]
fn expire_after_read(
&self,
key: &K,
value: &V,
current_time: Instant,
current_duration: Option<Duration>,
last_modified_at: Instant,
) -> Option<Duration> {
current_duration
}
#[allow(unused_variables)]
fn expire_after_update(
&self,
key: &K,
value: &V,
current_time: Instant,
current_duration: Option<Duration>,
) -> Option<Duration> {
current_duration
}
}
pub(crate) struct ExpirationPolicy<K, V> {
time_to_live: Option<Duration>,
time_to_idle: Option<Duration>,
expiry: Option<Arc<dyn Expiry<K, V> + Send + Sync + 'static>>,
}
impl<K, V> Default for ExpirationPolicy<K, V> {
fn default() -> Self {
Self {
time_to_live: None,
time_to_idle: None,
expiry: None,
}
}
}
impl<K, V> Clone for ExpirationPolicy<K, V> {
fn clone(&self) -> Self {
Self {
time_to_live: self.time_to_live,
time_to_idle: self.time_to_idle,
expiry: self.expiry.as_ref().map(Arc::clone),
}
}
}
impl<K, V> ExpirationPolicy<K, V> {
#[cfg(test)]
pub(crate) fn new(
time_to_live: Option<Duration>,
time_to_idle: Option<Duration>,
expiry: Option<Arc<dyn Expiry<K, V> + Send + Sync + 'static>>,
) -> Self {
Self {
time_to_live,
time_to_idle,
expiry,
}
}
pub(crate) fn time_to_live(&self) -> Option<Duration> {
self.time_to_live
}
pub(crate) fn set_time_to_live(&mut self, duration: Duration) {
self.time_to_live = Some(duration);
}
pub(crate) fn time_to_idle(&self) -> Option<Duration> {
self.time_to_idle
}
pub(crate) fn set_time_to_idle(&mut self, duration: Duration) {
self.time_to_idle = Some(duration);
}
pub(crate) fn expiry(&self) -> Option<Arc<dyn Expiry<K, V> + Send + Sync + 'static>> {
self.expiry.as_ref().map(Arc::clone)
}
pub(crate) fn set_expiry(&mut self, expiry: Arc<dyn Expiry<K, V> + Send + Sync + 'static>) {
self.expiry = Some(expiry);
}
}
#[cfg(test)]
pub(crate) mod test_utils {
use std::sync::atomic::{AtomicU8, Ordering};
#[derive(Default)]
pub(crate) struct ExpiryCallCounters {
expected_creations: AtomicU8,
expected_reads: AtomicU8,
expected_updates: AtomicU8,
actual_creations: AtomicU8,
actual_reads: AtomicU8,
actual_updates: AtomicU8,
}
impl ExpiryCallCounters {
pub(crate) fn incl_expected_creations(&self) {
self.expected_creations.fetch_add(1, Ordering::Relaxed);
}
pub(crate) fn incl_expected_reads(&self) {
self.expected_reads.fetch_add(1, Ordering::Relaxed);
}
pub(crate) fn incl_expected_updates(&self) {
self.expected_updates.fetch_add(1, Ordering::Relaxed);
}
pub(crate) fn incl_actual_creations(&self) {
self.actual_creations.fetch_add(1, Ordering::Relaxed);
}
pub(crate) fn incl_actual_reads(&self) {
self.actual_reads.fetch_add(1, Ordering::Relaxed);
}
pub(crate) fn incl_actual_updates(&self) {
self.actual_updates.fetch_add(1, Ordering::Relaxed);
}
pub(crate) fn verify(&self) {
assert_eq!(
self.expected_creations.load(Ordering::Relaxed),
self.actual_creations.load(Ordering::Relaxed),
"expected_creations != actual_creations"
);
assert_eq!(
self.expected_reads.load(Ordering::Relaxed),
self.actual_reads.load(Ordering::Relaxed),
"expected_reads != actual_reads"
);
assert_eq!(
self.expected_updates.load(Ordering::Relaxed),
self.actual_updates.load(Ordering::Relaxed),
"expected_updates != actual_updates"
);
}
}
}