Skip to main content

hyperi_rustlib/cache/
config.rs

1// Project:   hyperi-rustlib
2// File:      src/cache/config.rs
3// Purpose:   Cache configuration
4// Language:  Rust
5//
6// License:   BUSL-1.1
7// Copyright: (c) 2026 HYPERI PTY LIMITED
8
9//! Cache configuration with per-source TTL support.
10
11use std::collections::HashMap;
12
13use serde::{Deserialize, Serialize};
14
15/// Configuration for the in-memory cache.
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct CacheConfig {
18    /// Maximum number of entries. Default: 10,000.
19    #[serde(default = "default_max_capacity")]
20    pub max_capacity: u64,
21
22    /// Default TTL in seconds for entries without a source-specific TTL.
23    /// Default: 3600 (1 hour).
24    #[serde(default = "default_ttl_secs")]
25    pub default_ttl_secs: u64,
26
27    /// Per-source TTL overrides in seconds.
28    /// Keys are source names (e.g., "http", "db", "search").
29    #[serde(default)]
30    pub source_ttls: HashMap<String, u64>,
31}
32
33fn default_max_capacity() -> u64 {
34    10_000
35}
36
37fn default_ttl_secs() -> u64 {
38    3600
39}
40
41impl Default for CacheConfig {
42    fn default() -> Self {
43        Self {
44            max_capacity: default_max_capacity(),
45            default_ttl_secs: default_ttl_secs(),
46            source_ttls: HashMap::new(),
47        }
48    }
49}
50
51impl CacheConfig {
52    /// Load from the config cascade under the `cache` key.
53    #[must_use]
54    pub fn from_cascade() -> Self {
55        #[cfg(feature = "config")]
56        {
57            if let Some(cfg) = crate::config::try_get()
58                && let Ok(cc) = cfg.unmarshal_key_registered::<Self>("cache")
59            {
60                return cc;
61            }
62        }
63        Self::default()
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn defaults_are_sensible() {
73        let config = CacheConfig::default();
74        assert_eq!(config.max_capacity, 10_000);
75        assert_eq!(config.default_ttl_secs, 3600);
76        assert!(config.source_ttls.is_empty());
77    }
78
79    #[test]
80    fn deserialise_with_source_ttls() {
81        let yaml = r"
82max_capacity: 5000
83default_ttl_secs: 1800
84source_ttls:
85  http: 86400
86  db: 900
87";
88        let config: CacheConfig = serde_yaml_ng::from_str(yaml).unwrap();
89        assert_eq!(config.max_capacity, 5000);
90        assert_eq!(config.default_ttl_secs, 1800);
91        assert_eq!(config.source_ttls["http"], 86400);
92        assert_eq!(config.source_ttls["db"], 900);
93    }
94}