1use thiserror::Error;
7
8#[derive(Debug, Error)]
14pub enum EngineError {
15 #[error("shape mismatch: {rows}x{cols} != data len {data_len}")]
17 ShapeMismatch {
18 rows: usize,
19 cols: usize,
20 data_len: usize,
21 },
22
23 #[error("unknown series '{name}'")]
24 UnknownSeries { name: String },
25
26 #[error("unknown price series '{key}'")]
27 UnknownPriceKey { key: String },
28
29 #[error("unknown benchmark series '{key}'")]
30 UnknownBenchmark { key: String },
31
32 #[error("benchmark series '{key}' has no symbols")]
33 EmptyBenchmark { key: String },
34
35 #[error("bare Const {value} not allowed at top level")]
36 BareConst { value: f64 },
37
38 #[error("bad freq '{freq}'")]
39 BadFreq { freq: String },
40
41 #[error("Rebalance takes either freq or on, not both")]
42 RebalanceBoth,
43
44 #[error("Rebalance needs freq or on")]
45 RebalanceNeither,
46
47 #[error("bad groupby agg '{agg}'")]
48 BadGroupbyAgg { agg: String },
49
50 #[error("both operands of a binary op are Const")]
51 BothOperandsConst,
52
53 #[error("spec parse error: {0}")]
54 SpecParse(String),
55
56 #[error("eval error: {0}")]
58 Eval(String),
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn display_messages() {
67 let e = EngineError::ShapeMismatch {
68 rows: 1,
69 cols: 2,
70 data_len: 3,
71 };
72 assert!(e.to_string().contains("shape mismatch"));
73 assert_eq!(
74 EngineError::UnknownSeries { name: "pe".into() }.to_string(),
75 "unknown series 'pe'"
76 );
77 assert_eq!(
78 EngineError::BadFreq { freq: "X".into() }.to_string(),
79 "bad freq 'X'"
80 );
81 assert!(EngineError::Eval("boom".into())
82 .to_string()
83 .contains("boom"));
84 assert!(EngineError::SpecParse("eof".into())
85 .to_string()
86 .contains("spec parse"));
87 }
88
89 #[test]
90 fn is_std_error() {
91 let e: Box<dyn std::error::Error> = Box::new(EngineError::RebalanceNeither);
92 assert!(e.to_string().contains("Rebalance"));
93 }
94}