logisheets_controller/calc_engine/calculator/funcs/
utils.rs1use logisheets_parser::ast;
2
3use super::{CalcValue, Value};
4
5pub enum ConditionResult {
6 True,
7 False,
8 Error(ast::Error),
9}
10
11pub fn get_condition_result(calc_value: CalcValue) -> ConditionResult {
12 match calc_value {
13 CalcValue::Scalar(s) => match s {
14 Value::Blank => ConditionResult::False,
15 Value::Number(num) => {
16 if num.abs() < 1e-10 {
17 ConditionResult::False
18 } else {
19 ConditionResult::True
20 }
21 }
22 Value::Text(_) => ConditionResult::Error(ast::Error::Value),
23 Value::Boolean(b) => {
24 if b {
25 ConditionResult::True
26 } else {
27 ConditionResult::False
28 }
29 }
30 Value::Error(e) => ConditionResult::Error(e),
31 },
32 CalcValue::Union(_) => ConditionResult::Error(ast::Error::Value),
33 CalcValue::Range(_) => ConditionResult::Error(ast::Error::Value),
35 CalcValue::Cube(_) => ConditionResult::Error(ast::Error::Ref),
36 }
37}
38
39pub fn convert_f64(value: Value) -> Result<f64, ast::Error> {
40 match value {
41 Value::Blank => Ok(0_f64),
42 Value::Number(n) => Ok(n),
43 Value::Text(t) => match t.parse::<f64>() {
44 Ok(n) => Ok(n),
45 Err(_) => Err(ast::Error::Value),
46 },
47 Value::Boolean(b) => {
48 if b {
49 Ok(1.)
50 } else {
51 Ok(0.)
52 }
53 }
54 Value::Error(e) => Err(e),
55 }
56}
57
58pub fn is_na_error(value: &CalcValue) -> bool {
59 match value {
60 CalcValue::Scalar(s) => match s {
61 Value::Error(e) => *e == ast::Error::Na,
62 _ => false,
63 },
64 CalcValue::Range(_) => false,
65 CalcValue::Cube(_) => true,
66 CalcValue::Union(_) => false,
67 }
68}
69
70pub fn is_error(value: &CalcValue) -> bool {
71 match value {
72 CalcValue::Scalar(s) => match s {
73 Value::Error(_) => true,
74 _ => false,
75 },
76 CalcValue::Range(_) => false,
77 CalcValue::Cube(_) => true,
78 CalcValue::Union(_) => false,
79 }
80}
81
82fn get_f64(v: Value) -> Result<Option<f64>, ast::Error> {
83 match v {
84 Value::Number(f) => Ok(Some(f)),
85 Value::Boolean(b) => {
86 if b {
87 Ok(Some(1.))
88 } else {
89 Ok(Some(0.))
90 }
91 }
92 Value::Error(e) => Err(e),
93 _ => Ok(None),
94 }
95}
96
97pub fn get_nums_from_value(value: CalcValue) -> Result<Vec<f64>, ast::Error> {
98 match value {
99 CalcValue::Scalar(v) => match get_f64(v) {
100 Ok(num) => {
101 if let Some(f) = num {
102 Ok(vec![f])
103 } else {
104 Ok(vec![])
105 }
106 }
107 Err(e) => Err(e),
108 },
109 CalcValue::Range(r) => r.into_iter().fold(Ok(vec![]), |prev, curr| {
110 if prev.is_err() {
111 return prev;
112 }
113 let num = get_f64(curr);
114 match num {
115 Ok(f) => {
116 if let Some(n) = f {
117 let mut v = prev.unwrap();
118 v.push(n);
119 Ok(v)
120 } else {
121 prev
122 }
123 }
124 Err(e) => Err(e),
125 }
126 }),
127 CalcValue::Cube(c) => c.into_iter().fold(Ok(vec![]), |prev, curr| {
128 if prev.is_err() {
129 return prev;
130 }
131 let num = get_f64(curr);
132 match num {
133 Ok(f) => {
134 if let Some(n) = f {
135 let mut v = prev.unwrap();
136 v.push(n);
137 Ok(v)
138 } else {
139 prev
140 }
141 }
142 Err(e) => Err(e),
143 }
144 }),
145 CalcValue::Union(_) => Err(ast::Error::Unspecified),
146 }
147}
148
149#[cfg(test)]
150pub mod tests_utils {
151 use logisheets_base::async_func::{AsyncCalcResult, AsyncFuncCommitTrait, Task};
152 use logisheets_base::get_curr_addr::GetCurrAddrTrait;
153 use logisheets_base::set_curr_cell::SetCurrCellTrait;
154 use logisheets_base::SheetId;
155 use logisheets_parser::ast;
156
157 use crate::calc_engine::calculator::calc_vertex::{CalcValue, CalcVertex};
158 use crate::calc_engine::connector::Connector;
159 use crate::errors::Result;
160 use crate::CellId;
161
162 pub struct TestFetcher {}
163 impl AsyncFuncCommitTrait for TestFetcher {
164 fn query_or_commit_task(
165 &mut self,
166 _sheet_id: logisheets_base::SheetId,
167 _cell_id: logisheets_base::CellId,
168 _task: Task,
169 ) -> Option<AsyncCalcResult> {
170 None
171 }
172 }
173
174 impl GetCurrAddrTrait for TestFetcher {
175 fn get_curr_addr(&self) -> logisheets_base::Addr {
176 unreachable!()
177 }
178 }
179
180 impl SetCurrCellTrait for TestFetcher {
181 fn set_curr_cell(
182 &mut self,
183 _active_sheet: logisheets_base::SheetId,
184 _addr: logisheets_base::Addr,
185 ) {
186 unreachable!()
187 }
188 }
189
190 impl Connector for TestFetcher {
191 fn convert(&mut self, _: &ast::CellReference) -> CalcVertex {
192 unreachable!()
193 }
194
195 fn get_calc_value(&mut self, vertex: CalcVertex) -> CalcValue {
196 match vertex {
197 CalcVertex::Value(v) => v,
198 CalcVertex::Reference(_) => panic!(),
199 CalcVertex::Union(_) => todo!(),
200 }
201 }
202
203 fn get_text(&self, _: &logisheets_base::TextId) -> Result<String> {
204 todo!()
205 }
206
207 fn get_func_name(&self, _: &logisheets_base::FuncId) -> Result<String> {
208 todo!()
209 }
210
211 fn get_cell_idx(
212 &self,
213 _sheet_id: logisheets_base::SheetId,
214 _cell_id: &logisheets_base::CellId,
215 ) -> Result<(usize, usize)> {
216 Ok((0, 0))
217 }
218
219 fn get_cell_id(
220 &self,
221 _sheet_id: logisheets_base::SheetId,
222 _row: usize,
223 _col: usize,
224 ) -> Result<CellId> {
225 unreachable!()
226 }
227
228 fn commit_calc_values(&mut self, _vertex: (SheetId, CellId), _result: CalcValue) {
229 unreachable!()
230 }
231
232 fn is_async_func(&self, _func_name: &str) -> bool {
233 false
234 }
235
236 fn get_range(
237 &self,
238 _sheet_id: &logisheets_base::SheetId,
239 _range: &logisheets_base::RangeId,
240 ) -> Option<logisheets_base::Range> {
241 unreachable!()
242 }
243
244 fn get_sheet_id_by_name(&self, _name: &str) -> Result<SheetId> {
245 unreachable!()
246 }
247
248 fn set_curr_as_dirty(&mut self) -> Result<()> {
249 unreachable!()
250 }
251
252 fn get_active_sheet(&self) -> SheetId {
253 1
254 }
255 }
256}