1use crate::{
2 expressions::token::Error, language::Language, locale::Locale,
3 number_format::to_excel_precision_str, types::*,
4};
5
6#[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 pub fn new_string(si: i32, s: i32) -> Cell {
42 Cell::SharedString { si, s }
43 }
44
45 pub fn new_number(v: f64, s: i32) -> Cell {
47 Cell::NumberCell { v, s }
48 }
49
50 pub fn new_boolean(v: bool, s: i32) -> Cell {
52 Cell::BooleanCell { v, s }
53 }
54
55 pub fn new_error(ei: Error, s: i32) -> Cell {
57 Cell::ErrorCell { ei, s }
58 }
59
60 pub fn new_formula(f: i32, s: i32) -> Cell {
62 Cell::CellFormula {
63 f,
64 s,
65 v: FormulaValue::Unevaluated,
66 }
67 }
68
69 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}