umya_spreadsheet/structs/
numbering_format.rs1use std::io::Cursor;
2
3use md5::Digest;
4use phf::phf_map;
5use quick_xml::{
6 Reader,
7 Writer,
8 escape,
9 events::BytesStart,
10};
11
12use crate::{
13 reader::driver::get_attribute,
14 writer::driver::write_start_tag,
15};
16
17#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
18pub struct NumberingFormat {
19 number_format_id: u32,
20 format_code: Box<str>,
21 is_build_in: bool,
22}
23
24impl Default for NumberingFormat {
25 #[inline]
26 fn default() -> Self {
27 Self {
28 number_format_id: 0,
29 format_code: NumberingFormat::FORMAT_GENERAL.into(),
30 is_build_in: true,
31 }
32 }
33}
34
35impl NumberingFormat {
36 pub const FORMAT_ACCOUNTING_EUR: &'static str =
37 r#"_("€"* #,##0.00_);_("€"* \(#,##0.00\);_("€"* "-"??_);_(@_)"#;
38 pub const FORMAT_ACCOUNTING_USD: &'static str =
39 r#"_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)"#;
40 pub const FORMAT_CURRENCY_EUR: &'static str = r#"#,##0_-"€""#;
41 pub const FORMAT_CURRENCY_EUR_SIMPLE: &'static str = r#"#,##0.00_-"€""#;
42 pub const FORMAT_CURRENCY_USD: &'static str = r"$#,##0_-";
43 pub const FORMAT_CURRENCY_USD_SIMPLE: &'static str = r##""$"#,##0.00_-"##;
44 pub const FORMAT_DATE_DATETIME: &'static str = "d/m/yy h:mm";
45 pub const FORMAT_DATE_DDMMYYYY: &'static str = "dd-mm-yyyy";
46 pub const FORMAT_DATE_DDMMYYYYSLASH: &'static str = "dd/mm/yyyy";
47 pub const FORMAT_DATE_DMMINUS: &'static str = "d-m";
48 pub const FORMAT_DATE_DMYMINUS: &'static str = "d-m-yy";
49 pub const FORMAT_DATE_DMYSLASH: &'static str = "d/m/yy";
50 pub const FORMAT_DATE_MYMINUS: &'static str = "m-yy";
51 pub const FORMAT_DATE_TIME1: &'static str = "h:mm AM/PM";
52 pub const FORMAT_DATE_TIME2: &'static str = "h:mm:ss AM/PM";
53 pub const FORMAT_DATE_TIME3: &'static str = "h:mm";
54 pub const FORMAT_DATE_TIME4: &'static str = "h:mm:ss";
55 pub const FORMAT_DATE_TIME5: &'static str = "mm:ss";
56 pub const FORMAT_DATE_TIME6: &'static str = "h:mm:ss";
57 pub const FORMAT_DATE_TIME8: &'static str = "h:mm:ss;@";
58 pub const FORMAT_DATE_XLSX14: &'static str = "mm-dd-yy";
59 pub const FORMAT_DATE_XLSX15: &'static str = "d-mmm-yy";
60 pub const FORMAT_DATE_XLSX16: &'static str = "d-mmm";
61 pub const FORMAT_DATE_XLSX17: &'static str = "mmm-yy";
62 pub const FORMAT_DATE_XLSX22: &'static str = "m/d/yy h:mm";
63 pub const FORMAT_DATE_YYYYMMDD: &'static str = "yyyy-mm-dd";
64 pub const FORMAT_DATE_YYYYMMDD2: &'static str = "yyyy-mm-dd";
65 pub const FORMAT_DATE_YYYYMMDDSLASH: &'static str = "yyyy/mm/dd;@";
66 pub const FORMAT_GENERAL: &'static str = "General";
68 pub const FORMAT_NUMBER: &'static str = "0";
69 pub const FORMAT_NUMBER_00: &'static str = "0.00";
70 pub const FORMAT_NUMBER_COMMA_SEPARATED1: &'static str = "#,##0.00";
71 pub const FORMAT_NUMBER_COMMA_SEPARATED2: &'static str = "#,##0.00_-";
72 pub const FORMAT_PERCENTAGE: &'static str = "0%";
73 pub const FORMAT_PERCENTAGE_00: &'static str = "0.00%";
74 pub const FORMAT_TEXT: &'static str = "@";
75
76 #[inline]
77 #[must_use]
78 pub fn number_format_id(&self) -> u32 {
79 self.number_format_id
80 }
81
82 #[inline]
83 #[must_use]
84 #[deprecated(since = "3.0.0", note = "Use number_format_id()")]
85 pub fn get_number_format_id(&self) -> u32 {
86 self.number_format_id()
87 }
88
89 pub fn set_number_format_id(&mut self, value: u32) -> &mut Self {
90 let format_code_result = FILL_BUILT_IN_FORMAT_CODES.entries().find_map(|(key, val)| {
91 if key == &value {
92 Some(val.to_owned())
93 } else {
94 None
95 }
96 });
97
98 self.format_code = format_code_result
99 .expect("Not Found NumberFormatId.")
100 .to_owned()
101 .into_boxed_str();
102 self.number_format_id = value;
103 self.is_build_in = true;
104 self
105 }
106
107 #[inline]
108 pub(crate) fn set_number_format_id_crate(&mut self, value: u32) -> &mut Self {
109 self.number_format_id = value;
110 self
111 }
112
113 pub fn set_format_code<S: Into<String>>(&mut self, value: S) -> &mut Self {
126 self.format_code = value.into().into_boxed_str();
127 for (index, format) in FILL_BUILT_IN_FORMAT_CODES.entries() {
128 if &&*self.format_code == format {
129 self.number_format_id = *index;
130 self.is_build_in = true;
131 return self;
132 }
133 }
134 self.number_format_id = 999_999;
135 self.is_build_in = false;
136 self
137 }
138
139 #[inline]
140 pub(crate) fn set_format_code_crate<S: Into<String>>(&mut self, value: S) -> &mut Self {
141 self.format_code = value.into().into_boxed_str();
142 self
143 }
144
145 #[inline]
146 #[must_use]
147 pub fn format_code(&self) -> &str {
148 &self.format_code
149 }
150
151 #[inline]
152 #[must_use]
153 #[deprecated(since = "3.0.0", note = "Use format_code()")]
154 pub fn get_format_code(&self) -> &str {
155 self.format_code()
156 }
157
158 #[inline]
159 pub(crate) fn is_build_in(&self) -> bool {
160 self.is_build_in
161 }
162
163 #[inline]
164 #[deprecated(since = "3.0.0", note = "Use is_build_in()")]
165 pub(crate) fn get_is_build_in(&self) -> bool {
166 self.is_build_in()
167 }
168
169 #[inline]
170 pub(crate) fn hash_code(&self) -> String {
171 format!("{:x}", md5::Md5::digest(&*self.format_code))
172 }
173
174 #[inline]
175 #[deprecated(since = "3.0.0", note = "Use hash_code()")]
176 pub(crate) fn get_hash_code(&self) -> String {
177 self.hash_code()
178 }
179
180 pub(crate) fn set_attributes<R: std::io::BufRead>(
181 &mut self,
182 _reader: &mut Reader<R>,
183 e: &BytesStart,
184 ) {
185 self.number_format_id = get_attribute(e, b"numFmtId")
186 .unwrap()
187 .parse::<u32>()
188 .unwrap();
189 self.format_code = escape::unescape(get_attribute(e, b"formatCode").unwrap().as_str())
190 .unwrap()
191 .to_string()
192 .into_boxed_str();
193 self.is_build_in = false;
194 }
195
196 pub(crate) fn write_to(&self, writer: &mut Writer<Cursor<Vec<u8>>>, number_format_id: u32) {
197 write_start_tag(
199 writer,
200 "numFmt",
201 vec![
202 ("numFmtId", number_format_id.to_string()).into(),
203 ("formatCode", &self.format_code).into(),
204 ],
205 true,
206 );
207 }
208}
209
210pub(crate) static FILL_BUILT_IN_FORMAT_CODES: phf::Map<u32, &'static str> = phf_map! {
211 0u32 => NumberingFormat::FORMAT_GENERAL,
212 1u32 => "0",
213 2u32 => "0.00",
214 3u32 => "#,##0",
215 4u32 => "#,##0.00",
216
217 9u32 => "0%",
218 10u32 => "0.00%",
219 11u32 => "0.00E+00",
220 12u32 => "# ?/?",
221 13u32 => "# ??/??",
222 14u32 => "m/d/yyyy",
223 15u32 => "d-mmm-yy",
224 16u32 => "d-mmm",
225 17u32 => "mmm-yy",
226 18u32 => "h:mm AM/PM",
227 19u32 => "h:mm:ss AM/PM",
228 20u32 => "h:mm",
229 21u32 => "h:mm:ss",
230 22u32 => "m/d/yyyy h:mm",
231
232 37u32 => "#,##0_);(#,##0)",
233 38u32 => "#,##0_);[Red](#,##0)",
234 39u32 => "#,##0.00_);(#,##0.00)",
235 40u32 => "#,##0.00_);[Red](#,##0.00)",
236
237 44u32 => r#"_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)"#,
238 45u32 => "mm:ss",
239 46u32 => "[h]:mm:ss",
240 47u32 => "mm:ss.0",
241 48u32 => "##0.0E+0",
242 49u32 => "@",
243
244 27u32 => "[$-404]e/m/d",
246 30u32 => "m/d/yy",
247 36u32 => "[$-404]e/m/d",
248 50u32 => "[$-404]e/m/d",
249 57u32 => "[$-404]e/m/d",
250
251 59u32 => "t0",
253 60u32 => "t0.00",
254 61u32 => "t#,##0",
255 62u32 => "t#,##0.00",
256 67u32 => "t0%",
257 68u32 => "t0.00%",
258 69u32 => "t# ?/?",
259 70u32 => "t# ??/??",
260
261 28u32 => r#"[$-411]ggge"年"m"月"d"日""#,
263 29u32 => r#"[$-411]ggge"年"m"月"d"日""#,
264 31u32 => r#"yyyy"年"m"月"d"日""#,
265 32u32 => r#"h"時"mm"分""#,
266 33u32 => r#"h"時"mm"分"ss"秒""#,
267 34u32 => r#"yyyy"年"m"月""#,
268 35u32 => r#"m"月"d"日""#,
269 51u32 => r#"[$-411]ggge"年"m"月"d"日""#,
270 52u32 => r#"yyyy"年"m"月""#,
271 53u32 => r#"m"月"d"日""#,
272 54u32 => r#"[$-411]ggge"年"m"月"d"日""#,
273 55u32 => r#"yyyy"年"m"月""#,
274 56u32 => r#"m"月"d"日""#,
275 58u32 => r#"[$-411]ggge"年"m"月"d"日""#,
276};
277
278#[cfg(test)]
279mod tests {
280 use super::*;
281
282 #[test]
283 fn set_number_format_id() {
284 let mut obj = NumberingFormat::default();
285
286 obj.set_number_format_id(0);
287 assert_eq!(obj.format_code(), "General");
288
289 obj.set_number_format_id(1);
290 assert_eq!(obj.format_code(), "0");
291 }
292}