use std::{ cmp::Ordering, fmt::{self, Debug}, }; use chrono::{DateTime, Duration, Utc}; use super::{log::LogFilter, Filter}; use crate::{EarlyLogResult, LogResult}; pub trait Producer: Send + Sync + Debug { type Output; fn produce_early(&self, _early_log: &EarlyLogResult) -> Option { None } fn produce(&self, log: &LogResult) -> Self::Output; } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum CompOp { Less, LessEqual, Equal, GreaterEqual, Greater, } impl fmt::Display for CompOp { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let symbol = match self { CompOp::Less => "<", CompOp::LessEqual => "<=", CompOp::Equal => "=", CompOp::GreaterEqual => ">=", CompOp::Greater => ">", }; f.pad(symbol) } } impl CompOp { pub fn matches(self, cmp: Ordering) -> bool { match cmp { Ordering::Less => self == CompOp::Less || self == CompOp::LessEqual, Ordering::Equal => { self == CompOp::LessEqual || self == CompOp::Equal || self == CompOp::GreaterEqual } Ordering::Greater => self == CompOp::Greater || self == CompOp::GreaterEqual, } } } struct Comparator( Box>, CompOp, Box>, ); impl Debug for Comparator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({:?} {} {:?})", self.0, self.1, self.2) } } impl Filter for Comparator where V: Ord, { fn filter(&self, log: &LogResult) -> bool { let lhs = self.0.produce(log); let rhs = self.2.produce(log); self.1.matches(lhs.cmp(&rhs)) } } pub fn comparison( lhs: Box>, op: CompOp, rhs: Box>, ) -> Box where V: Ord, { Box::new(Comparator(lhs, op, rhs)) } #[derive(Debug, Clone, PartialEq, Eq, Hash)] struct ConstantProducer(V); impl Producer for ConstantProducer { type Output = V; fn produce_early(&self, _: &EarlyLogResult) -> Option { Some(self.0.clone()) } fn produce(&self, _: &LogResult) -> Self::Output { self.0.clone() } } pub fn constant( value: V, ) -> Box> { Box::new(ConstantProducer(value)) } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] struct TimeProducer; impl Producer for TimeProducer { type Output = DateTime; fn produce_early(&self, early_log: &EarlyLogResult) -> Option { early_log .log_file .file_name() .and_then(super::log::datetime_from_filename) } fn produce(&self, log: &LogResult) -> Self::Output { log.time } } pub fn time() -> Box>> { Box::new(TimeProducer) } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] struct DurationProducer; impl Producer for DurationProducer { type Output = Duration; fn produce(&self, log: &LogResult) -> Self::Output { log.duration } } pub fn duration() -> Box> { Box::new(DurationProducer) }