1use chrono::{DateTime, Duration, Utc};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8pub enum TimeHorizon {
9 Immediate,
11 ShortTerm,
13 MediumTerm,
15 LongTerm,
17 Permanent,
19}
20
21impl TimeHorizon {
22 pub fn duration(&self) -> Option<Duration> {
24 match self {
25 Self::Immediate => Some(Duration::minutes(5)),
26 Self::ShortTerm => Some(Duration::hours(1)),
27 Self::MediumTerm => Some(Duration::hours(24)),
28 Self::LongTerm => Some(Duration::weeks(1)),
29 Self::Permanent => None,
30 }
31 }
32
33 pub fn compression_level(&self) -> f64 {
35 match self {
36 Self::Immediate => 0.0, Self::ShortTerm => 0.2, Self::MediumTerm => 0.5, Self::LongTerm => 0.7, Self::Permanent => 0.9, }
42 }
43
44 pub fn contains(&self, timestamp: DateTime<Utc>) -> bool {
46 match self.duration() {
47 Some(d) => Utc::now() - timestamp <= d,
48 None => true,
49 }
50 }
51
52 pub fn for_depth(depth: u8) -> Self {
54 match depth {
55 0 => Self::LongTerm, 1 => Self::MediumTerm, 2 => Self::ShortTerm, _ => Self::Immediate, }
60 }
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct HorizonConfig {
66 pub horizon: TimeHorizon,
68 pub max_entries: usize,
70 pub auto_compress: bool,
72 pub auto_evict: bool,
74}
75
76impl Default for HorizonConfig {
77 fn default() -> Self {
78 Self {
79 horizon: TimeHorizon::MediumTerm,
80 max_entries: 100,
81 auto_compress: true,
82 auto_evict: true,
83 }
84 }
85}
86
87impl HorizonConfig {
88 pub fn for_depth(depth: u8) -> Self {
90 let horizon = TimeHorizon::for_depth(depth);
91 let max_entries = match horizon {
92 TimeHorizon::Immediate => 10,
93 TimeHorizon::ShortTerm => 25,
94 TimeHorizon::MediumTerm => 50,
95 TimeHorizon::LongTerm => 100,
96 TimeHorizon::Permanent => 500,
97 };
98 Self {
99 horizon,
100 max_entries,
101 auto_compress: true,
102 auto_evict: true,
103 }
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn test_horizon_duration() {
113 assert!(TimeHorizon::Immediate.duration().is_some());
114 assert!(TimeHorizon::Permanent.duration().is_none());
115 }
116
117 #[test]
118 fn test_horizon_for_depth() {
119 assert_eq!(TimeHorizon::for_depth(0), TimeHorizon::LongTerm);
120 assert_eq!(TimeHorizon::for_depth(3), TimeHorizon::Immediate);
121 }
122
123 #[test]
124 fn test_contains() {
125 let now = Utc::now();
126 assert!(TimeHorizon::Immediate.contains(now));
127 }
128}