xls_rs/operations/
types.rs1use anyhow::Result;
4
5pub trait ProgressCallback: Send {
7 fn on_progress(&mut self, current: usize, total: Option<usize>, message: &str);
8}
9
10pub struct StderrProgress {
12 last_percent: usize,
13}
14
15impl StderrProgress {
16 pub fn new() -> Self {
17 Self { last_percent: 0 }
18 }
19}
20
21impl ProgressCallback for StderrProgress {
22 fn on_progress(&mut self, current: usize, total: Option<usize>, message: &str) {
23 if let Some(total) = total {
24 let percent = if total > 0 {
25 (current * 100) / total
26 } else {
27 0
28 };
29 if percent != self.last_percent {
30 eprintln!("\r{}: {}% ({}/{})", message, percent, current, total);
31 self.last_percent = percent;
32 }
33 } else {
34 eprintln!("\r{}: {} processed", message, current);
35 }
36 }
37}
38
39pub struct NoProgress;
41
42impl ProgressCallback for NoProgress {
43 fn on_progress(&mut self, _current: usize, _total: Option<usize>, _message: &str) {}
44}
45
46#[derive(Debug, Clone, Copy, PartialEq)]
48pub enum SortOrder {
49 Ascending,
50 Descending,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq)]
55pub enum JoinType {
56 Inner,
57 Left,
58 Right,
59 Outer,
60}
61
62impl JoinType {
63 pub fn from_str(s: &str) -> Result<Self> {
64 match s.to_lowercase().as_str() {
65 "inner" => Ok(JoinType::Inner),
66 "left" => Ok(JoinType::Left),
67 "right" => Ok(JoinType::Right),
68 "outer" | "full" => Ok(JoinType::Outer),
69 _ => anyhow::bail!("Unknown join type: {}. Use: inner, left, right, outer", s),
70 }
71 }
72}
73
74#[derive(Debug, Clone, Copy)]
76pub enum AggFunc {
77 Sum,
78 Count,
79 Mean,
80 Min,
81 Max,
82}
83
84impl AggFunc {
85 pub fn from_str(s: &str) -> Result<Self> {
86 match s.to_lowercase().as_str() {
87 "sum" => Ok(AggFunc::Sum),
88 "count" => Ok(AggFunc::Count),
89 "mean" | "avg" | "average" => Ok(AggFunc::Mean),
90 "min" => Ok(AggFunc::Min),
91 "max" => Ok(AggFunc::Max),
92 _ => anyhow::bail!(
93 "Unknown aggregation: {}. Use: sum, count, mean, min, max",
94 s
95 ),
96 }
97 }
98
99 pub fn name(&self) -> &'static str {
100 match self {
101 AggFunc::Sum => "sum",
102 AggFunc::Count => "count",
103 AggFunc::Mean => "mean",
104 AggFunc::Min => "min",
105 AggFunc::Max => "max",
106 }
107 }
108
109 pub fn apply(&self, values: &[f64]) -> f64 {
110 if values.is_empty() {
111 return 0.0;
112 }
113 match self {
114 AggFunc::Sum => values.iter().sum(),
115 AggFunc::Count => values.len() as f64,
116 AggFunc::Mean => values.iter().sum::<f64>() / values.len() as f64,
117 AggFunc::Min => values.iter().cloned().fold(f64::INFINITY, f64::min),
118 AggFunc::Max => values.iter().cloned().fold(f64::NEG_INFINITY, f64::max),
119 }
120 }
121}