1use std::borrow::Cow;
2
3use chrono::{Duration, NaiveDate, NaiveDateTime, NaiveTime};
4use get_size2::GetSize;
5use rust_decimal::prelude::FromPrimitive;
6use rust_decimal::prelude::ToPrimitive;
7use rust_decimal::Decimal;
8
9use crate::text::TextTag;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, GetSize)]
13#[allow(missing_docs)]
14pub enum ValueType {
15 Empty,
16 Boolean,
17 Number,
18 Percentage,
19 Currency,
20 Text,
21 TextXml,
22 DateTime,
23 TimeDuration,
24}
25
26#[derive(Debug, Clone, PartialEq, Default)]
28#[allow(missing_docs)]
29pub enum Value {
30 #[default]
31 Empty,
32 Boolean(bool),
33 Number(f64),
34 Percentage(f64),
35 Currency(f64, Box<str>),
36 Text(String),
37 TextXml(Vec<TextTag>),
38 DateTime(NaiveDateTime),
39 TimeDuration(Duration),
40}
41
42impl GetSize for Value {
43 fn get_heap_size(&self) -> usize {
44 match self {
45 Value::Empty => 0,
46 Value::Boolean(_) => 0,
47 Value::Number(_) => 0,
48 Value::Percentage(_) => 0,
49 Value::Currency(_, v) => v.get_heap_size(),
50 Value::Text(v) => v.get_heap_size(),
51 Value::TextXml(v) => v.get_heap_size(),
52 Value::DateTime(_) => 0,
53 Value::TimeDuration(_) => 0,
54 }
55 }
56}
57
58impl Value {
59 pub fn value_type(&self) -> ValueType {
61 match self {
62 Value::Empty => ValueType::Empty,
63 Value::Boolean(_) => ValueType::Boolean,
64 Value::Number(_) => ValueType::Number,
65 Value::Percentage(_) => ValueType::Percentage,
66 Value::Currency(_, _) => ValueType::Currency,
67 Value::Text(_) => ValueType::Text,
68 Value::TextXml(_) => ValueType::TextXml,
69 Value::TimeDuration(_) => ValueType::TimeDuration,
70 Value::DateTime(_) => ValueType::DateTime,
71 }
72 }
73
74 pub fn as_bool_or(&self, d: bool) -> bool {
76 match self {
77 Value::Boolean(b) => *b,
78 _ => d,
79 }
80 }
81
82 pub fn as_i64_or_default(&self) -> i64 {
85 self.as_i64_opt().unwrap_or_default()
86 }
87
88 pub fn as_i64_or(&self, d: i64) -> i64 {
91 self.as_i64_opt().unwrap_or(d)
92 }
93
94 pub fn as_i64_opt(&self) -> Option<i64> {
97 match self {
98 Value::Number(n) => Some(*n as i64),
99 Value::Percentage(p) => Some(*p as i64),
100 Value::Currency(v, _) => Some(*v as i64),
101 _ => None,
102 }
103 }
104
105 pub fn as_u64_or_default(&self) -> u64 {
108 self.as_u64_opt().unwrap_or_default()
109 }
110
111 pub fn as_u64_or(&self, d: u64) -> u64 {
114 self.as_u64_opt().unwrap_or(d)
115 }
116
117 pub fn as_u64_opt(&self) -> Option<u64> {
120 match self {
121 Value::Number(n) => Some(*n as u64),
122 Value::Percentage(p) => Some(*p as u64),
123 Value::Currency(v, _) => Some(*v as u64),
124 _ => None,
125 }
126 }
127
128 pub fn as_i32_or_default(&self) -> i32 {
131 self.as_i32_opt().unwrap_or_default()
132 }
133
134 pub fn as_i32_or(&self, d: i32) -> i32 {
137 self.as_i32_opt().unwrap_or(d)
138 }
139
140 pub fn as_i32_opt(&self) -> Option<i32> {
143 match self {
144 Value::Number(n) => Some(*n as i32),
145 Value::Percentage(p) => Some(*p as i32),
146 Value::Currency(v, _) => Some(*v as i32),
147 _ => None,
148 }
149 }
150
151 pub fn as_u32_or_default(&self) -> u32 {
154 self.as_u32_opt().unwrap_or_default()
155 }
156
157 pub fn as_u32_or(&self, d: u32) -> u32 {
160 self.as_u32_opt().unwrap_or(d)
161 }
162
163 pub fn as_u32_opt(&self) -> Option<u32> {
166 match self {
167 Value::Number(n) => Some(*n as u32),
168 Value::Percentage(p) => Some(*p as u32),
169 Value::Currency(v, _) => Some(*v as u32),
170 _ => None,
171 }
172 }
173
174 pub fn as_i16_or_default(&self) -> i16 {
177 self.as_i16_opt().unwrap_or_default()
178 }
179
180 pub fn as_i16_or(&self, d: i16) -> i16 {
183 self.as_i16_opt().unwrap_or(d)
184 }
185
186 pub fn as_i16_opt(&self) -> Option<i16> {
189 match self {
190 Value::Number(n) => Some(*n as i16),
191 Value::Percentage(p) => Some(*p as i16),
192 Value::Currency(v, _) => Some(*v as i16),
193 _ => None,
194 }
195 }
196
197 pub fn as_u16_or_default(&self) -> u16 {
200 self.as_u16_opt().unwrap_or_default()
201 }
202
203 pub fn as_u16_or(&self, d: u16) -> u16 {
206 self.as_u16_opt().unwrap_or(d)
207 }
208
209 pub fn as_u16_opt(&self) -> Option<u16> {
212 match self {
213 Value::Number(n) => Some(*n as u16),
214 Value::Percentage(p) => Some(*p as u16),
215 Value::Currency(v, _) => Some(*v as u16),
216 _ => None,
217 }
218 }
219
220 pub fn as_i8_or_default(&self) -> i8 {
223 self.as_i8_opt().unwrap_or_default()
224 }
225
226 pub fn as_i8_or(&self, d: i8) -> i8 {
229 self.as_i8_opt().unwrap_or(d)
230 }
231
232 pub fn as_i8_opt(&self) -> Option<i8> {
235 match self {
236 Value::Number(n) => Some(*n as i8),
237 Value::Percentage(p) => Some(*p as i8),
238 Value::Currency(v, _) => Some(*v as i8),
239 _ => None,
240 }
241 }
242
243 pub fn as_u8_or_default(&self) -> u8 {
246 self.as_u8_opt().unwrap_or_default()
247 }
248
249 pub fn as_u8_or(&self, d: u8) -> u8 {
252 self.as_u8_opt().unwrap_or(d)
253 }
254
255 pub fn as_u8_opt(&self) -> Option<u8> {
258 match self {
259 Value::Number(n) => Some(*n as u8),
260 Value::Percentage(p) => Some(*p as u8),
261 Value::Currency(v, _) => Some(*v as u8),
262 _ => None,
263 }
264 }
265
266 #[cfg(feature = "rust_decimal")]
269 pub fn as_decimal_or_default(&self) -> Decimal {
270 self.as_decimal_opt().unwrap_or_default()
271 }
272
273 #[cfg(feature = "rust_decimal")]
276 pub fn as_decimal_or(&self, d: Decimal) -> Decimal {
277 self.as_decimal_opt().unwrap_or(d)
278 }
279
280 #[cfg(feature = "rust_decimal")]
283 pub fn as_decimal_opt(&self) -> Option<Decimal> {
284 match self {
285 Value::Number(n) => Decimal::from_f64(*n),
286 Value::Currency(v, _) => Decimal::from_f64(*v),
287 Value::Percentage(p) => Decimal::from_f64(*p),
288 _ => None,
289 }
290 }
291
292 pub fn as_f64_or_default(&self) -> f64 {
295 self.as_f64_opt().unwrap_or_default()
296 }
297
298 pub fn as_f64_or(&self, d: f64) -> f64 {
301 self.as_f64_opt().unwrap_or(d)
302 }
303
304 pub fn as_f64_opt(&self) -> Option<f64> {
307 match self {
308 Value::Number(n) => Some(*n),
309 Value::Currency(v, _) => Some(*v),
310 Value::Percentage(p) => Some(*p),
311 _ => None,
312 }
313 }
314
315 pub fn as_str_or_default(&self) -> &str {
317 self.as_str_opt().unwrap_or_default()
318 }
319
320 pub fn as_str_or<'a>(&'a self, d: &'a str) -> &'a str {
322 self.as_str_opt().unwrap_or(d)
323 }
324
325 pub fn as_cow_str_or<'a>(&'a self, d: &'a str) -> Cow<'a, str> {
329 match self {
330 Value::Text(s) => Cow::from(s),
331 Value::TextXml(v) => {
332 let mut buf = String::new();
333 let mut add_newline = false;
334 for t in v {
335 if add_newline {
336 buf.push('\n');
337 }
338 t.extract_text(&mut buf);
339 add_newline = true;
340 }
341 Cow::from(buf)
342 }
343 _ => Cow::from(d),
344 }
345 }
346
347 pub fn as_str_opt(&self) -> Option<&str> {
349 match self {
350 Value::Text(s) => Some(s.as_ref()),
351 _ => None,
352 }
353 }
354
355 pub fn as_string_or_default(&self) -> String {
357 self.as_string_opt().unwrap_or_default()
358 }
359
360 pub fn as_string_opt(&self) -> Option<String> {
362 match self {
363 Value::Text(s) => Some(s.clone()),
364 _ => None,
365 }
366 }
367
368 pub fn as_timeduration_or_default(&self) -> Duration {
371 self.as_timeduration_opt().unwrap_or_default()
372 }
373
374 pub fn as_timeduration_or(&self, d: Duration) -> Duration {
377 self.as_timeduration_opt().unwrap_or(d)
378 }
379
380 pub fn as_timeduration_opt(&self) -> Option<Duration> {
383 match self {
384 Value::TimeDuration(td) => Some(*td),
385 _ => None,
386 }
387 }
388
389 pub fn as_datetime_or_default(&self) -> NaiveDateTime {
392 self.as_datetime_opt().unwrap_or_default()
393 }
394
395 pub fn as_datetime_or(&self, d: NaiveDateTime) -> NaiveDateTime {
398 self.as_datetime_opt().unwrap_or(d)
399 }
400
401 pub fn as_datetime_opt(&self) -> Option<NaiveDateTime> {
404 match self {
405 Value::DateTime(dt) => Some(*dt),
406 _ => None,
407 }
408 }
409
410 pub fn as_date_or_default(&self) -> NaiveDate {
413 self.as_date_opt().unwrap_or_default()
414 }
415
416 pub fn as_date_or(&self, d: NaiveDate) -> NaiveDate {
419 self.as_date_opt().unwrap_or(d)
420 }
421
422 pub fn as_date_opt(&self) -> Option<NaiveDate> {
425 match self {
426 Value::DateTime(dt) => Some(dt.date()),
427 _ => None,
428 }
429 }
430
431 pub fn currency(&self) -> &str {
433 match self {
434 Value::Currency(_, c) => c,
435 _ => "",
436 }
437 }
438
439 #[allow(clippy::needless_range_loop)]
441 pub fn new_currency<S: AsRef<str>>(cur: S, value: f64) -> Self {
442 Value::Currency(value, cur.as_ref().into())
443 }
444
445 pub fn new_percentage(value: f64) -> Self {
447 Value::Percentage(value)
448 }
449}
450
451#[macro_export]
453macro_rules! currency {
454 ($c:expr, $v:expr) => {
455 Value::new_currency($c, $v as f64)
456 };
457}
458
459#[macro_export]
461macro_rules! percent {
462 ($v:expr) => {
463 Value::new_percentage($v)
464 };
465}
466
467impl From<()> for Value {
468 fn from(_: ()) -> Self {
469 Value::Empty
470 }
471}
472
473impl From<&str> for Value {
474 fn from(s: &str) -> Self {
475 Value::Text(s.to_string())
476 }
477}
478
479impl From<String> for Value {
480 fn from(s: String) -> Self {
481 Value::Text(s)
482 }
483}
484
485impl From<&String> for Value {
486 fn from(s: &String) -> Self {
487 Value::Text(s.to_string())
488 }
489}
490
491impl From<TextTag> for Value {
492 fn from(t: TextTag) -> Self {
493 Value::TextXml(vec![t])
494 }
495}
496
497impl From<Vec<TextTag>> for Value {
498 fn from(t: Vec<TextTag>) -> Self {
499 Value::TextXml(t)
500 }
501}
502
503impl From<Option<&str>> for Value {
504 fn from(s: Option<&str>) -> Self {
505 if let Some(s) = s {
506 Value::Text(s.to_string())
507 } else {
508 Value::Empty
509 }
510 }
511}
512
513impl From<Option<&String>> for Value {
514 fn from(s: Option<&String>) -> Self {
515 if let Some(s) = s {
516 Value::Text(s.to_string())
517 } else {
518 Value::Empty
519 }
520 }
521}
522
523impl From<Option<String>> for Value {
524 fn from(s: Option<String>) -> Self {
525 if let Some(s) = s {
526 Value::Text(s)
527 } else {
528 Value::Empty
529 }
530 }
531}
532
533#[cfg(feature = "rust_decimal")]
534impl From<Decimal> for Value {
535 fn from(f: Decimal) -> Self {
536 Value::Number(f.to_f64().expect("decimal->f64 should not fail"))
537 }
538}
539
540#[cfg(feature = "rust_decimal")]
541impl From<Option<Decimal>> for Value {
542 fn from(f: Option<Decimal>) -> Self {
543 if let Some(f) = f {
544 Value::Number(f.to_f64().expect("decimal->f64 should not fail"))
545 } else {
546 Value::Empty
547 }
548 }
549}
550
551macro_rules! from_number {
552 ($l:ty) => {
553 impl From<$l> for Value {
554 #![allow(trivial_numeric_casts)]
555 fn from(f: $l) -> Self {
556 Value::Number(f as f64)
557 }
558 }
559
560 impl From<&$l> for Value {
561 #![allow(trivial_numeric_casts)]
562 fn from(f: &$l) -> Self {
563 Value::Number(*f as f64)
564 }
565 }
566
567 impl From<Option<$l>> for Value {
568 #![allow(trivial_numeric_casts)]
569 fn from(f: Option<$l>) -> Self {
570 if let Some(f) = f {
571 Value::Number(f as f64)
572 } else {
573 Value::Empty
574 }
575 }
576 }
577
578 impl From<Option<&$l>> for Value {
579 #![allow(trivial_numeric_casts)]
580 fn from(f: Option<&$l>) -> Self {
581 if let Some(f) = f {
582 Value::Number(*f as f64)
583 } else {
584 Value::Empty
585 }
586 }
587 }
588 };
589}
590
591from_number!(f64);
592from_number!(f32);
593from_number!(i64);
594from_number!(i32);
595from_number!(i16);
596from_number!(i8);
597from_number!(u64);
598from_number!(u32);
599from_number!(u16);
600from_number!(u8);
601
602impl From<bool> for Value {
603 fn from(b: bool) -> Self {
604 Value::Boolean(b)
605 }
606}
607
608impl From<Option<bool>> for Value {
609 fn from(b: Option<bool>) -> Self {
610 if let Some(b) = b {
611 Value::Boolean(b)
612 } else {
613 Value::Empty
614 }
615 }
616}
617
618impl From<NaiveDateTime> for Value {
619 fn from(dt: NaiveDateTime) -> Self {
620 Value::DateTime(dt)
621 }
622}
623
624impl From<Option<NaiveDateTime>> for Value {
625 fn from(dt: Option<NaiveDateTime>) -> Self {
626 if let Some(dt) = dt {
627 Value::DateTime(dt)
628 } else {
629 Value::Empty
630 }
631 }
632}
633
634impl From<NaiveDate> for Value {
635 fn from(dt: NaiveDate) -> Self {
636 Value::DateTime(dt.and_hms_opt(0, 0, 0).unwrap())
637 }
638}
639
640impl From<Option<NaiveDate>> for Value {
641 fn from(dt: Option<NaiveDate>) -> Self {
642 if let Some(dt) = dt {
643 Value::DateTime(dt.and_hms_opt(0, 0, 0).expect("valid time"))
644 } else {
645 Value::Empty
646 }
647 }
648}
649
650impl From<NaiveTime> for Value {
651 fn from(ti: NaiveTime) -> Self {
652 Value::DateTime(NaiveDateTime::new(
653 NaiveDate::from_ymd_opt(1899, 12, 30).expect("valid date"),
654 ti,
655 ))
656 }
657}
658
659impl From<Option<NaiveTime>> for Value {
660 fn from(dt: Option<NaiveTime>) -> Self {
661 if let Some(ti) = dt {
662 Value::DateTime(NaiveDateTime::new(
663 NaiveDate::from_ymd_opt(1899, 12, 30).expect("valid date"),
664 ti,
665 ))
666 } else {
667 Value::Empty
668 }
669 }
670}
671
672impl From<Duration> for Value {
673 fn from(d: Duration) -> Self {
674 Value::TimeDuration(d)
675 }
676}
677
678impl From<Option<Duration>> for Value {
679 fn from(d: Option<Duration>) -> Self {
680 if let Some(d) = d {
681 Value::TimeDuration(d)
682 } else {
683 Value::Empty
684 }
685 }
686}