|
1 | 1 | use crate::simulation::fee_model::FeePoint; |
2 | 2 | use std::fmt::Write as FmtWrite; |
3 | 3 |
|
| 4 | +/// Time window filter for exports. |
| 5 | +#[derive(Debug, Clone, Copy)] |
| 6 | +pub enum Window { |
| 7 | + OneHour, |
| 8 | + SixHours, |
| 9 | + TwentyFourHours, |
| 10 | + All, |
| 11 | +} |
| 12 | + |
| 13 | +impl Window { |
| 14 | + pub fn from_str(s: &str) -> Option<Self> { |
| 15 | + match s { |
| 16 | + "1h" => Some(Self::OneHour), |
| 17 | + "6h" => Some(Self::SixHours), |
| 18 | + "24h" => Some(Self::TwentyFourHours), |
| 19 | + "all" => Some(Self::All), |
| 20 | + _ => None, |
| 21 | + } |
| 22 | + } |
| 23 | + |
| 24 | + pub fn cutoff_seconds(&self) -> Option<u64> { |
| 25 | + match self { |
| 26 | + Self::OneHour => Some(3600), |
| 27 | + Self::SixHours => Some(21600), |
| 28 | + Self::TwentyFourHours => Some(86400), |
| 29 | + Self::All => None, |
| 30 | + } |
| 31 | + } |
| 32 | +} |
| 33 | + |
4 | 34 | /// Exports devkit results to external formats. |
5 | 35 | pub struct Export; |
6 | 36 |
|
7 | 37 | impl Export { |
| 38 | + /// Filter points by window relative to the latest timestamp. |
| 39 | + pub fn filter_window<'a>(points: &'a [FeePoint], window: Window) -> &'a [FeePoint] { |
| 40 | + match window.cutoff_seconds() { |
| 41 | + None => points, |
| 42 | + Some(secs) => { |
| 43 | + let max_ts = points.iter().map(|p| p.timestamp).max().unwrap_or(0); |
| 44 | + let cutoff = max_ts.saturating_sub(secs); |
| 45 | + let start = points.partition_point(|p| p.timestamp < cutoff); |
| 46 | + &points[start..] |
| 47 | + } |
| 48 | + } |
| 49 | + } |
| 50 | + |
8 | 51 | /// Serialize fee points to CSV: timestamp,fee,ledger,is_spike. |
9 | 52 | pub fn to_csv(points: &[FeePoint]) -> String { |
10 | 53 | let mut out = String::from("timestamp,fee,ledger,is_spike\n"); |
@@ -44,6 +87,25 @@ mod tests { |
44 | 87 | use super::*; |
45 | 88 | use crate::simulation::fee_model::FeePoint; |
46 | 89 |
|
| 90 | + fn pts() -> Vec<FeePoint> { |
| 91 | + vec![ |
| 92 | + FeePoint { timestamp: 0, fee: 100, ledger: 1, is_spike: false }, |
| 93 | + FeePoint { timestamp: 7200, fee: 200, ledger: 2, is_spike: true }, |
| 94 | + ] |
| 95 | + } |
| 96 | + |
| 97 | + #[test] |
| 98 | + fn window_1h_filters() { |
| 99 | + let p = pts(); |
| 100 | + let filtered = Export::filter_window(&p, Window::OneHour); |
| 101 | + assert_eq!(filtered.len(), 1); |
| 102 | + assert_eq!(filtered[0].timestamp, 7200); |
| 103 | + } |
| 104 | + |
| 105 | + #[test] |
| 106 | + fn window_all_keeps_all() { |
| 107 | + let p = pts(); |
| 108 | + assert_eq!(Export::filter_window(&p, Window::All).len(), 2); |
47 | 109 | fn sample() -> Vec<FeePoint> { |
48 | 110 | vec![FeePoint { timestamp: 1000, fee: 100, ledger: 1, is_spike: false }] |
49 | 111 | } |
|
0 commit comments