Skip to main content

omega_cache/core/
entry.rs

1use crate::core::key::Key;
2use std::cmp::Ordering;
3use std::hash::Hash;
4use std::time::{Duration, Instant};
5
6/// A container representing a single cached item.
7///
8/// `Entry` holds the mapping between a [Key] and its associated value,
9/// along with optional TTL (Time To Live) metadata to handle expiration.
10///
11/// ### Generic Constraints
12/// * `K`: The raw key type, which must implement [Eq] and [Hash].
13/// * `V`: The type of the value being stored.
14pub struct Entry<K, V>
15where
16    K: Eq + Hash,
17{
18    /// The wrapped key of the entry.
19    key: Key<K>,
20    /// The value stored in the cache.
21    value: V,
22    /// An optional timestamp indicating when this entry becomes invalid.
23    expiration: Expiration,
24}
25
26impl<K, V> Entry<K, V>
27where
28    K: Eq + Hash,
29{
30    /// Creates a new cache entry with a specified expiration.
31    ///
32    /// # Parameters
33    /// * `key`: The raw key to be wrapped in a [Key].
34    /// * `value`: The data to store.
35    /// * `expired_at`: An [Instant] in the future when the entry expires, or `None` for no limit.
36    #[inline]
37    pub fn new(key: K, value: V) -> Self {
38        Self {
39            key: Key::new(key),
40            value,
41            expiration: Expiration::Never,
42        }
43    }
44
45    #[inline(always)]
46    pub fn with_ttl(key: K, value: V, ttl: Duration) -> Self {
47        Self {
48            key: Key::new(key),
49            value,
50            expiration: Expiration::ttl(ttl),
51        }
52    }
53
54    #[inline(always)]
55    pub fn with_custom_expiration(
56        key: K,
57        value: V,
58        is_expire: impl Fn() -> bool + 'static + Send + Sync,
59    ) -> Self {
60        Self {
61            key: Key::new(key),
62            value,
63            expiration: Expiration::Custom(CustomExpiration {
64                is_expired: Box::new(is_expire),
65            }),
66        }
67    }
68
69    /// Returns a reference to the entry's [Key].
70    #[inline]
71    pub fn key(&self) -> &Key<K> {
72        &self.key
73    }
74
75    /// Returns a reference to the stored value.
76    #[inline]
77    pub fn value(&self) -> &V {
78        &self.value
79    }
80
81    /// Checks if the entry has passed its expiration deadline.
82    ///
83    /// Returns `true` if `expired_at` is a time in the past relative to [Instant::now].
84    /// If no expiration was set, this always returns `false`.
85    #[inline]
86    pub fn is_expired(&self) -> bool {
87        self.expiration.is_expired()
88    }
89}
90
91pub enum Expiration {
92    Never,
93    TTL(Instant),
94    Custom(CustomExpiration),
95}
96
97pub struct CustomExpiration {
98    is_expired: Box<dyn Fn() -> bool + Send + Sync>,
99}
100
101impl Expiration {
102    #[inline(always)]
103    pub fn never() -> Self {
104        Self::Never
105    }
106
107    #[inline(always)]
108    pub fn ttl(ttl: Duration) -> Self {
109        Self::TTL(Instant::now() + ttl)
110    }
111
112    #[inline(always)]
113    pub fn is_expired(&self) -> bool {
114        match self {
115            Expiration::Never => false,
116            Expiration::TTL(deadline) => Instant::now().cmp(deadline) == Ordering::Greater,
117            Expiration::Custom(custom) => (custom.is_expired)(),
118        }
119    }
120}