use rayon::iter::{IntoParallelIterator, ParallelIterator};
use crate::filters::bsd_month_from_timestamp;
use crate::ingestion::FileReader;
use crate::parser::LogFormatParser;
#[derive(Debug)]
pub struct YearMap {
transitions: Vec<(usize, i32)>,
}
impl YearMap {
pub fn build<P: LogFormatParser + ?Sized>(
file_reader: &FileReader,
parser: &P,
start_year: i32,
) -> Self {
let count = file_reader.line_count();
let months: Vec<Option<u32>> = (0..count)
.into_par_iter()
.map(|i| {
let line = file_reader.get_line(i);
parser
.parse_timestamp(line)
.and_then(bsd_month_from_timestamp)
})
.collect();
let mut transitions = Vec::with_capacity(16);
transitions.push((0, start_year));
let mut current_year = start_year;
let mut prev_month = 0;
for (i, month_opt) in months.iter().enumerate() {
if let Some(month) = month_opt {
let month = *month;
if prev_month > 0 && month < prev_month && prev_month - month > 3 {
current_year += 1;
transitions.push((i, current_year));
}
prev_month = month;
}
}
YearMap { transitions }
}
pub fn year_for_line(&self, line_idx: usize) -> i32 {
match self
.transitions
.binary_search_by_key(&line_idx, |&(idx, _)| idx)
{
Ok(pos) => self.transitions[pos].1,
Err(0) => self.transitions[0].1,
Err(pos) => self.transitions[pos - 1].1,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn map_from(transitions: Vec<(usize, i32)>) -> YearMap {
YearMap { transitions }
}
#[test]
fn test_year_for_line_single_year() {
let m = map_from(vec![(0, 2024)]);
assert_eq!(m.year_for_line(0), 2024);
assert_eq!(m.year_for_line(100), 2024);
assert_eq!(m.year_for_line(usize::MAX), 2024);
}
#[test]
fn test_year_for_line_transition() {
let m = map_from(vec![(0, 2023), (50, 2024)]);
assert_eq!(m.year_for_line(0), 2023);
assert_eq!(m.year_for_line(49), 2023);
assert_eq!(m.year_for_line(50), 2024);
assert_eq!(m.year_for_line(200), 2024);
}
#[test]
fn test_year_for_line_exact_transition_boundary() {
let m = map_from(vec![(0, 2022), (10, 2023), (20, 2024)]);
assert_eq!(m.year_for_line(9), 2022);
assert_eq!(m.year_for_line(10), 2023);
assert_eq!(m.year_for_line(19), 2023);
assert_eq!(m.year_for_line(20), 2024);
}
}