use std::any::Any;
use std::sync::Arc;
pub trait Lifecycle: Send + Sync {
fn on_evict(&self, key: &dyn Any);
fn on_remove(&self, key: &dyn Any) {
self.on_evict(key);
}
fn on_clear(&self, key: &dyn Any) {
self.on_evict(key);
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct DefaultLifecycle;
impl Lifecycle for DefaultLifecycle {
#[inline]
fn on_evict(&self, _key: &dyn Any) {
}
#[inline]
fn on_remove(&self, _key: &dyn Any) {
}
#[inline]
fn on_clear(&self, _key: &dyn Any) {
}
}
impl<L: Lifecycle> Lifecycle for Arc<L> {
#[inline]
fn on_evict(&self, key: &dyn Any) {
(**self).on_evict(key);
}
#[inline]
fn on_remove(&self, key: &dyn Any) {
(**self).on_remove(key);
}
#[inline]
fn on_clear(&self, key: &dyn Any) {
(**self).on_clear(key);
}
}
pub struct TypedLifecycle<K, F>
where
F: Fn(K) + Send + Sync,
{
callback: F,
_marker: std::marker::PhantomData<fn(K)>,
}
impl<K, F> TypedLifecycle<K, F>
where
F: Fn(K) + Send + Sync,
{
pub fn new(callback: F) -> Self {
Self {
callback,
_marker: std::marker::PhantomData,
}
}
}
impl<K, F> Lifecycle for TypedLifecycle<K, F>
where
K: Clone + Send + Sync + 'static,
F: Fn(K) + Send + Sync,
{
fn on_evict(&self, key: &dyn Any) {
if let Some(key) = key.downcast_ref::<K>() {
(self.callback)(key.clone());
}
}
}
#[cfg(test)]
mod tests {
use std::sync::atomic::{AtomicUsize, Ordering};
use super::*;
#[test]
fn test_default_lifecycle() {
let lifecycle = DefaultLifecycle;
lifecycle.on_evict(&42u64);
lifecycle.on_remove(&42u64);
lifecycle.on_clear(&42u64);
}
#[test]
fn test_typed_lifecycle() {
let counter = Arc::new(AtomicUsize::new(0));
let counter_clone = counter.clone();
let lifecycle = TypedLifecycle::<u64, _>::new(move |key| {
assert_eq!(key, 42);
counter_clone.fetch_add(1, Ordering::Relaxed);
});
lifecycle.on_evict(&42u64);
assert_eq!(counter.load(Ordering::Relaxed), 1);
lifecycle.on_evict(&"wrong_type");
assert_eq!(counter.load(Ordering::Relaxed), 1);
}
#[test]
fn test_arc_lifecycle() {
let counter = Arc::new(AtomicUsize::new(0));
let counter_clone = counter.clone();
let lifecycle = TypedLifecycle::<u64, _>::new(move |_| {
counter_clone.fetch_add(1, Ordering::Relaxed);
});
let arc_lifecycle = Arc::new(lifecycle);
arc_lifecycle.on_evict(&42u64);
assert_eq!(counter.load(Ordering::Relaxed), 1);
}
}