use cached::macros::concurrent_cached;
use cached::{Expires, ShardedExpiringCache, ShardedExpiringLruCache};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
#[derive(Clone, Debug)]
struct Session {
user_id: u32,
expired: Arc<AtomicBool>,
}
impl Expires for Session {
fn is_expired(&self) -> bool {
self.expired.load(Ordering::Relaxed)
}
}
#[concurrent_cached(expires = true, key = "u32", convert = r#"{ user_id }"#)]
fn get_session(user_id: u32, expired_flag: Arc<AtomicBool>) -> Session {
Session {
user_id,
expired: expired_flag,
}
}
#[concurrent_cached(
expires = true,
max_size = 128,
key = "u32",
convert = r#"{ user_id }"#
)]
fn get_session_bounded(user_id: u32, expired_flag: Arc<AtomicBool>) -> Session {
Session {
user_id,
expired: expired_flag,
}
}
fn main() {
println!("--- Sharded Expiring Cache Example ---");
let expiry = Arc::new(AtomicBool::new(false)); let already_expired = Arc::new(AtomicBool::new(true));
let s1 = get_session(1, expiry.clone());
let s2 = get_session(1, expiry.clone());
println!("Call 1 (live session): {:?}", s1);
println!("Call 2 (live session cached): {:?}", s2);
expiry.store(true, Ordering::Relaxed);
let s3 = get_session(1, expiry.clone());
println!(
"Call 3 (after flag changed to expired -> recalculated): {:?}",
s3
);
let bounded_flag = Arc::new(AtomicBool::new(false));
let b1 = get_session_bounded(10, bounded_flag.clone());
let b2 = get_session_bounded(10, bounded_flag.clone());
println!("LRU call 1 (live): {:?}", b1);
println!("LRU call 2 (live): {:?}", b2);
let live_shared = Arc::new(AtomicBool::new(false));
let handles: Vec<_> = (0..8)
.map(|id| {
let flag = live_shared.clone();
thread::spawn(move || {
for i in 0..50 {
let _ = get_session(i % 5, flag.clone());
}
println!("Thread {id} finished lookups.");
})
})
.collect();
for h in handles {
h.join().expect("thread panicked");
}
println!("\n--- Manual Store Construction ---");
let cache: ShardedExpiringCache<u32, Session> =
ShardedExpiringCache::builder().build().unwrap();
let s_manual = Session {
user_id: 100,
expired: already_expired.clone(), };
cached::ConcurrentCached::cache_set(&cache, 100, s_manual).expect("infallible");
let val = cached::ConcurrentCached::cache_get(&cache, &100).expect("infallible");
assert!(
val.is_none(),
"Expired manual entry should be filtered out on get"
);
println!(
"Manual ShardedExpiringCache lookup for expired entry: {:?}",
val
);
let lru: ShardedExpiringLruCache<u32, Session> = ShardedExpiringLruCache::builder()
.max_size(64)
.shards(4)
.build()
.expect("valid config");
let live_manual = Session {
user_id: 200,
expired: Arc::new(AtomicBool::new(false)),
};
println!("Caching session for user_id {}", live_manual.user_id);
cached::ConcurrentCached::cache_set(&lru, 200, live_manual).expect("infallible");
let val_lru = cached::ConcurrentCached::cache_get(&lru, &200).expect("infallible");
assert!(val_lru.is_some(), "Live manual entry should be present");
println!(
"Manual ShardedExpiringLruCache lookup for live entry: {:?}",
val_lru
);
println!("Example complete.");
}