Skip to main content

ironcalc_base/
cell.rs

1use crate::{
2    expressions::token::Error, language::Language, locale::Locale,
3    number_format::to_excel_precision_str, types::*,
4};
5
6/// A CellValue is the representation of the cell content.
7#[derive(Debug, PartialEq)]
8pub enum CellValue {
9    None,
10    String(String),
11    Number(f64),
12    Boolean(bool),
13}
14
15impl From<f64> for CellValue {
16    fn from(value: f64) -> Self {
17        Self::Number(value)
18    }
19}
20
21impl From<String> for CellValue {
22    fn from(value: String) -> Self {
23        Self::String(value)
24    }
25}
26
27impl From<&str> for CellValue {
28    fn from(value: &str) -> Self {
29        Self::String(value.to_string())
30    }
31}
32
33impl From<bool> for CellValue {
34    fn from(value: bool) -> Self {
35        Self::Boolean(value)
36    }
37}
38
39impl Cell {
40    /// Creates a new Cell with a shared string (`si` is the string index)
41    pub fn new_string(si: i32, s: i32) -> Cell {
42        Cell::SharedString { si, s }
43    }
44
45    /// Creates a new Cell with a number
46    pub fn new_number(v: f64, s: i32) -> Cell {
47        Cell::NumberCell { v, s }
48    }
49
50    /// Creates a new Cell with a boolean
51    pub fn new_boolean(v: bool, s: i32) -> Cell {
52        Cell::BooleanCell { v, s }
53    }
54
55    /// Creates a new Cell with an error value
56    pub fn new_error(ei: Error, s: i32) -> Cell {
57        Cell::ErrorCell { ei, s }
58    }
59
60    /// Creates a new Cell with an unevaluated formula
61    pub fn new_formula(f: i32, s: i32) -> Cell {
62        Cell::CellFormula {
63            f,
64            s,
65            v: FormulaValue::Unevaluated,
66        }
67    }
68
69    /// Returns the formula index of a cell if any.
70    pub fn get_formula(&self) -> Option<i32> {
71        match self {
72            Cell::CellFormula { f, .. } | Cell::ArrayFormula { f, .. } => Some(*f),
73            _ => None,
74        }
75    }
76
77    pub fn has_formula(&self) -> bool {
78        self.get_formula().is_some()
79    }
80
81    pub fn set_style(&mut self, style: i32) {
82        match self {
83            Cell::EmptyCell { s, .. }
84            | Cell::BooleanCell { s, .. }
85            | Cell::NumberCell { s, .. }
86            | Cell::ErrorCell { s, .. }
87            | Cell::SharedString { s, .. }
88            | Cell::CellFormula { s, .. }
89            | Cell::ArrayFormula { s, .. }
90            | Cell::SpillCell { s, .. } => *s = style,
91        }
92    }
93
94    pub fn get_style(&self) -> i32 {
95        match self {
96            Cell::EmptyCell { s, .. }
97            | Cell::BooleanCell { s, .. }
98            | Cell::NumberCell { s, .. }
99            | Cell::ErrorCell { s, .. }
100            | Cell::SharedString { s, .. }
101            | Cell::CellFormula { s, .. }
102            | Cell::ArrayFormula { s, .. }
103            | Cell::SpillCell { s, .. } => *s,
104        }
105    }
106
107    pub fn get_type(&self) -> CellType {
108        match self {
109            Cell::EmptyCell { .. } => CellType::Number,
110            Cell::BooleanCell { .. } => CellType::LogicalValue,
111            Cell::NumberCell { .. } => CellType::Number,
112            Cell::ErrorCell { .. } => CellType::ErrorValue,
113            Cell::SharedString { .. } => CellType::Text,
114            Cell::CellFormula { v, .. } | Cell::ArrayFormula { v, .. } => match v {
115                FormulaValue::Unevaluated | FormulaValue::Number(_) => CellType::Number,
116                FormulaValue::Boolean(_) => CellType::LogicalValue,
117                FormulaValue::Text(_) => CellType::Text,
118                FormulaValue::Error { .. } => CellType::ErrorValue,
119            },
120            Cell::SpillCell { v, .. } => match v {
121                SpillValue::Number(_) => CellType::Number,
122                SpillValue::Boolean(_) => CellType::LogicalValue,
123                SpillValue::Text(_) => CellType::Text,
124                SpillValue::Error(_) => CellType::ErrorValue,
125            },
126        }
127    }
128
129    pub fn get_localized_text(
130        &self,
131        shared_strings: &[String],
132        locale: &Locale,
133        language: &Language,
134    ) -> String {
135        match self.value(shared_strings, language) {
136            CellValue::None => "".to_string(),
137            CellValue::String(v) => v,
138            CellValue::Boolean(v) => {
139                if v {
140                    language.booleans.r#true.to_string()
141                } else {
142                    language.booleans.r#false.to_string()
143                }
144            }
145            CellValue::Number(v) => {
146                let value = to_excel_precision_str(v);
147
148                if locale.numbers.symbols.decimal != "." {
149                    value.replace(".", &locale.numbers.symbols.decimal)
150                } else {
151                    value
152                }
153            }
154        }
155    }
156
157    pub fn value(&self, shared_strings: &[String], language: &Language) -> CellValue {
158        match self {
159            Cell::EmptyCell { .. } => CellValue::None,
160            Cell::BooleanCell { v, .. } => CellValue::Boolean(*v),
161            Cell::NumberCell { v, .. } => CellValue::Number(*v),
162            Cell::ErrorCell { ei, .. } => CellValue::String(ei.to_localized_error_string(language)),
163            Cell::SharedString { si, .. } => {
164                let v = shared_strings
165                    .get(*si as usize)
166                    .cloned()
167                    .unwrap_or_default();
168                CellValue::String(v)
169            }
170            Cell::CellFormula { v, .. } | Cell::ArrayFormula { v, .. } => {
171                formula_value_to_cell_value(v, language)
172            }
173            Cell::SpillCell { v, .. } => spill_value_to_cell_value(v, language),
174        }
175    }
176
177    pub fn formatted_value<F>(
178        &self,
179        shared_strings: &[String],
180        language: &Language,
181        format_number: F,
182    ) -> String
183    where
184        F: Fn(f64) -> String,
185    {
186        match self.value(shared_strings, language) {
187            CellValue::None => "".to_string(),
188            CellValue::String(value) => value,
189            CellValue::Boolean(value) => {
190                if value {
191                    language.booleans.r#true.to_string()
192                } else {
193                    language.booleans.r#false.to_string()
194                }
195            }
196            CellValue::Number(value) => format_number(value),
197        }
198    }
199}
200
201fn formula_value_to_cell_value(v: &FormulaValue, language: &Language) -> CellValue {
202    match v {
203        FormulaValue::Unevaluated => CellValue::String("#ERROR!".to_string()),
204        FormulaValue::Boolean(b) => CellValue::Boolean(*b),
205        FormulaValue::Number(n) => CellValue::Number(*n),
206        FormulaValue::Text(s) => CellValue::String(s.clone()),
207        FormulaValue::Error { ei, .. } => CellValue::String(ei.to_localized_error_string(language)),
208    }
209}
210
211fn spill_value_to_cell_value(v: &SpillValue, language: &Language) -> CellValue {
212    match v {
213        SpillValue::Boolean(b) => CellValue::Boolean(*b),
214        SpillValue::Number(n) => CellValue::Number(*n),
215        SpillValue::Text(s) => CellValue::String(s.clone()),
216        SpillValue::Error(ei) => CellValue::String(ei.to_localized_error_string(language)),
217    }
218}