1use crate::dataset::DataSet;
7use dicom_toolkit_core::error::{DcmError, DcmResult};
8use dicom_toolkit_dict::Tag;
9use std::fmt;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
17pub struct DicomDate {
18 pub year: u16,
19 pub month: u8,
21 pub day: u8,
23}
24
25impl DicomDate {
26 pub fn parse(s: &str) -> DcmResult<Self> {
28 let s = s.trim();
29 match s.len() {
30 4 => {
31 let year = parse_u16_str(&s[0..4])?;
32 Ok(Self {
33 year,
34 month: 0,
35 day: 0,
36 })
37 }
38 6 => {
39 let year = parse_u16_str(&s[0..4])?;
40 let month = parse_u8_str(&s[4..6])?;
41 Ok(Self {
42 year,
43 month,
44 day: 0,
45 })
46 }
47 8 => {
48 let year = parse_u16_str(&s[0..4])?;
49 let month = parse_u8_str(&s[4..6])?;
50 let day = parse_u8_str(&s[6..8])?;
51 Ok(Self { year, month, day })
52 }
53 _ => Err(DcmError::Other(format!("invalid DICOM date: {:?}", s))),
54 }
55 }
56
57 pub fn from_da_str(s: &str) -> DcmResult<Self> {
59 let s = s.trim();
60 if s.len() == 10 && s.as_bytes().get(4) == Some(&b'.') && s.as_bytes().get(7) == Some(&b'.')
61 {
62 let year = parse_u16_str(&s[0..4])?;
63 let month = parse_u8_str(&s[5..7])?;
64 let day = parse_u8_str(&s[8..10])?;
65 return Ok(Self { year, month, day });
66 }
67 Self::parse(s)
68 }
69}
70
71impl fmt::Display for DicomDate {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 if self.month == 0 {
74 write!(f, "{:04}", self.year)
75 } else if self.day == 0 {
76 write!(f, "{:04}{:02}", self.year, self.month)
77 } else {
78 write!(f, "{:04}{:02}{:02}", self.year, self.month, self.day)
79 }
80 }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub struct DicomTime {
91 pub hour: u8,
92 pub minute: u8,
93 pub second: u8,
94 pub fraction: u32,
96}
97
98impl DicomTime {
99 pub fn parse(s: &str) -> DcmResult<Self> {
101 let s = s.trim();
102 if s.is_empty() {
103 return Err(DcmError::Other("empty DICOM time string".into()));
104 }
105
106 let (time_part, fraction) = if let Some(dot_pos) = s.find('.') {
108 let frac_str = &s[dot_pos + 1..];
109 let mut padded = String::from(frac_str);
111 while padded.len() < 6 {
112 padded.push('0');
113 }
114 let frac = parse_u32_str(&padded[..6])?;
115 (&s[..dot_pos], frac)
116 } else {
117 (s, 0u32)
118 };
119
120 match time_part.len() {
121 2 => {
122 let hour = parse_u8_str(&time_part[0..2])?;
123 if hour > 23 {
124 return Err(DcmError::Other(format!(
125 "invalid hour in DICOM time: {hour}"
126 )));
127 }
128 Ok(Self {
129 hour,
130 minute: 0,
131 second: 0,
132 fraction: 0,
133 })
134 }
135 4 => {
136 let hour = parse_u8_str(&time_part[0..2])?;
137 let minute = parse_u8_str(&time_part[2..4])?;
138 if hour > 23 {
139 return Err(DcmError::Other(format!(
140 "invalid hour in DICOM time: {hour}"
141 )));
142 }
143 if minute > 59 {
144 return Err(DcmError::Other(format!(
145 "invalid minute in DICOM time: {minute}"
146 )));
147 }
148 Ok(Self {
149 hour,
150 minute,
151 second: 0,
152 fraction: 0,
153 })
154 }
155 6 => {
156 let hour = parse_u8_str(&time_part[0..2])?;
157 let minute = parse_u8_str(&time_part[2..4])?;
158 let second = parse_u8_str(&time_part[4..6])?;
159 if hour > 23 {
160 return Err(DcmError::Other(format!(
161 "invalid hour in DICOM time: {hour}"
162 )));
163 }
164 if minute > 59 {
165 return Err(DcmError::Other(format!(
166 "invalid minute in DICOM time: {minute}"
167 )));
168 }
169 if second > 59 {
170 return Err(DcmError::Other(format!(
171 "invalid second in DICOM time: {second}"
172 )));
173 }
174 Ok(Self {
175 hour,
176 minute,
177 second,
178 fraction,
179 })
180 }
181 _ => Err(DcmError::Other(format!("invalid DICOM time: {:?}", s))),
182 }
183 }
184}
185
186impl fmt::Display for DicomTime {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 write!(f, "{:02}{:02}{:02}", self.hour, self.minute, self.second)?;
189 if self.fraction > 0 {
190 write!(f, ".{:06}", self.fraction)?;
191 }
192 Ok(())
193 }
194}
195
196#[derive(Debug, Clone, PartialEq)]
200pub struct DicomDateTime {
201 pub date: DicomDate,
202 pub time: Option<DicomTime>,
203 pub offset_minutes: Option<i16>,
205}
206
207impl DicomDateTime {
208 pub fn parse(s: &str) -> DcmResult<Self> {
210 let s = s.trim();
211 if s.len() < 4 {
212 return Err(DcmError::Other(format!("invalid DICOM datetime: {:?}", s)));
213 }
214
215 let (dt_part, offset_minutes) = extract_tz_offset(s)?;
218
219 let date_len = dt_part.len().min(8);
221 let date_str = &dt_part[..date_len];
222 let date = DicomDate::parse(date_str)?;
224
225 let time = if dt_part.len() > 8 {
226 Some(DicomTime::parse(&dt_part[8..])?)
227 } else {
228 None
229 };
230
231 Ok(Self {
232 date,
233 time,
234 offset_minutes,
235 })
236 }
237}
238
239fn extract_tz_offset(s: &str) -> DcmResult<(&str, Option<i16>)> {
241 let bytes = s.as_bytes();
245 for i in (1..s.len()).rev() {
246 if bytes[i] == b'+' || bytes[i] == b'-' {
247 let tz_str = &s[i..];
248 if tz_str.len() == 5 {
249 let sign: i16 = if bytes[i] == b'+' { 1 } else { -1 };
250 let hh = parse_u8_str(&tz_str[1..3])? as i16;
251 let mm = parse_u8_str(&tz_str[3..5])? as i16;
252 return Ok((&s[..i], Some(sign * (hh * 60 + mm))));
253 }
254 }
255 }
256 Ok((s, None))
257}
258
259impl fmt::Display for DicomDateTime {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 write!(f, "{}", self.date)?;
262 if let Some(ref t) = self.time {
263 write!(f, "{}", t)?;
264 }
265 if let Some(offset) = self.offset_minutes {
266 let sign = if offset >= 0 { '+' } else { '-' };
267 let abs = offset.unsigned_abs();
268 write!(f, "{}{:02}{:02}", sign, abs / 60, abs % 60)?;
269 }
270 Ok(())
271 }
272}
273
274#[derive(Debug, Clone, PartialEq, Eq)]
282pub struct PersonName {
283 pub alphabetic: String,
284 pub ideographic: String,
285 pub phonetic: String,
286}
287
288impl PersonName {
289 pub fn parse(s: &str) -> Self {
291 let mut parts = s.splitn(3, '=');
292 PersonName {
293 alphabetic: parts.next().unwrap_or("").to_string(),
294 ideographic: parts.next().unwrap_or("").to_string(),
295 phonetic: parts.next().unwrap_or("").to_string(),
296 }
297 }
298
299 fn component(group: &str, index: usize) -> &str {
300 group.split('^').nth(index).unwrap_or("")
301 }
302
303 pub fn last_name(&self) -> &str {
304 Self::component(&self.alphabetic, 0)
305 }
306
307 pub fn first_name(&self) -> &str {
308 Self::component(&self.alphabetic, 1)
309 }
310
311 pub fn middle_name(&self) -> &str {
312 Self::component(&self.alphabetic, 2)
313 }
314
315 pub fn prefix(&self) -> &str {
316 Self::component(&self.alphabetic, 3)
317 }
318
319 pub fn suffix(&self) -> &str {
320 Self::component(&self.alphabetic, 4)
321 }
322}
323
324impl fmt::Display for PersonName {
325 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326 if !self.phonetic.is_empty() {
328 write!(
329 f,
330 "{}={}={}",
331 self.alphabetic, self.ideographic, self.phonetic
332 )
333 } else if !self.ideographic.is_empty() {
334 write!(f, "{}={}", self.alphabetic, self.ideographic)
335 } else {
336 write!(f, "{}", self.alphabetic)
337 }
338 }
339}
340
341#[derive(Debug, Clone, PartialEq)]
346pub enum PixelData {
347 Native { bytes: Vec<u8> },
349 Encapsulated {
351 offset_table: Vec<u32>,
352 fragments: Vec<Vec<u8>>,
353 },
354}
355
356#[derive(Debug, Clone, PartialEq)]
363pub enum Value {
364 Empty,
366 Strings(Vec<String>),
368 PersonNames(Vec<PersonName>),
370 Uid(String),
372 Date(Vec<DicomDate>),
374 Time(Vec<DicomTime>),
376 DateTime(Vec<DicomDateTime>),
378 Ints(Vec<i64>),
380 Decimals(Vec<f64>),
382 U8(Vec<u8>),
384 U16(Vec<u16>),
386 I16(Vec<i16>),
388 U32(Vec<u32>),
390 I32(Vec<i32>),
392 U64(Vec<u64>),
394 I64(Vec<i64>),
396 F32(Vec<f32>),
398 F64(Vec<f64>),
400 Tags(Vec<Tag>),
402 Sequence(Vec<DataSet>),
404 PixelData(PixelData),
406}
407
408impl Value {
409 pub fn multiplicity(&self) -> usize {
411 match self {
412 Value::Empty => 0,
413 Value::Strings(v) => v.len(),
414 Value::PersonNames(v) => v.len(),
415 Value::Uid(_) => 1,
416 Value::Date(v) => v.len(),
417 Value::Time(v) => v.len(),
418 Value::DateTime(v) => v.len(),
419 Value::Ints(v) => v.len(),
420 Value::Decimals(v) => v.len(),
421 Value::U8(v) => v.len(),
422 Value::U16(v) => v.len(),
423 Value::I16(v) => v.len(),
424 Value::U32(v) => v.len(),
425 Value::I32(v) => v.len(),
426 Value::U64(v) => v.len(),
427 Value::I64(v) => v.len(),
428 Value::F32(v) => v.len(),
429 Value::F64(v) => v.len(),
430 Value::Tags(v) => v.len(),
431 Value::Sequence(v) => v.len(),
432 Value::PixelData(_) => 1,
433 }
434 }
435
436 pub fn is_empty(&self) -> bool {
437 self.multiplicity() == 0
438 }
439
440 pub fn as_string(&self) -> Option<&str> {
442 match self {
443 Value::Strings(v) => v.first().map(|s| s.as_str()),
444 Value::Uid(s) => Some(s.as_str()),
445 Value::PersonNames(v) => v.first().map(|p| p.alphabetic.as_str()),
446 _ => None,
447 }
448 }
449
450 pub fn as_strings(&self) -> Option<&[String]> {
451 match self {
452 Value::Strings(v) => Some(v.as_slice()),
453 _ => None,
454 }
455 }
456
457 pub fn as_u16(&self) -> Option<u16> {
458 match self {
459 Value::U16(v) => v.first().copied(),
460 _ => None,
461 }
462 }
463
464 pub fn as_u32(&self) -> Option<u32> {
465 match self {
466 Value::U32(v) => v.first().copied(),
467 _ => None,
468 }
469 }
470
471 pub fn as_i32(&self) -> Option<i32> {
472 match self {
473 Value::I32(v) => v.first().copied(),
474 _ => None,
475 }
476 }
477
478 pub fn as_f64(&self) -> Option<f64> {
479 match self {
480 Value::F64(v) => v.first().copied(),
481 Value::Decimals(v) => v.first().copied(),
482 _ => None,
483 }
484 }
485
486 pub fn as_bytes(&self) -> Option<&[u8]> {
487 match self {
488 Value::U8(v) => Some(v.as_slice()),
489 Value::PixelData(PixelData::Native { bytes }) => Some(bytes.as_slice()),
490 _ => None,
491 }
492 }
493
494 pub fn to_display_string(&self) -> String {
496 match self {
497 Value::Empty => String::new(),
498 Value::Strings(v) => v.join("\\"),
499 Value::PersonNames(v) => v
500 .iter()
501 .map(|p| p.to_string())
502 .collect::<Vec<_>>()
503 .join("\\"),
504 Value::Uid(s) => s.clone(),
505 Value::Date(v) => v
506 .iter()
507 .map(|d| d.to_string())
508 .collect::<Vec<_>>()
509 .join("\\"),
510 Value::Time(v) => v
511 .iter()
512 .map(|t| t.to_string())
513 .collect::<Vec<_>>()
514 .join("\\"),
515 Value::DateTime(v) => v
516 .iter()
517 .map(|dt| dt.to_string())
518 .collect::<Vec<_>>()
519 .join("\\"),
520 Value::Ints(v) => v
521 .iter()
522 .map(|n| n.to_string())
523 .collect::<Vec<_>>()
524 .join("\\"),
525 Value::Decimals(v) => v
526 .iter()
527 .map(|n| format_f64(*n))
528 .collect::<Vec<_>>()
529 .join("\\"),
530 Value::U8(v) => format!("({} bytes)", v.len()),
531 Value::U16(v) => v
532 .iter()
533 .map(|n| n.to_string())
534 .collect::<Vec<_>>()
535 .join("\\"),
536 Value::I16(v) => v
537 .iter()
538 .map(|n| n.to_string())
539 .collect::<Vec<_>>()
540 .join("\\"),
541 Value::U32(v) => v
542 .iter()
543 .map(|n| n.to_string())
544 .collect::<Vec<_>>()
545 .join("\\"),
546 Value::I32(v) => v
547 .iter()
548 .map(|n| n.to_string())
549 .collect::<Vec<_>>()
550 .join("\\"),
551 Value::U64(v) => v
552 .iter()
553 .map(|n| n.to_string())
554 .collect::<Vec<_>>()
555 .join("\\"),
556 Value::I64(v) => v
557 .iter()
558 .map(|n| n.to_string())
559 .collect::<Vec<_>>()
560 .join("\\"),
561 Value::F32(v) => v
562 .iter()
563 .map(|n| format!("{}", n))
564 .collect::<Vec<_>>()
565 .join("\\"),
566 Value::F64(v) => v
567 .iter()
568 .map(|n| format_f64(*n))
569 .collect::<Vec<_>>()
570 .join("\\"),
571 Value::Tags(v) => v
572 .iter()
573 .map(|t| format!("({:04X},{:04X})", t.group, t.element))
574 .collect::<Vec<_>>()
575 .join("\\"),
576 Value::Sequence(v) => format!("(Sequence with {} item(s))", v.len()),
577 Value::PixelData(PixelData::Native { bytes }) => {
578 format!("(PixelData, {} bytes)", bytes.len())
579 }
580 Value::PixelData(PixelData::Encapsulated { fragments, .. }) => {
581 format!("(PixelData, {} fragment(s))", fragments.len())
582 }
583 }
584 }
585
586 pub(crate) fn encoded_len(&self) -> usize {
588 match self {
589 Value::Empty => 0,
590 Value::Strings(v) => {
591 let total: usize = v.iter().map(|s| s.len()).sum();
592 total + v.len().saturating_sub(1)
593 }
594 Value::PersonNames(v) => {
595 let total: usize = v.iter().map(|p| p.to_string().len()).sum();
596 total + v.len().saturating_sub(1)
597 }
598 Value::Uid(s) => s.len(),
599 Value::Date(v) => v.len() * 8,
600 Value::Time(v) => v.len() * 14,
601 Value::DateTime(v) => v.len() * 26,
602 Value::Ints(v) => {
603 v.iter().map(|n| n.to_string().len()).sum::<usize>() + v.len().saturating_sub(1)
604 }
605 Value::Decimals(v) => {
606 v.iter().map(|n| format_f64(*n).len()).sum::<usize>() + v.len().saturating_sub(1)
607 }
608 Value::U8(v) => v.len(),
609 Value::U16(v) => v.len() * 2,
610 Value::I16(v) => v.len() * 2,
611 Value::U32(v) => v.len() * 4,
612 Value::I32(v) => v.len() * 4,
613 Value::U64(v) => v.len() * 8,
614 Value::I64(v) => v.len() * 8,
615 Value::F32(v) => v.len() * 4,
616 Value::F64(v) => v.len() * 8,
617 Value::Tags(v) => v.len() * 4,
618 Value::Sequence(_) => 0,
619 Value::PixelData(PixelData::Native { bytes }) => bytes.len(),
620 Value::PixelData(PixelData::Encapsulated { fragments, .. }) => {
621 fragments.iter().map(|f| f.len()).sum()
622 }
623 }
624 }
625}
626
627fn parse_u8_str(s: &str) -> DcmResult<u8> {
630 s.parse::<u8>()
631 .map_err(|_| DcmError::Other(format!("expected u8, got {:?}", s)))
632}
633
634fn parse_u16_str(s: &str) -> DcmResult<u16> {
635 s.parse::<u16>()
636 .map_err(|_| DcmError::Other(format!("expected u16, got {:?}", s)))
637}
638
639fn parse_u32_str(s: &str) -> DcmResult<u32> {
640 s.parse::<u32>()
641 .map_err(|_| DcmError::Other(format!("expected u32, got {:?}", s)))
642}
643
644fn format_f64(v: f64) -> String {
646 if v.fract() == 0.0 && v.abs() < 1e15 {
647 format!("{:.1}", v)
648 } else {
649 format!("{}", v)
650 }
651}
652
653#[cfg(test)]
656mod tests {
657 use super::*;
658
659 #[test]
662 fn date_full_parse() {
663 let d = DicomDate::parse("20231215").unwrap();
664 assert_eq!(d.year, 2023);
665 assert_eq!(d.month, 12);
666 assert_eq!(d.day, 15);
667 }
668
669 #[test]
670 fn date_year_only() {
671 let d = DicomDate::parse("2023").unwrap();
672 assert_eq!(d.year, 2023);
673 assert_eq!(d.month, 0);
674 assert_eq!(d.day, 0);
675 }
676
677 #[test]
678 fn date_year_month() {
679 let d = DicomDate::parse("202312").unwrap();
680 assert_eq!(d.year, 2023);
681 assert_eq!(d.month, 12);
682 assert_eq!(d.day, 0);
683 }
684
685 #[test]
686 fn date_display_full() {
687 let d = DicomDate {
688 year: 2023,
689 month: 12,
690 day: 15,
691 };
692 assert_eq!(d.to_string(), "20231215");
693 }
694
695 #[test]
696 fn date_display_partial_year() {
697 let d = DicomDate {
698 year: 2023,
699 month: 0,
700 day: 0,
701 };
702 assert_eq!(d.to_string(), "2023");
703 }
704
705 #[test]
706 fn date_display_partial_year_month() {
707 let d = DicomDate {
708 year: 2023,
709 month: 12,
710 day: 0,
711 };
712 assert_eq!(d.to_string(), "202312");
713 }
714
715 #[test]
716 fn date_legacy_format() {
717 let d = DicomDate::from_da_str("2023.12.15").unwrap();
718 assert_eq!(d.year, 2023);
719 assert_eq!(d.month, 12);
720 assert_eq!(d.day, 15);
721 }
722
723 #[test]
724 fn date_invalid() {
725 assert!(DicomDate::parse("20231").is_err());
726 assert!(DicomDate::parse("2023121").is_err());
727 assert!(DicomDate::parse("abcdefgh").is_err());
728 }
729
730 #[test]
733 fn time_full_parse() {
734 let t = DicomTime::parse("143022.500000").unwrap();
735 assert_eq!(t.hour, 14);
736 assert_eq!(t.minute, 30);
737 assert_eq!(t.second, 22);
738 assert_eq!(t.fraction, 500000);
739 }
740
741 #[test]
742 fn time_partial_hour() {
743 let t = DicomTime::parse("14").unwrap();
744 assert_eq!(t.hour, 14);
745 assert_eq!(t.minute, 0);
746 assert_eq!(t.second, 0);
747 assert_eq!(t.fraction, 0);
748 }
749
750 #[test]
751 fn time_partial_hour_minute() {
752 let t = DicomTime::parse("1430").unwrap();
753 assert_eq!(t.hour, 14);
754 assert_eq!(t.minute, 30);
755 assert_eq!(t.second, 0);
756 }
757
758 #[test]
759 fn time_partial_no_fraction() {
760 let t = DicomTime::parse("143022").unwrap();
761 assert_eq!(t.hour, 14);
762 assert_eq!(t.minute, 30);
763 assert_eq!(t.second, 22);
764 assert_eq!(t.fraction, 0);
765 }
766
767 #[test]
768 fn time_fraction_short() {
769 let t = DicomTime::parse("143022.5").unwrap();
771 assert_eq!(t.fraction, 500000);
772 }
773
774 #[test]
775 fn time_display() {
776 let t = DicomTime {
777 hour: 14,
778 minute: 30,
779 second: 22,
780 fraction: 500000,
781 };
782 assert_eq!(t.to_string(), "143022.500000");
783 }
784
785 #[test]
786 fn time_display_no_fraction() {
787 let t = DicomTime {
788 hour: 14,
789 minute: 30,
790 second: 22,
791 fraction: 0,
792 };
793 assert_eq!(t.to_string(), "143022");
794 }
795
796 #[test]
799 fn datetime_full_parse() {
800 let dt = DicomDateTime::parse("20231215143022.000000+0530").unwrap();
801 assert_eq!(dt.date.year, 2023);
802 assert_eq!(dt.date.month, 12);
803 assert_eq!(dt.date.day, 15);
804 let t = dt.time.unwrap();
805 assert_eq!(t.hour, 14);
806 assert_eq!(t.minute, 30);
807 assert_eq!(t.second, 22);
808 assert_eq!(dt.offset_minutes, Some(330)); }
810
811 #[test]
812 fn datetime_negative_offset() {
813 let dt = DicomDateTime::parse("20231215143022.000000-0500").unwrap();
814 assert_eq!(dt.offset_minutes, Some(-300));
815 }
816
817 #[test]
818 fn datetime_no_time() {
819 let dt = DicomDateTime::parse("20231215").unwrap();
820 assert_eq!(dt.date.year, 2023);
821 assert!(dt.time.is_none());
822 assert!(dt.offset_minutes.is_none());
823 }
824
825 #[test]
826 fn datetime_display_roundtrip() {
827 let s = "20231215143022.500000+0530";
829 let dt = DicomDateTime::parse(s).unwrap();
830 assert_eq!(dt.to_string(), s);
831 }
832
833 #[test]
834 fn datetime_display_roundtrip_no_fraction() {
835 let s = "20231215143022+0530";
837 let dt = DicomDateTime::parse(s).unwrap();
838 assert_eq!(dt.to_string(), s);
839 }
840
841 #[test]
844 fn pn_simple() {
845 let pn = PersonName::parse("Eichelberg^Marco^^Dr.");
846 assert_eq!(pn.last_name(), "Eichelberg");
847 assert_eq!(pn.first_name(), "Marco");
848 assert_eq!(pn.middle_name(), "");
849 assert_eq!(pn.prefix(), "Dr.");
850 assert_eq!(pn.suffix(), "");
851 }
852
853 #[test]
854 fn pn_multi_component() {
855 let pn = PersonName::parse("Smith^John=\u{5C71}\u{7530}^\u{592A}\u{90CE}=\u{3084}\u{307E}\u{3060}^\u{305F}\u{308D}\u{3046}");
856 assert_eq!(pn.last_name(), "Smith");
857 assert_eq!(pn.first_name(), "John");
858 assert!(!pn.ideographic.is_empty());
859 assert!(!pn.phonetic.is_empty());
860 }
861
862 #[test]
863 fn pn_display_single_group() {
864 let pn = PersonName::parse("Smith^John");
865 assert_eq!(pn.to_string(), "Smith^John");
866 }
867
868 #[test]
869 fn pn_display_two_groups() {
870 let pn = PersonName::parse("Smith^John=SJ");
871 assert_eq!(pn.to_string(), "Smith^John=SJ");
872 }
873
874 #[test]
877 fn value_multiplicity() {
878 assert_eq!(Value::Empty.multiplicity(), 0);
879 assert_eq!(
880 Value::Strings(vec!["a".into(), "b".into()]).multiplicity(),
881 2
882 );
883 assert_eq!(Value::U16(vec![1, 2, 3]).multiplicity(), 3);
884 assert_eq!(Value::Uid("1.2.3".into()).multiplicity(), 1);
885 assert_eq!(Value::Sequence(vec![]).multiplicity(), 0);
886 }
887
888 #[test]
889 fn value_is_empty() {
890 assert!(Value::Empty.is_empty());
891 assert!(Value::Strings(vec![]).is_empty());
892 assert!(!Value::Strings(vec!["x".into()]).is_empty());
893 }
894
895 #[test]
896 fn value_as_string() {
897 let v = Value::Strings(vec!["hello".into(), "world".into()]);
898 assert_eq!(v.as_string(), Some("hello"));
899 assert_eq!(v.as_strings().unwrap().len(), 2);
900 }
901
902 #[test]
903 fn value_as_uid() {
904 let v = Value::Uid("1.2.840.10008.1.1".into());
905 assert_eq!(v.as_string(), Some("1.2.840.10008.1.1"));
906 }
907
908 #[test]
909 fn value_as_numeric() {
910 let v = Value::U16(vec![512]);
911 assert_eq!(v.as_u16(), Some(512));
912
913 let v = Value::U32(vec![65536]);
914 assert_eq!(v.as_u32(), Some(65536));
915
916 let v = Value::I32(vec![-1]);
917 assert_eq!(v.as_i32(), Some(-1));
918
919 let v = Value::F64(vec![2.78]);
920 assert_eq!(v.as_f64(), Some(2.78));
921 }
922
923 #[test]
924 fn value_to_display_string_strings() {
925 let v = Value::Strings(vec!["foo".into(), "bar".into()]);
926 assert_eq!(v.to_display_string(), "foo\\bar");
927 }
928
929 #[test]
930 fn value_to_display_string_u16() {
931 let v = Value::U16(vec![512, 256]);
932 assert_eq!(v.to_display_string(), "512\\256");
933 }
934
935 #[test]
936 fn value_to_display_string_sequence() {
937 let v = Value::Sequence(vec![]);
938 assert_eq!(v.to_display_string(), "(Sequence with 0 item(s))");
939 }
940
941 #[test]
942 fn value_as_bytes() {
943 let v = Value::U8(vec![1, 2, 3]);
944 assert_eq!(v.as_bytes(), Some(&[1u8, 2, 3][..]));
945 }
946}