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 for t in v {
334 if !buf.is_empty() {
335 buf.push('\n');
336 }
337 t.extract_text(&mut buf);
338 }
339 Cow::from(buf)
340 }
341 _ => Cow::from(d),
342 }
343 }
344
345 pub fn as_str_opt(&self) -> Option<&str> {
347 match self {
348 Value::Text(s) => Some(s.as_ref()),
349 _ => None,
350 }
351 }
352
353 pub fn as_string_or_default(&self) -> String {
355 self.as_string_opt().unwrap_or_default()
356 }
357
358 pub fn as_string_opt(&self) -> Option<String> {
360 match self {
361 Value::Text(s) => Some(s.clone()),
362 _ => None,
363 }
364 }
365
366 pub fn as_timeduration_or_default(&self) -> Duration {
369 self.as_timeduration_opt().unwrap_or_default()
370 }
371
372 pub fn as_timeduration_or(&self, d: Duration) -> Duration {
375 self.as_timeduration_opt().unwrap_or(d)
376 }
377
378 pub fn as_timeduration_opt(&self) -> Option<Duration> {
381 match self {
382 Value::TimeDuration(td) => Some(*td),
383 _ => None,
384 }
385 }
386
387 pub fn as_datetime_or_default(&self) -> NaiveDateTime {
390 self.as_datetime_opt().unwrap_or_default()
391 }
392
393 pub fn as_datetime_or(&self, d: NaiveDateTime) -> NaiveDateTime {
396 self.as_datetime_opt().unwrap_or(d)
397 }
398
399 pub fn as_datetime_opt(&self) -> Option<NaiveDateTime> {
402 match self {
403 Value::DateTime(dt) => Some(*dt),
404 _ => None,
405 }
406 }
407
408 pub fn as_date_or_default(&self) -> NaiveDate {
411 self.as_date_opt().unwrap_or_default()
412 }
413
414 pub fn as_date_or(&self, d: NaiveDate) -> NaiveDate {
417 self.as_date_opt().unwrap_or(d)
418 }
419
420 pub fn as_date_opt(&self) -> Option<NaiveDate> {
423 match self {
424 Value::DateTime(dt) => Some(dt.date()),
425 _ => None,
426 }
427 }
428
429 pub fn currency(&self) -> &str {
431 match self {
432 Value::Currency(_, c) => c,
433 _ => "",
434 }
435 }
436
437 #[allow(clippy::needless_range_loop)]
439 pub fn new_currency<S: AsRef<str>>(cur: S, value: f64) -> Self {
440 Value::Currency(value, cur.as_ref().into())
441 }
442
443 pub fn new_percentage(value: f64) -> Self {
445 Value::Percentage(value)
446 }
447}
448
449#[macro_export]
451macro_rules! currency {
452 ($c:expr, $v:expr) => {
453 Value::new_currency($c, $v as f64)
454 };
455}
456
457#[macro_export]
459macro_rules! percent {
460 ($v:expr) => {
461 Value::new_percentage($v)
462 };
463}
464
465impl From<()> for Value {
466 fn from(_: ()) -> Self {
467 Value::Empty
468 }
469}
470
471impl From<&str> for Value {
472 fn from(s: &str) -> Self {
473 Value::Text(s.to_string())
474 }
475}
476
477impl From<String> for Value {
478 fn from(s: String) -> Self {
479 Value::Text(s)
480 }
481}
482
483impl From<&String> for Value {
484 fn from(s: &String) -> Self {
485 Value::Text(s.to_string())
486 }
487}
488
489impl From<TextTag> for Value {
490 fn from(t: TextTag) -> Self {
491 Value::TextXml(vec![t])
492 }
493}
494
495impl From<Vec<TextTag>> for Value {
496 fn from(t: Vec<TextTag>) -> Self {
497 Value::TextXml(t)
498 }
499}
500
501impl From<Option<&str>> for Value {
502 fn from(s: Option<&str>) -> Self {
503 if let Some(s) = s {
504 Value::Text(s.to_string())
505 } else {
506 Value::Empty
507 }
508 }
509}
510
511impl From<Option<&String>> for Value {
512 fn from(s: Option<&String>) -> Self {
513 if let Some(s) = s {
514 Value::Text(s.to_string())
515 } else {
516 Value::Empty
517 }
518 }
519}
520
521impl From<Option<String>> for Value {
522 fn from(s: Option<String>) -> Self {
523 if let Some(s) = s {
524 Value::Text(s)
525 } else {
526 Value::Empty
527 }
528 }
529}
530
531#[cfg(feature = "rust_decimal")]
532impl From<Decimal> for Value {
533 fn from(f: Decimal) -> Self {
534 Value::Number(f.to_f64().expect("decimal->f64 should not fail"))
535 }
536}
537
538#[cfg(feature = "rust_decimal")]
539impl From<Option<Decimal>> for Value {
540 fn from(f: Option<Decimal>) -> Self {
541 if let Some(f) = f {
542 Value::Number(f.to_f64().expect("decimal->f64 should not fail"))
543 } else {
544 Value::Empty
545 }
546 }
547}
548
549macro_rules! from_number {
550 ($l:ty) => {
551 impl From<$l> for Value {
552 #![allow(trivial_numeric_casts)]
553 fn from(f: $l) -> Self {
554 Value::Number(f as f64)
555 }
556 }
557
558 impl From<&$l> for Value {
559 #![allow(trivial_numeric_casts)]
560 fn from(f: &$l) -> Self {
561 Value::Number(*f as f64)
562 }
563 }
564
565 impl From<Option<$l>> for Value {
566 #![allow(trivial_numeric_casts)]
567 fn from(f: Option<$l>) -> Self {
568 if let Some(f) = f {
569 Value::Number(f as f64)
570 } else {
571 Value::Empty
572 }
573 }
574 }
575
576 impl From<Option<&$l>> for Value {
577 #![allow(trivial_numeric_casts)]
578 fn from(f: Option<&$l>) -> Self {
579 if let Some(f) = f {
580 Value::Number(*f as f64)
581 } else {
582 Value::Empty
583 }
584 }
585 }
586 };
587}
588
589from_number!(f64);
590from_number!(f32);
591from_number!(i64);
592from_number!(i32);
593from_number!(i16);
594from_number!(i8);
595from_number!(u64);
596from_number!(u32);
597from_number!(u16);
598from_number!(u8);
599
600impl From<bool> for Value {
601 fn from(b: bool) -> Self {
602 Value::Boolean(b)
603 }
604}
605
606impl From<Option<bool>> for Value {
607 fn from(b: Option<bool>) -> Self {
608 if let Some(b) = b {
609 Value::Boolean(b)
610 } else {
611 Value::Empty
612 }
613 }
614}
615
616impl From<NaiveDateTime> for Value {
617 fn from(dt: NaiveDateTime) -> Self {
618 Value::DateTime(dt)
619 }
620}
621
622impl From<Option<NaiveDateTime>> for Value {
623 fn from(dt: Option<NaiveDateTime>) -> Self {
624 if let Some(dt) = dt {
625 Value::DateTime(dt)
626 } else {
627 Value::Empty
628 }
629 }
630}
631
632impl From<NaiveDate> for Value {
633 fn from(dt: NaiveDate) -> Self {
634 Value::DateTime(dt.and_hms_opt(0, 0, 0).unwrap())
635 }
636}
637
638impl From<Option<NaiveDate>> for Value {
639 fn from(dt: Option<NaiveDate>) -> Self {
640 if let Some(dt) = dt {
641 Value::DateTime(dt.and_hms_opt(0, 0, 0).expect("valid time"))
642 } else {
643 Value::Empty
644 }
645 }
646}
647
648impl From<NaiveTime> for Value {
649 fn from(ti: NaiveTime) -> Self {
650 Value::DateTime(NaiveDateTime::new(
651 NaiveDate::from_ymd_opt(1899, 12, 30).expect("valid date"),
652 ti,
653 ))
654 }
655}
656
657impl From<Option<NaiveTime>> for Value {
658 fn from(dt: Option<NaiveTime>) -> Self {
659 if let Some(ti) = dt {
660 Value::DateTime(NaiveDateTime::new(
661 NaiveDate::from_ymd_opt(1899, 12, 30).expect("valid date"),
662 ti,
663 ))
664 } else {
665 Value::Empty
666 }
667 }
668}
669
670impl From<Duration> for Value {
671 fn from(d: Duration) -> Self {
672 Value::TimeDuration(d)
673 }
674}
675
676impl From<Option<Duration>> for Value {
677 fn from(d: Option<Duration>) -> Self {
678 if let Some(d) = d {
679 Value::TimeDuration(d)
680 } else {
681 Value::Empty
682 }
683 }
684}