Skip to main content

rullst_core/cache/
inspection.rs

1//! Bounded metadata-only cache inspection contracts.
2
3/// Maximum entries returned by one cache inspection.
4pub const MAX_CACHE_INSPECTION_ENTRIES: usize = 200;
5
6/// Metadata for one cache entry. Values are deliberately never included.
7#[derive(Clone, PartialEq, Eq)]
8pub struct CacheEntryMetadata {
9    pub(crate) logical_key: String,
10    pub(crate) value_bytes: usize,
11    pub(crate) remaining_ttl_ms: Option<u64>,
12}
13
14impl std::fmt::Debug for CacheEntryMetadata {
15    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        formatter
17            .debug_struct("CacheEntryMetadata")
18            .field("logical_key", &"[REDACTED]")
19            .field("value_bytes", &self.value_bytes)
20            .field("remaining_ttl_ms", &self.remaining_ttl_ms)
21            .finish()
22    }
23}
24
25impl CacheEntryMetadata {
26    pub(crate) fn new(
27        logical_key: String,
28        value_bytes: usize,
29        remaining_ttl_ms: Option<u64>,
30    ) -> Self {
31        Self {
32            logical_key,
33            value_bytes,
34            remaining_ttl_ms,
35        }
36    }
37
38    /// Returns the exact logical key.
39    ///
40    /// Keys can contain application identifiers. Keep this output inside an
41    /// explicitly authorized local diagnostic boundary.
42    pub fn logical_key(&self) -> &str {
43        &self.logical_key
44    }
45
46    /// Exact UTF-8 byte length of the cached value without returning it.
47    pub const fn value_bytes(&self) -> usize {
48        self.value_bytes
49    }
50
51    /// Approximate remaining TTL in milliseconds, or `None` for no expiry.
52    pub const fn remaining_ttl_ms(&self) -> Option<u64> {
53        self.remaining_ttl_ms
54    }
55}
56
57/// One bounded metadata-only cache snapshot.
58#[derive(Clone, Debug, PartialEq, Eq)]
59pub struct CacheInspection {
60    pub(crate) entries: Vec<CacheEntryMetadata>,
61    pub(crate) truncated: bool,
62}
63
64impl CacheInspection {
65    pub(crate) fn new(entries: Vec<CacheEntryMetadata>, truncated: bool) -> Self {
66        Self { entries, truncated }
67    }
68
69    /// Entries in deterministic logical-key order.
70    pub fn entries(&self) -> &[CacheEntryMetadata] {
71        &self.entries
72    }
73
74    /// Whether additional entries existed beyond the requested bound.
75    pub const fn truncated(&self) -> bool {
76        self.truncated
77    }
78}
79
80pub(crate) fn validate_inspection_limit(limit: usize) -> Result<(), super::CacheError> {
81    if limit == 0 || limit > MAX_CACHE_INSPECTION_ENTRIES {
82        return Err(super::CacheError::InvalidInspectionLimit);
83    }
84    Ok(())
85}