dicom_core/value/
primitive.rs

1//! Declaration and implementation of a DICOM primitive value.
2//!
3//! See [`PrimitiveValue`](./enum.PrimitiveValue.html).
4
5use super::{AsRange, DicomValueType};
6use crate::header::{HasLength, Length, Tag};
7use crate::value::partial::{DateComponent, DicomDate, DicomDateTime, DicomTime};
8use crate::value::person_name::PersonName;
9use crate::value::range::{AmbiguousDtRangeParser, DateRange, DateTimeRange, TimeRange};
10use itertools::Itertools;
11use num_traits::NumCast;
12use safe_transmute::to_bytes::transmute_to_bytes;
13use smallvec::SmallVec;
14use snafu::{Backtrace, ResultExt, Snafu};
15use std::borrow::Cow;
16use std::fmt::{self, Display};
17use std::str::FromStr;
18
19/// Triggered when a value reading attempt fails.
20#[derive(Debug, Snafu)]
21#[non_exhaustive]
22pub enum InvalidValueReadError {
23    /// Attempted to retrieve a complex value as primitive.
24    #[snafu(display("Sequence cannot be read as a primitive value"))]
25    NonPrimitiveType { backtrace: Backtrace },
26    /// Invalid or ambiguous combination of date with time.
27    #[snafu(display("Invalid or ambiguous combination of date with time"))]
28    DateTimeZone { backtrace: Backtrace },
29    /// The value cannot be parsed to a floating point number.
30    #[snafu(display("Failed to read text as a floating point number"))]
31    ParseFloat {
32        backtrace: Backtrace,
33        source: std::num::ParseFloatError,
34    },
35    /// The value cannot be parsed to an integer.
36    #[snafu(display("Failed to read text as an integer"))]
37    ParseInteger {
38        backtrace: Backtrace,
39        source: std::num::ParseIntError,
40    },
41    /// An attempt of reading more than the number of bytes in the length attribute was made.
42    #[snafu(display("Unexpected end of element"))]
43    UnexpectedEndOfElement {},
44    /// The value cannot be converted to the target type requested.
45    #[snafu(display("Cannot convert `{}` to the target type requested", value))]
46    NarrowConvert { value: String, backtrace: Backtrace },
47    #[snafu(display("Failed to read text as a date"))]
48    ParseDate {
49        #[snafu(backtrace)]
50        source: crate::value::deserialize::Error,
51    },
52    #[snafu(display("Failed to read text as a time"))]
53    ParseTime {
54        #[snafu(backtrace)]
55        source: crate::value::deserialize::Error,
56    },
57    #[snafu(display("Failed to read text as a date-time"))]
58    ParseDateTime {
59        #[snafu(backtrace)]
60        source: crate::value::deserialize::Error,
61    },
62    #[snafu(display("Failed to convert into a DicomDate"))]
63    IntoDicomDate {
64        #[snafu(backtrace)]
65        source: crate::value::partial::Error,
66    },
67    #[snafu(display("Failed to convert into a DicomTime"))]
68    IntoDicomTime {
69        #[snafu(backtrace)]
70        source: crate::value::partial::Error,
71    },
72    #[snafu(display("Failed to convert into a DicomDateTime"))]
73    IntoDicomDateTime {
74        #[snafu(backtrace)]
75        source: crate::value::partial::Error,
76    },
77    #[snafu(display("Failed to read text as a date range"))]
78    ParseDateRange {
79        #[snafu(backtrace)]
80        source: crate::value::range::Error,
81    },
82    #[snafu(display("Failed to read text as a time range"))]
83    ParseTimeRange {
84        #[snafu(backtrace)]
85        source: crate::value::range::Error,
86    },
87    #[snafu(display("Failed to read text as a date-time range"))]
88    ParseDateTimeRange {
89        #[snafu(backtrace)]
90        source: crate::value::range::Error,
91    },
92}
93
94/// Error type for a failed attempt to modify an existing DICOM primitive value.
95#[derive(Debug, Snafu)]
96#[non_exhaustive]
97pub enum ModifyValueError {
98    /// The modification using strings cannot proceed
99    /// due to the value's current type,
100    /// as that would lead to mixed representations.
101    #[snafu(display("cannot not modify {:?} value as string values", original))]
102    IncompatibleStringType { original: ValueType },
103
104    /// The modification using numbers cannot proceed
105    /// due to the value's current type,
106    /// as that would lead to mixed representations.
107    #[snafu(display("cannot not modify {:?} value as numeric values", original))]
108    IncompatibleNumberType { original: ValueType },
109}
110
111/// An error type for an attempt of accessing a value
112/// in one internal representation as another.
113///
114/// This error is raised whenever it is not possible to retrieve the requested
115/// value, either because the inner representation is not compatible with the
116/// requested value type, or a conversion would be required. In other words,
117/// if a reference to the inner value cannot be obtained with
118/// the requested target type (for example, retrieving a date from a string),
119/// an error of this type is returned.
120///
121/// If such a conversion is acceptable, please use conversion methods instead:
122/// `to_date` instead of `date`, `to_str` instead of `string`, and so on.
123/// The error type would then be [`ConvertValueError`].
124///
125/// [`ConvertValueError`]: ./struct.ConvertValueError.html
126#[derive(Debug, Clone, PartialEq)]
127pub struct CastValueError {
128    /// The value format requested
129    pub requested: &'static str,
130    /// The value's actual representation
131    pub got: ValueType,
132}
133
134impl Display for CastValueError {
135    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136        write!(
137            f,
138            "bad value cast: requested {} but value is {:?}",
139            self.requested, self.got
140        )
141    }
142}
143
144impl std::error::Error for CastValueError {}
145
146/// An error type for a failed attempt at converting a value
147/// into another representation.
148#[derive(Debug)]
149pub struct ConvertValueError {
150    /// The value format requested
151    pub requested: &'static str,
152    /// The value's original representation
153    pub original: ValueType,
154    /// The reason why the conversion was unsuccessful,
155    /// or none if a conversion from the given original representation
156    /// is not possible
157    pub cause: Option<Box<InvalidValueReadError>>,
158}
159
160impl Display for ConvertValueError {
161    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162        write!(
163            f,
164            "could not convert {:?} to a {}: ",
165            self.original, self.requested
166        )?;
167        if let Some(cause) = &self.cause {
168            write!(f, "{}", cause)?;
169        } else {
170            write!(f, "conversion not possible")?;
171        }
172        Ok(())
173    }
174}
175
176impl std::error::Error for ConvertValueError {
177    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
178        self.cause.as_ref().map(|x| x as _)
179    }
180}
181
182pub type Result<T, E = InvalidValueReadError> = std::result::Result<T, E>;
183
184// Re-exported from chrono
185pub use chrono::{NaiveDate, NaiveTime};
186
187/// An aggregation of one or more elements in a value.
188pub type C<T> = SmallVec<[T; 2]>;
189
190/// An enum representing a primitive value from a DICOM element.
191/// The result of decoding an element's data value
192/// may be one of the enumerated types
193/// depending on its content and value representation.
194///
195/// Multiple elements are contained in a [`smallvec`] vector,
196/// conveniently aliased to the type [`C`].
197///
198/// See the macro [`dicom_value!`] for a more intuitive means
199/// of constructing these values.
200/// Alternatively, `From` conversions into `PrimitiveValue` exist
201/// for single element types,
202/// including numeric types, `String`, and `&str`.
203///
204/// # Example
205///
206/// ```
207/// # use dicom_core::PrimitiveValue;
208/// # use smallvec::smallvec;
209/// let value = PrimitiveValue::from("Smith^John");
210/// assert_eq!(value, PrimitiveValue::Str("Smith^John".to_string()));
211/// assert_eq!(value.multiplicity(), 1);
212///
213/// let value = PrimitiveValue::from(512_u16);
214/// assert_eq!(value, PrimitiveValue::U16(smallvec![512]));
215/// ```
216///
217/// [`smallvec`]: ../../smallvec/index.html
218/// [`C`]: ./type.C.html
219/// [`dicom_value!`]: ../macro.dicom_value.html
220#[derive(Debug, Clone)]
221pub enum PrimitiveValue {
222    /// No data. Usually employed for zero-length values.
223    Empty,
224
225    /// A sequence of strings.
226    /// Used for AE, AS, PN, SH, CS, LO, UI and UC.
227    /// Can also be used for IS, SS, DS, DA, DT and TM when decoding
228    /// with format preservation.
229    Strs(C<String>),
230
231    /// A single string.
232    /// Used for ST, LT, UT and UR, which are never multi-valued.
233    Str(String),
234
235    /// A sequence of attribute tags.
236    /// Used specifically for AT.
237    Tags(C<Tag>),
238
239    /// The value is a sequence of unsigned 8-bit integers.
240    /// Used for OB and UN.
241    U8(C<u8>),
242
243    /// The value is a sequence of signed 16-bit integers.
244    /// Used for SS.
245    I16(C<i16>),
246
247    /// A sequence of unsigned 16-bit integers.
248    /// Used for US and OW.
249    U16(C<u16>),
250
251    /// A sequence of signed 32-bit integers.
252    /// Used for SL and IS.
253    I32(C<i32>),
254
255    /// A sequence of unsigned 32-bit integers.
256    /// Used for UL and OL.
257    U32(C<u32>),
258
259    /// A sequence of signed 64-bit integers.
260    /// Used for SV.
261    I64(C<i64>),
262
263    /// A sequence of unsigned 64-bit integers.
264    /// Used for UV and OV.
265    U64(C<u64>),
266
267    /// The value is a sequence of 32-bit floating point numbers.
268    /// Used for OF and FL.
269    F32(C<f32>),
270
271    /// The value is a sequence of 64-bit floating point numbers.
272    /// Used for OD and FD, DS.
273    F64(C<f64>),
274
275    /// A sequence of dates with arbitrary precision.
276    /// Used for the DA representation.
277    Date(C<DicomDate>),
278
279    /// A sequence of date-time values with arbitrary precision.
280    /// Used for the DT representation.
281    DateTime(C<DicomDateTime>),
282
283    /// A sequence of time values with arbitrary precision.
284    /// Used for the TM representation.
285    Time(C<DicomTime>),
286}
287
288/// A utility macro for implementing the conversion from a core type into a
289/// DICOM primitive value with a single element.
290macro_rules! impl_from_for_primitive {
291    ($typ: ty, $variant: ident) => {
292        impl From<$typ> for PrimitiveValue {
293            fn from(value: $typ) -> Self {
294                PrimitiveValue::$variant(C::from_elem(value, 1))
295            }
296        }
297    };
298}
299
300impl_from_for_primitive!(u8, U8);
301impl_from_for_primitive!(u16, U16);
302impl_from_for_primitive!(i16, I16);
303impl_from_for_primitive!(u32, U32);
304impl_from_for_primitive!(i32, I32);
305impl_from_for_primitive!(u64, U64);
306impl_from_for_primitive!(i64, I64);
307impl_from_for_primitive!(f32, F32);
308impl_from_for_primitive!(f64, F64);
309
310impl_from_for_primitive!(Tag, Tags);
311impl_from_for_primitive!(DicomDate, Date);
312impl_from_for_primitive!(DicomTime, Time);
313impl_from_for_primitive!(DicomDateTime, DateTime);
314
315impl From<String> for PrimitiveValue {
316    fn from(value: String) -> Self {
317        PrimitiveValue::Str(value)
318    }
319}
320
321impl From<&str> for PrimitiveValue {
322    fn from(value: &str) -> Self {
323        PrimitiveValue::Str(value.to_owned())
324    }
325}
326
327impl From<Vec<u8>> for PrimitiveValue {
328    fn from(value: Vec<u8>) -> Self {
329        PrimitiveValue::U8(C::from(value))
330    }
331}
332
333impl From<&[u8]> for PrimitiveValue {
334    fn from(value: &[u8]) -> Self {
335        PrimitiveValue::U8(C::from(value))
336    }
337}
338
339impl From<PersonName<'_>> for PrimitiveValue {
340    fn from(p: PersonName) -> Self {
341        PrimitiveValue::Str(p.to_dicom_string())
342    }
343}
344
345impl From<()> for PrimitiveValue {
346    /// constructs an empty DICOM value
347    #[inline]
348    fn from(_value: ()) -> Self {
349        PrimitiveValue::Empty
350    }
351}
352
353macro_rules! impl_from_array_for_primitive {
354    ($typ: ty, $variant: ident) => {
355        impl From<$typ> for PrimitiveValue {
356            fn from(value: $typ) -> Self {
357                PrimitiveValue::$variant(C::from_slice(&value[..]))
358            }
359        }
360    };
361}
362
363macro_rules! impl_from_array_for_primitive_1_to_8 {
364    ($typ: ty, $variant: ident) => {
365        impl_from_array_for_primitive!([$typ; 1], $variant);
366        impl_from_array_for_primitive!([$typ; 2], $variant);
367        impl_from_array_for_primitive!([$typ; 3], $variant);
368        impl_from_array_for_primitive!([$typ; 4], $variant);
369        impl_from_array_for_primitive!([$typ; 5], $variant);
370        impl_from_array_for_primitive!([$typ; 6], $variant);
371        impl_from_array_for_primitive!([$typ; 7], $variant);
372        impl_from_array_for_primitive!([$typ; 8], $variant);
373        impl_from_array_for_primitive!(&[$typ; 1], $variant);
374        impl_from_array_for_primitive!(&[$typ; 2], $variant);
375        impl_from_array_for_primitive!(&[$typ; 3], $variant);
376        impl_from_array_for_primitive!(&[$typ; 4], $variant);
377        impl_from_array_for_primitive!(&[$typ; 5], $variant);
378        impl_from_array_for_primitive!(&[$typ; 6], $variant);
379        impl_from_array_for_primitive!(&[$typ; 7], $variant);
380        impl_from_array_for_primitive!(&[$typ; 8], $variant);
381    };
382}
383
384impl_from_array_for_primitive_1_to_8!(u8, U8);
385impl_from_array_for_primitive_1_to_8!(u16, U16);
386impl_from_array_for_primitive_1_to_8!(i16, I16);
387impl_from_array_for_primitive_1_to_8!(u32, U32);
388impl_from_array_for_primitive_1_to_8!(i32, I32);
389impl_from_array_for_primitive_1_to_8!(u64, U64);
390impl_from_array_for_primitive_1_to_8!(i64, I64);
391impl_from_array_for_primitive_1_to_8!(f32, F32);
392impl_from_array_for_primitive_1_to_8!(f64, F64);
393impl_from_array_for_primitive_1_to_8!(DicomDate, Date);
394impl_from_array_for_primitive_1_to_8!(DicomTime, Time);
395impl_from_array_for_primitive_1_to_8!(DicomDateTime, DateTime);
396
397impl PrimitiveValue {
398    /// Create a single unsigned 16-bit value.
399    pub fn new_u16(value: u16) -> Self {
400        PrimitiveValue::U16(C::from_elem(value, 1))
401    }
402
403    /// Create a single unsigned 32-bit value.
404    pub fn new_u32(value: u32) -> Self {
405        PrimitiveValue::U32(C::from_elem(value, 1))
406    }
407
408    /// Create a single I32 value.
409    pub fn new_i32(value: i32) -> Self {
410        PrimitiveValue::I32(C::from_elem(value, 1))
411    }
412
413    /// Obtain the number of individual elements. This number may not
414    /// match the DICOM value multiplicity in some value representations.
415    pub fn multiplicity(&self) -> u32 {
416        use self::PrimitiveValue::*;
417        match self {
418            Empty => 0,
419            Str(_) => 1,
420            Strs(c) => c.len() as u32,
421            Tags(c) => c.len() as u32,
422            U8(c) => c.len() as u32,
423            I16(c) => c.len() as u32,
424            U16(c) => c.len() as u32,
425            I32(c) => c.len() as u32,
426            U32(c) => c.len() as u32,
427            I64(c) => c.len() as u32,
428            U64(c) => c.len() as u32,
429            F32(c) => c.len() as u32,
430            F64(c) => c.len() as u32,
431            Date(c) => c.len() as u32,
432            DateTime(c) => c.len() as u32,
433            Time(c) => c.len() as u32,
434        }
435    }
436
437    /// Determine the length of the DICOM value in its encoded form.
438    ///
439    /// In other words,
440    /// this is the number of bytes that the value
441    /// would need to occupy in a DICOM file,
442    /// without compression and without the element header.
443    /// The output is always an even number,
444    /// so as to consider the mandatory trailing padding.
445    ///
446    /// This method is particularly useful for presenting an estimated
447    /// space occupation to the end user.
448    /// However, consumers should not depend on this number for
449    /// decoding or encoding values.
450    /// The calculated number does not need to match
451    /// the length of the original byte stream
452    /// from where the value was originally decoded.
453    pub fn calculate_byte_len(&self) -> usize {
454        use self::PrimitiveValue::*;
455        match self {
456            Empty => 0,
457            U8(c) => c.len(),
458            I16(c) => c.len() * 2,
459            U16(c) => c.len() * 2,
460            U32(c) => c.len() * 4,
461            I32(c) => c.len() * 4,
462            U64(c) => c.len() * 8,
463            I64(c) => c.len() * 8,
464            F32(c) => c.len() * 4,
465            F64(c) => c.len() * 8,
466            Tags(c) => c.len() * 4,
467            Str(s) => s.len(),
468            Strs(c) => c.iter().map(|s| s.len() + 1).sum::<usize>() & !1,
469            Date(c) => {
470                c.iter()
471                    .map(|d| PrimitiveValue::da_byte_len(d) + 1)
472                    .sum::<usize>()
473                    & !1
474            }
475            Time(c) => {
476                c.iter()
477                    .map(|t| PrimitiveValue::tm_byte_len(t) + 1)
478                    .sum::<usize>()
479                    & !1
480            }
481            DateTime(c) => {
482                c.iter()
483                    .map(|dt| PrimitiveValue::dt_byte_len(dt) + 1)
484                    .sum::<usize>()
485                    & !1
486            }
487        }
488    }
489
490    fn da_byte_len(date: &DicomDate) -> usize {
491        match date.precision() {
492            DateComponent::Year => 4,
493            DateComponent::Month => 6,
494            DateComponent::Day => 8,
495            _ => panic!("Impossible precision for a DicomDate"),
496        }
497    }
498
499    fn tm_byte_len(time: &DicomTime) -> usize {
500        match time.precision() {
501            DateComponent::Hour => 2,
502            DateComponent::Minute => 4,
503            DateComponent::Second => 6,
504            DateComponent::Fraction => match time.fraction_and_precision() {
505                None => panic!("DicomTime has fraction precision but no fraction can be retrieved"),
506                Some((_, fp)) => 7 + *fp as usize, // 1 is for the '.'
507            },
508            _ => panic!("Impossible precision for a Dicomtime"),
509        }
510    }
511
512    fn dt_byte_len(datetime: &DicomDateTime) -> usize {
513        PrimitiveValue::da_byte_len(datetime.date())
514            + match datetime.time() {
515                Some(time) => PrimitiveValue::tm_byte_len(time),
516                None => 0,
517            }
518            + match datetime.has_time_zone() {
519                true => 5,
520                false => 0,
521            }
522    }
523
524    /// Convert the primitive value into a string representation.
525    ///
526    /// String values already encoded with the `Str` and `Strs` variants
527    /// are provided as is.
528    /// In the case of `Strs`, the strings are first joined together
529    /// with a backslash (`'\\'`).
530    /// All other type variants are first converted to a string,
531    /// then joined together with a backslash.
532    ///
533    /// Trailing whitespace is stripped from each string.
534    ///
535    /// **Note:**
536    /// As the process of reading a DICOM value
537    /// may not always preserve its original nature,
538    /// it is not guaranteed that `to_str()` returns a string with
539    /// the exact same byte sequence as the one originally found
540    /// at the source of the value,
541    /// even for the string variants.
542    /// Therefore, this method is not reliable
543    /// for compliant DICOM serialization.
544    ///
545    /// # Examples
546    ///
547    /// ```
548    /// # use dicom_core::dicom_value;
549    /// # use dicom_core::value::{C, PrimitiveValue, DicomDate};
550    /// # use smallvec::smallvec;
551    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
552    /// assert_eq!(
553    ///     dicom_value!(Str, "Smith^John").to_str(),
554    ///     "Smith^John",
555    /// );
556    /// assert_eq!(
557    ///     dicom_value!(Date, DicomDate::from_y(2014)?).to_str(),
558    ///     "2014",
559    /// );
560    /// assert_eq!(
561    ///     dicom_value!(Str, "Smith^John\0").to_str(),
562    ///     "Smith^John",
563    /// );
564    /// assert_eq!(
565    ///     dicom_value!(Strs, [
566    ///         "DERIVED",
567    ///         "PRIMARY",
568    ///         "WHOLE BODY",
569    ///         "EMISSION",
570    ///     ])
571    ///     .to_str(),
572    ///     "DERIVED\\PRIMARY\\WHOLE BODY\\EMISSION",
573    /// );
574    /// Ok(())
575    /// }
576    /// ```
577    pub fn to_str(&self) -> Cow<str> {
578        match self {
579            PrimitiveValue::Empty => Cow::from(""),
580            PrimitiveValue::Str(values) => {
581                Cow::from(values.trim_end_matches([' ', '\u{0}']))
582            }
583            PrimitiveValue::Strs(values) => {
584                if values.len() == 1 {
585                    Cow::from(values[0].trim_end_matches([' ', '\u{0}']))
586                } else {
587                    Cow::Owned(
588                        values
589                            .iter()
590                            .map(|s| s.trim_end_matches([' ', '\u{0}']))
591                            .join("\\"),
592                    )
593                }
594            }
595            prim => Cow::from(prim.to_string()),
596        }
597    }
598
599    /// Convert the primitive value into a raw string representation.
600    ///
601    /// String values already encoded with the `Str` and `Strs` variants
602    /// are provided as is.
603    /// In the case of `Strs`, the strings are first joined together
604    /// with a backslash (`'\\'`).
605    /// All other type variants are first converted to a string,
606    /// then joined together with a backslash.
607    ///
608    /// This method keeps all trailing whitespace,
609    /// unlike [`to_str()`](PrimitiveValue::to_str).
610    ///
611    /// **Note:**
612    /// As the process of reading a DICOM value
613    /// may not always preserve its original nature,
614    /// it is not guaranteed that `to_raw_str()` returns a string with
615    /// the exact same byte sequence as the one originally found
616    /// at the source of the value,
617    /// even for the string variants.
618    /// Therefore, this method is not reliable
619    /// for compliant DICOM serialization.
620    ///
621    /// # Examples
622    ///
623    /// ```
624    /// # use dicom_core::dicom_value;
625    /// # use dicom_core::value::{C, DicomDate, PrimitiveValue};
626    /// # use smallvec::smallvec;
627    /// assert_eq!(
628    ///     dicom_value!(Str, "Smith^John\0").to_raw_str(),
629    ///     "Smith^John\0",
630    /// );
631    /// assert_eq!(
632    ///     dicom_value!(Date, DicomDate::from_ymd(2014, 10, 12).unwrap()).to_raw_str(),
633    ///     "2014-10-12",
634    /// );
635    /// assert_eq!(
636    ///     dicom_value!(Strs, [
637    ///         "DERIVED",
638    ///         " PRIMARY ",
639    ///         "WHOLE BODY",
640    ///         "EMISSION ",
641    ///     ])
642    ///     .to_raw_str(),
643    ///     "DERIVED\\ PRIMARY \\WHOLE BODY\\EMISSION ",
644    /// );
645    /// ```
646    pub fn to_raw_str(&self) -> Cow<str> {
647        match self {
648            PrimitiveValue::Empty => Cow::from(""),
649            PrimitiveValue::Str(values) => Cow::from(values.as_str()),
650            PrimitiveValue::Strs(values) => {
651                if values.len() == 1 {
652                    Cow::from(&values[0])
653                } else {
654                    Cow::from(values.iter().join("\\"))
655                }
656            }
657            prim => Cow::from(prim.to_string()),
658        }
659    }
660
661    /// Convert the primitive value into a multi-string representation.
662    ///
663    /// String values already encoded with the `Str` and `Strs` variants
664    /// are provided as is.
665    /// All other type variants are first converted to a string,
666    /// then collected into a vector.
667    ///
668    /// Trailing whitespace is stripped from each string.
669    /// If keeping it is desired,
670    /// use [`to_raw_str()`](PrimitiveValue::to_raw_str).
671    ///
672    /// **Note:**
673    /// As the process of reading a DICOM value
674    /// may not always preserve its original nature,
675    /// it is not guaranteed that `to_multi_str()` returns strings with
676    /// the exact same byte sequence as the one originally found
677    /// at the source of the value,
678    /// even for the string variants.
679    /// Therefore, this method is not reliable
680    /// for compliant DICOM serialization.
681    ///
682    /// # Examples
683    ///
684    /// ```
685    /// # use dicom_core::dicom_value;
686    /// # use dicom_core::value::{C, PrimitiveValue, DicomDate};
687    /// # use smallvec::smallvec;
688    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
689    /// assert_eq!(
690    ///     dicom_value!(Strs, [
691    ///         "DERIVED",
692    ///         "PRIMARY",
693    ///         "WHOLE BODY ",
694    ///         " EMISSION ",
695    ///     ])
696    ///     .to_multi_str(),
697    ///     &["DERIVED", "PRIMARY", "WHOLE BODY", " EMISSION"][..],
698    /// );
699    /// assert_eq!(
700    ///     dicom_value!(Str, "Smith^John").to_multi_str(),
701    ///     &["Smith^John"][..],
702    /// );
703    /// assert_eq!(
704    ///     dicom_value!(Str, "Smith^John\0").to_multi_str(),
705    ///     &["Smith^John"][..],
706    /// );
707    /// assert_eq!(
708    ///     dicom_value!(Date, DicomDate::from_ym(2014, 10)?).to_multi_str(),
709    ///     &["201410"][..],
710    /// );
711    /// assert_eq!(
712    ///     dicom_value!(I64, [128, 256, 512]).to_multi_str(),
713    ///     &["128", "256", "512"][..],
714    /// );
715    /// Ok(())
716    /// }
717    /// ```
718    pub fn to_multi_str(&self) -> Cow<[String]> {
719        /// Auxiliary function for turning a sequence of values
720        /// into a sequence of strings.
721        fn seq_to_str<I>(iter: I) -> Vec<String>
722        where
723            I: IntoIterator,
724            I::Item: Display,
725        {
726            iter.into_iter().map(|x| x.to_string()).collect()
727        }
728
729        match self {
730            PrimitiveValue::Empty => Cow::from(&[][..]),
731            PrimitiveValue::Str(_) => Cow::Owned(vec![self.to_str().to_string()]),
732            PrimitiveValue::Strs(_) => {
733                Cow::Owned(self.to_str().split('\\').map(|s| s.to_string()).collect())
734            }
735            PrimitiveValue::Date(values) => values
736                .into_iter()
737                .map(|date| date.to_encoded())
738                .collect::<Vec<_>>()
739                .into(),
740            PrimitiveValue::Time(values) => values
741                .into_iter()
742                .map(|time| time.to_encoded())
743                .collect::<Vec<_>>()
744                .into(),
745            PrimitiveValue::DateTime(values) => values
746                .into_iter()
747                .map(|dt| dt.to_encoded())
748                .collect::<Vec<_>>()
749                .into(),
750            PrimitiveValue::U8(values) => Cow::Owned(seq_to_str(values)),
751            PrimitiveValue::U16(values) => Cow::Owned(seq_to_str(values)),
752            PrimitiveValue::U32(values) => Cow::Owned(seq_to_str(values)),
753            PrimitiveValue::I16(values) => Cow::Owned(seq_to_str(values)),
754            PrimitiveValue::I32(values) => Cow::Owned(seq_to_str(values)),
755            PrimitiveValue::U64(values) => Cow::Owned(seq_to_str(values)),
756            PrimitiveValue::I64(values) => Cow::Owned(seq_to_str(values)),
757            PrimitiveValue::F32(values) => Cow::Owned(seq_to_str(values)),
758            PrimitiveValue::F64(values) => Cow::Owned(seq_to_str(values)),
759            PrimitiveValue::Tags(values) => Cow::Owned(seq_to_str(values)),
760        }
761    }
762
763    /// Retrieve this DICOM value as raw bytes.
764    ///
765    /// Binary numeric values are returned with a reinterpretation
766    /// of the holding vector's occupied data block as bytes,
767    /// without copying,
768    /// under the platform's native byte order.
769    ///
770    /// String values already encoded with the `Str` and `Strs` variants
771    /// are provided as their respective bytes in UTF-8.
772    /// In the case of `Strs`, the strings are first joined together
773    /// with a backslash (`'\\'`).
774    /// Other type variants are first converted to a string,
775    /// joined together with a backslash,
776    /// then turned into a byte vector.
777    /// For values which are inherently textual according the standard,
778    /// this is equivalent to calling `as_bytes()` after [`to_str()`].
779    ///
780    /// **Note:**
781    /// As the process of reading a DICOM value
782    /// may not always preserve its original nature,
783    /// it is not guaranteed that `to_bytes()` returns the same byte sequence
784    /// as the one originally found at the source of the value.
785    /// Therefore, this method is not reliable
786    /// for compliant DICOM serialization.
787    ///
788    /// [`to_str()`]: #method.to_str
789    ///
790    /// # Examples
791    ///
792    /// `U8` provides a straight, zero-copy slice of bytes.
793    ///
794    /// ```
795    /// # use dicom_core::value::{C, PrimitiveValue, DicomDate};
796    /// # use smallvec::smallvec;
797    ///
798    /// assert_eq!(
799    ///     PrimitiveValue::U8(smallvec![
800    ///         1, 2, 5,
801    ///     ]).to_bytes(),
802    ///     &[1, 2, 5][..],
803    /// );
804    /// ```
805    ///
806    /// Other values are converted to text first.
807    ///
808    /// ```
809    /// # use dicom_core::dicom_value;
810    /// # use dicom_core::value::{C, PrimitiveValue, DicomDate};
811    /// # use smallvec::smallvec;
812    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
813    /// assert_eq!(
814    ///     PrimitiveValue::from("Smith^John").to_bytes(),
815    ///     &b"Smith^John"[..],
816    /// );
817    /// assert_eq!(
818    ///     PrimitiveValue::from(DicomDate::from_ymd(2014, 10, 12)?)
819    ///     .to_bytes(),
820    ///     &b"2014-10-12"[..],
821    /// );
822    /// assert_eq!(
823    ///     dicom_value!(Strs, [
824    ///         "DERIVED",
825    ///         "PRIMARY",
826    ///         "WHOLE BODY",
827    ///         "EMISSION",
828    ///     ])
829    ///     .to_bytes(),
830    ///     &b"DERIVED\\PRIMARY\\WHOLE BODY\\EMISSION"[..],
831    /// );
832    /// Ok(())
833    /// }
834    /// ```
835    pub fn to_bytes(&self) -> Cow<[u8]> {
836        match self {
837            PrimitiveValue::Empty => Cow::from(&[][..]),
838            PrimitiveValue::U8(values) => Cow::from(&values[..]),
839            PrimitiveValue::U16(values) => Cow::Borrowed(transmute_to_bytes(values)),
840            PrimitiveValue::I16(values) => Cow::Borrowed(transmute_to_bytes(values)),
841            PrimitiveValue::U32(values) => Cow::Borrowed(transmute_to_bytes(values)),
842            PrimitiveValue::I32(values) => Cow::Borrowed(transmute_to_bytes(values)),
843            PrimitiveValue::I64(values) => Cow::Borrowed(transmute_to_bytes(values)),
844            PrimitiveValue::U64(values) => Cow::Borrowed(transmute_to_bytes(values)),
845            PrimitiveValue::F32(values) => Cow::Borrowed(transmute_to_bytes(values)),
846            PrimitiveValue::F64(values) => Cow::Borrowed(transmute_to_bytes(values)),
847            PrimitiveValue::Str(values) => Cow::from(values.as_bytes()),
848            PrimitiveValue::Strs(values) => {
849                if values.len() == 1 {
850                    // no need to copy if it's a single string
851                    Cow::from(values[0].as_bytes())
852                } else {
853                    Cow::from(values.iter().join("\\").into_bytes())
854                }
855            }
856            prim => match prim.to_str() {
857                Cow::Borrowed(string) => Cow::Borrowed(string.as_bytes()),
858                Cow::Owned(string) => Cow::Owned(string.into_bytes()),
859            },
860        }
861    }
862
863    /// Retrieve a single integer of type `T` from this value.
864    ///
865    /// If the value is already represented as an integer,
866    /// it is returned after a conversion to the target type.
867    /// An error is returned if the integer cannot be represented
868    /// by the given integer type.
869    /// If the value is a string or sequence of strings,
870    /// the first string is parsed to obtain an integer,
871    /// potentially failing if the string does not represent a valid integer.
872    /// The string is stripped of leading/trailing whitespace before parsing.
873    /// If the value is a sequence of U8 bytes,
874    /// the bytes are individually interpreted as independent numbers.
875    /// Otherwise, the operation fails.
876    ///
877    /// Note that this method does not enable
878    /// the conversion of floating point numbers to integers via truncation.
879    /// If this is intentional,
880    /// retrieve a float via [`to_float32`] or [`to_float64`] instead,
881    /// then cast it to an integer.
882    ///
883    /// [`to_float32`]: #method.to_float32
884    /// [`to_float64`]: #method.to_float64
885    ///
886    /// # Example
887    ///
888    /// ```
889    /// # use dicom_core::value::{C, PrimitiveValue};
890    /// # use smallvec::smallvec;
891    ///
892    /// assert_eq!(
893    ///     PrimitiveValue::I32(smallvec![
894    ///         1, 2, 5,
895    ///     ])
896    ///     .to_int::<u32>().ok(),
897    ///     Some(1_u32),
898    /// );
899    ///
900    /// assert_eq!(
901    ///     PrimitiveValue::from("505 ").to_int::<i32>().ok(),
902    ///     Some(505),
903    /// );
904    /// ```
905    pub fn to_int<T>(&self) -> Result<T, ConvertValueError>
906    where
907        T: NumCast,
908        T: FromStr<Err = std::num::ParseIntError>,
909    {
910        match self {
911            PrimitiveValue::Str(s) => {
912                s.trim_matches(whitespace_or_null)
913                    .parse()
914                    .context(ParseIntegerSnafu)
915                    .map_err(|err| ConvertValueError {
916                        requested: "integer",
917                        original: self.value_type(),
918                        cause: Some(Box::from(err)),
919                    })
920            }
921            PrimitiveValue::Strs(s) if !s.is_empty() => s[0]
922                .trim_matches(whitespace_or_null)
923                .parse()
924                .context(ParseIntegerSnafu)
925                .map_err(|err| ConvertValueError {
926                    requested: "integer",
927                    original: self.value_type(),
928                    cause: Some(Box::from(err)),
929                }),
930            PrimitiveValue::U8(bytes) if !bytes.is_empty() => {
931                T::from(bytes[0]).ok_or_else(|| ConvertValueError {
932                    requested: "integer",
933                    original: self.value_type(),
934                    cause: Some(
935                        NarrowConvertSnafu {
936                            value: bytes[0].to_string(),
937                        }
938                        .build()
939                        .into(),
940                    ),
941                })
942            }
943            PrimitiveValue::U16(s) if !s.is_empty() => {
944                T::from(s[0]).ok_or_else(|| ConvertValueError {
945                    requested: "integer",
946                    original: self.value_type(),
947                    cause: Some(
948                        NarrowConvertSnafu {
949                            value: s[0].to_string(),
950                        }
951                        .build()
952                        .into(),
953                    ),
954                })
955            }
956            PrimitiveValue::I16(s) if !s.is_empty() => {
957                T::from(s[0]).ok_or_else(|| ConvertValueError {
958                    requested: "integer",
959                    original: self.value_type(),
960                    cause: Some(
961                        NarrowConvertSnafu {
962                            value: s[0].to_string(),
963                        }
964                        .build()
965                        .into(),
966                    ),
967                })
968            }
969            PrimitiveValue::U32(s) if !s.is_empty() => {
970                T::from(s[0]).ok_or_else(|| ConvertValueError {
971                    requested: "integer",
972                    original: self.value_type(),
973                    cause: Some(
974                        NarrowConvertSnafu {
975                            value: s[0].to_string(),
976                        }
977                        .build()
978                        .into(),
979                    ),
980                })
981            }
982            PrimitiveValue::I32(s) if !s.is_empty() => {
983                T::from(s[0]).ok_or_else(|| ConvertValueError {
984                    requested: "integer",
985                    original: self.value_type(),
986                    cause: Some(
987                        NarrowConvertSnafu {
988                            value: s[0].to_string(),
989                        }
990                        .build()
991                        .into(),
992                    ),
993                })
994            }
995            PrimitiveValue::U64(s) if !s.is_empty() => {
996                T::from(s[0]).ok_or_else(|| ConvertValueError {
997                    requested: "integer",
998                    original: self.value_type(),
999                    cause: Some(
1000                        NarrowConvertSnafu {
1001                            value: s[0].to_string(),
1002                        }
1003                        .build()
1004                        .into(),
1005                    ),
1006                })
1007            }
1008            PrimitiveValue::I64(s) if !s.is_empty() => {
1009                T::from(s[0]).ok_or_else(|| ConvertValueError {
1010                    requested: "integer",
1011                    original: self.value_type(),
1012                    cause: Some(
1013                        NarrowConvertSnafu {
1014                            value: s[0].to_string(),
1015                        }
1016                        .build()
1017                        .into(),
1018                    ),
1019                })
1020            }
1021            _ => Err(ConvertValueError {
1022                requested: "integer",
1023                original: self.value_type(),
1024                cause: None,
1025            }),
1026        }
1027    }
1028
1029    /// Retrieve a sequence of integers of type `T` from this value.
1030    ///
1031    /// If the values is already represented as an integer,
1032    /// it is returned after a [`NumCast`] conversion to the target type.
1033    /// An error is returned if any of the integers cannot be represented
1034    /// by the given integer type.
1035    /// If the value is a string or sequence of strings,
1036    /// each string is parsed to obtain an integer,
1037    /// potentially failing if the string does not represent a valid integer.
1038    /// The string is stripped of leading/trailing whitespace before parsing.
1039    /// If the value is a sequence of U8 bytes,
1040    /// the bytes are individually interpreted as independent numbers.
1041    /// Otherwise, the operation fails.
1042    ///
1043    /// Note that this method does not enable
1044    /// the conversion of floating point numbers to integers via truncation.
1045    /// If this is intentional,
1046    /// retrieve a float via [`to_float32`] or [`to_float64`] instead,
1047    /// then cast it to an integer.
1048    ///
1049    /// [`NumCast`]: ../num_traits/cast/trait.NumCast.html
1050    /// [`to_float32`]: #method.to_float32
1051    /// [`to_float64`]: #method.to_float64
1052    ///
1053    /// # Example
1054    ///
1055    /// ```
1056    /// # use dicom_core::value::{C, PrimitiveValue};
1057    /// # use dicom_core::dicom_value;
1058    /// # use smallvec::smallvec;
1059    ///
1060    /// assert_eq!(
1061    ///     PrimitiveValue::I32(smallvec![
1062    ///         1, 2, 5,
1063    ///     ])
1064    ///     .to_multi_int::<u32>().ok(),
1065    ///     Some(vec![1_u32, 2, 5]),
1066    /// );
1067    ///
1068    /// assert_eq!(
1069    ///     dicom_value!(Strs, ["5050", "23 "]).to_multi_int::<i32>().ok(),
1070    ///     Some(vec![5050, 23]),
1071    /// );
1072    /// ```
1073    pub fn to_multi_int<T>(&self) -> Result<Vec<T>, ConvertValueError>
1074    where
1075        T: NumCast,
1076        T: FromStr<Err = std::num::ParseIntError>,
1077    {
1078        match self {
1079            PrimitiveValue::Empty => Ok(Vec::new()),
1080            PrimitiveValue::Str(s) => {
1081                let out = s.trim_matches(whitespace_or_null).parse().context(ParseIntegerSnafu).map_err(|err| {
1082                    ConvertValueError {
1083                        requested: "integer",
1084                        original: self.value_type(),
1085                        cause: Some(Box::from(err)),
1086                    }
1087                })?;
1088                Ok(vec![out])
1089            }
1090            PrimitiveValue::Strs(s) => {
1091                s.iter()
1092                    .map(|v| {
1093                        v.trim_matches(whitespace_or_null).parse().context(ParseIntegerSnafu).map_err(|err| {
1094                            ConvertValueError {
1095                                requested: "integer",
1096                                original: self.value_type(),
1097                                cause: Some(Box::from(err)),
1098                            }
1099                        })
1100                    })
1101                    .collect::<Result<Vec<_>, _>>()
1102            }
1103            PrimitiveValue::U8(bytes) => bytes
1104                .iter()
1105                .map(|v| {
1106                    T::from(*v).ok_or_else(|| ConvertValueError {
1107                        requested: "integer",
1108                        original: self.value_type(),
1109                        cause: Some(
1110                            NarrowConvertSnafu {
1111                                value: v.to_string(),
1112                            }
1113                            .build()
1114                            .into(),
1115                        ),
1116                    })
1117                })
1118                .collect::<Result<Vec<_>, _>>(),
1119            PrimitiveValue::U16(s) => s
1120                .iter()
1121                .map(|v| {
1122                    T::from(*v).ok_or_else(|| ConvertValueError {
1123                        requested: "integer",
1124                        original: self.value_type(),
1125                        cause: Some(
1126                            NarrowConvertSnafu {
1127                                value: v.to_string(),
1128                            }
1129                            .build()
1130                            .into(),
1131                        ),
1132                    })
1133                })
1134                .collect::<Result<Vec<_>, _>>(),
1135            PrimitiveValue::I16(s) => s
1136                .iter()
1137                .map(|v| {
1138                    T::from(*v).ok_or_else(|| ConvertValueError {
1139                        requested: "integer",
1140                        original: self.value_type(),
1141                        cause: Some(
1142                            NarrowConvertSnafu {
1143                                value: v.to_string(),
1144                            }
1145                            .build()
1146                            .into(),
1147                        ),
1148                    })
1149                })
1150                .collect::<Result<Vec<_>, _>>(),
1151            PrimitiveValue::U32(s) => s
1152                .iter()
1153                .map(|v| {
1154                    T::from(*v).ok_or_else(|| ConvertValueError {
1155                        requested: "integer",
1156                        original: self.value_type(),
1157                        cause: Some(
1158                            NarrowConvertSnafu {
1159                                value: v.to_string(),
1160                            }
1161                            .build()
1162                            .into(),
1163                        ),
1164                    })
1165                })
1166                .collect::<Result<Vec<_>, _>>(),
1167            PrimitiveValue::I32(s) if !s.is_empty() => s
1168                .iter()
1169                .map(|v| {
1170                    T::from(*v).ok_or_else(|| ConvertValueError {
1171                        requested: "integer",
1172                        original: self.value_type(),
1173                        cause: Some(
1174                            NarrowConvertSnafu {
1175                                value: v.to_string(),
1176                            }
1177                            .build()
1178                            .into(),
1179                        ),
1180                    })
1181                })
1182                .collect::<Result<Vec<_>, _>>(),
1183            PrimitiveValue::U64(s) if !s.is_empty() => s
1184                .iter()
1185                .map(|v| {
1186                    T::from(*v).ok_or_else(|| ConvertValueError {
1187                        requested: "integer",
1188                        original: self.value_type(),
1189                        cause: Some(
1190                            NarrowConvertSnafu {
1191                                value: v.to_string(),
1192                            }
1193                            .build()
1194                            .into(),
1195                        ),
1196                    })
1197                })
1198                .collect::<Result<Vec<_>, _>>(),
1199            PrimitiveValue::I64(s) if !s.is_empty() => s
1200                .iter()
1201                .map(|v| {
1202                    T::from(*v).ok_or_else(|| ConvertValueError {
1203                        requested: "integer",
1204                        original: self.value_type(),
1205                        cause: Some(
1206                            NarrowConvertSnafu {
1207                                value: v.to_string(),
1208                            }
1209                            .build()
1210                            .into(),
1211                        ),
1212                    })
1213                })
1214                .collect::<Result<Vec<_>, _>>(),
1215            _ => Err(ConvertValueError {
1216                requested: "integer",
1217                original: self.value_type(),
1218                cause: None,
1219            }),
1220        }
1221    }
1222
1223    /// Retrieve one single-precision floating point from this value.
1224    ///
1225    /// If the value is already represented as a number,
1226    /// it is returned after a conversion to `f32`.
1227    /// An error is returned if the number cannot be represented
1228    /// by the given number type.
1229    /// If the value is a string or sequence of strings,
1230    /// the first string is parsed to obtain a number,
1231    /// potentially failing if the string does not represent a valid number.
1232    /// The string is stripped of leading/trailing whitespace before parsing.
1233    /// If the value is a sequence of U8 bytes,
1234    /// the bytes are individually interpreted as independent numbers.
1235    /// Otherwise, the operation fails.
1236    ///
1237    /// # Example
1238    ///
1239    /// ```
1240    /// # use dicom_core::value::{C, PrimitiveValue};
1241    /// # use smallvec::smallvec;
1242    ///
1243    /// assert_eq!(
1244    ///     PrimitiveValue::F32(smallvec![
1245    ///         1.5, 2., 5.,
1246    ///     ])
1247    ///     .to_float32().ok(),
1248    ///     Some(1.5_f32),
1249    /// );
1250    ///
1251    /// assert_eq!(
1252    ///     PrimitiveValue::from("-6.75 ").to_float32().ok(),
1253    ///     Some(-6.75),
1254    /// );
1255    /// ```
1256    pub fn to_float32(&self) -> Result<f32, ConvertValueError> {
1257        match self {
1258            PrimitiveValue::Str(s) => {
1259                s.trim_matches(whitespace_or_null)
1260                    .parse()
1261                    .context(ParseFloatSnafu)
1262                    .map_err(|err| ConvertValueError {
1263                        requested: "float32",
1264                        original: self.value_type(),
1265                        cause: Some(Box::from(err)),
1266                    })
1267            }
1268            PrimitiveValue::Strs(s) if !s.is_empty() => s[0]
1269                .trim_matches(whitespace_or_null)
1270                .parse()
1271                .context(ParseFloatSnafu)
1272                .map_err(|err| ConvertValueError {
1273                    requested: "float32",
1274                    original: self.value_type(),
1275                    cause: Some(Box::from(err)),
1276                }),
1277            PrimitiveValue::U8(bytes) if !bytes.is_empty() => {
1278                NumCast::from(bytes[0]).ok_or_else(|| ConvertValueError {
1279                    requested: "float32",
1280                    original: self.value_type(),
1281                    cause: Some(
1282                        NarrowConvertSnafu {
1283                            value: bytes[0].to_string(),
1284                        }
1285                        .build()
1286                        .into(),
1287                    ),
1288                })
1289            }
1290            PrimitiveValue::U16(s) if !s.is_empty() => {
1291                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1292                    requested: "float32",
1293                    original: self.value_type(),
1294                    cause: Some(
1295                        NarrowConvertSnafu {
1296                            value: s[0].to_string(),
1297                        }
1298                        .build()
1299                        .into(),
1300                    ),
1301                })
1302            }
1303            PrimitiveValue::I16(s) if !s.is_empty() => {
1304                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1305                    requested: "float32",
1306                    original: self.value_type(),
1307                    cause: Some(
1308                        NarrowConvertSnafu {
1309                            value: s[0].to_string(),
1310                        }
1311                        .build()
1312                        .into(),
1313                    ),
1314                })
1315            }
1316            PrimitiveValue::U32(s) if !s.is_empty() => {
1317                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1318                    requested: "float32",
1319                    original: self.value_type(),
1320                    cause: Some(
1321                        NarrowConvertSnafu {
1322                            value: s[0].to_string(),
1323                        }
1324                        .build()
1325                        .into(),
1326                    ),
1327                })
1328            }
1329            PrimitiveValue::I32(s) if !s.is_empty() => {
1330                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1331                    requested: "float32",
1332                    original: self.value_type(),
1333                    cause: Some(
1334                        NarrowConvertSnafu {
1335                            value: s[0].to_string(),
1336                        }
1337                        .build()
1338                        .into(),
1339                    ),
1340                })
1341            }
1342            PrimitiveValue::U64(s) if !s.is_empty() => {
1343                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1344                    requested: "float32",
1345                    original: self.value_type(),
1346                    cause: Some(
1347                        NarrowConvertSnafu {
1348                            value: s[0].to_string(),
1349                        }
1350                        .build()
1351                        .into(),
1352                    ),
1353                })
1354            }
1355            PrimitiveValue::I64(s) if !s.is_empty() => {
1356                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1357                    requested: "float32",
1358                    original: self.value_type(),
1359                    cause: Some(
1360                        NarrowConvertSnafu {
1361                            value: s[0].to_string(),
1362                        }
1363                        .build()
1364                        .into(),
1365                    ),
1366                })
1367            }
1368            PrimitiveValue::F32(s) if !s.is_empty() => Ok(s[0]),
1369            PrimitiveValue::F64(s) if !s.is_empty() => {
1370                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1371                    requested: "float32",
1372                    original: self.value_type(),
1373                    cause: Some(
1374                        NarrowConvertSnafu {
1375                            value: s[0].to_string(),
1376                        }
1377                        .build()
1378                        .into(),
1379                    ),
1380                })
1381            }
1382            _ => Err(ConvertValueError {
1383                requested: "float32",
1384                original: self.value_type(),
1385                cause: None,
1386            }),
1387        }
1388    }
1389
1390    /// Retrieve a sequence of single-precision floating point numbers
1391    /// from this value.
1392    ///
1393    /// If the value is already represented as numbers,
1394    /// they are returned after a conversion to `f32`.
1395    /// An error is returned if any of the numbers cannot be represented
1396    /// by an `f32`.
1397    /// If the value is a string or sequence of strings,
1398    /// the strings are parsed to obtain a number,
1399    /// potentially failing if the string does not represent a valid number.
1400    /// The string is stripped of leading/trailing whitespace before parsing.
1401    /// If the value is a sequence of U8 bytes,
1402    /// the bytes are individually interpreted as independent numbers.
1403    /// Otherwise, the operation fails.
1404    ///
1405    /// # Example
1406    ///
1407    /// ```
1408    /// # use dicom_core::value::{C, PrimitiveValue};
1409    /// # use smallvec::smallvec;
1410    ///
1411    /// assert_eq!(
1412    ///     PrimitiveValue::F32(smallvec![
1413    ///         1.5, 2., 5.,
1414    ///     ])
1415    ///     .to_multi_float32().ok(),
1416    ///     Some(vec![1.5_f32, 2., 5.]),
1417    /// );
1418    ///
1419    /// assert_eq!(
1420    ///     PrimitiveValue::from("-6.75 ").to_multi_float32().ok(),
1421    ///     Some(vec![-6.75]),
1422    /// );
1423    /// ```
1424    pub fn to_multi_float32(&self) -> Result<Vec<f32>, ConvertValueError> {
1425        match self {
1426            PrimitiveValue::Empty => Ok(Vec::new()),
1427            PrimitiveValue::Str(s) => {
1428                let out =
1429                    s.trim_matches(whitespace_or_null)
1430                        .parse()
1431                        .context(ParseFloatSnafu)
1432                        .map_err(|err| ConvertValueError {
1433                            requested: "float32",
1434                            original: self.value_type(),
1435                            cause: Some(Box::from(err)),
1436                        })?;
1437                Ok(vec![out])
1438            }
1439            PrimitiveValue::Strs(s) => s
1440                .iter()
1441                .map(|v| {
1442                    v.trim_matches(whitespace_or_null)
1443                        .parse()
1444                        .context(ParseFloatSnafu)
1445                        .map_err(|err| ConvertValueError {
1446                            requested: "float32",
1447                            original: self.value_type(),
1448                            cause: Some(Box::from(err)),
1449                        })
1450                })
1451                .collect::<Result<Vec<_>, _>>(),
1452            PrimitiveValue::U8(bytes) => bytes
1453                .iter()
1454                .map(|v| {
1455                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1456                        requested: "float32",
1457                        original: self.value_type(),
1458                        cause: Some(
1459                            NarrowConvertSnafu {
1460                                value: v.to_string(),
1461                            }
1462                            .build()
1463                            .into(),
1464                        ),
1465                    })
1466                })
1467                .collect::<Result<Vec<_>, _>>(),
1468            PrimitiveValue::U16(s) => s
1469                .iter()
1470                .map(|v| {
1471                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1472                        requested: "float32",
1473                        original: self.value_type(),
1474                        cause: Some(
1475                            NarrowConvertSnafu {
1476                                value: v.to_string(),
1477                            }
1478                            .build()
1479                            .into(),
1480                        ),
1481                    })
1482                })
1483                .collect::<Result<Vec<_>, _>>(),
1484            PrimitiveValue::I16(s) => s
1485                .iter()
1486                .map(|v| {
1487                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1488                        requested: "float32",
1489                        original: self.value_type(),
1490                        cause: Some(
1491                            NarrowConvertSnafu {
1492                                value: v.to_string(),
1493                            }
1494                            .build()
1495                            .into(),
1496                        ),
1497                    })
1498                })
1499                .collect::<Result<Vec<_>, _>>(),
1500            PrimitiveValue::U32(s) => s
1501                .iter()
1502                .map(|v| {
1503                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1504                        requested: "float32",
1505                        original: self.value_type(),
1506                        cause: Some(
1507                            NarrowConvertSnafu {
1508                                value: v.to_string(),
1509                            }
1510                            .build()
1511                            .into(),
1512                        ),
1513                    })
1514                })
1515                .collect::<Result<Vec<_>, _>>(),
1516            PrimitiveValue::I32(s) => s
1517                .iter()
1518                .map(|v| {
1519                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1520                        requested: "float32",
1521                        original: self.value_type(),
1522                        cause: Some(
1523                            NarrowConvertSnafu {
1524                                value: v.to_string(),
1525                            }
1526                            .build()
1527                            .into(),
1528                        ),
1529                    })
1530                })
1531                .collect::<Result<Vec<_>, _>>(),
1532            PrimitiveValue::U64(s) => s
1533                .iter()
1534                .map(|v| {
1535                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1536                        requested: "float32",
1537                        original: self.value_type(),
1538                        cause: Some(
1539                            NarrowConvertSnafu {
1540                                value: v.to_string(),
1541                            }
1542                            .build()
1543                            .into(),
1544                        ),
1545                    })
1546                })
1547                .collect::<Result<Vec<_>, _>>(),
1548            PrimitiveValue::I64(s) => s
1549                .iter()
1550                .map(|v| {
1551                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1552                        requested: "float32",
1553                        original: self.value_type(),
1554                        cause: Some(
1555                            NarrowConvertSnafu {
1556                                value: v.to_string(),
1557                            }
1558                            .build()
1559                            .into(),
1560                        ),
1561                    })
1562                })
1563                .collect::<Result<Vec<_>, _>>(),
1564            PrimitiveValue::F32(s) => Ok(s[..].to_owned()),
1565            PrimitiveValue::F64(s) => s
1566                .iter()
1567                .map(|v| {
1568                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1569                        requested: "float32",
1570                        original: self.value_type(),
1571                        cause: Some(
1572                            NarrowConvertSnafu {
1573                                value: v.to_string(),
1574                            }
1575                            .build()
1576                            .into(),
1577                        ),
1578                    })
1579                })
1580                .collect::<Result<Vec<_>, _>>(),
1581            _ => Err(ConvertValueError {
1582                requested: "float32",
1583                original: self.value_type(),
1584                cause: None,
1585            }),
1586        }
1587    }
1588
1589    /// Retrieve one double-precision floating point from this value.
1590    ///
1591    /// If the value is already represented as a number,
1592    /// it is returned after a conversion to `f64`.
1593    /// An error is returned if the number cannot be represented
1594    /// by the given number type.
1595    /// If the value is a string or sequence of strings,
1596    /// the first string is parsed to obtain a number,
1597    /// potentially failing if the string does not represent a valid number.
1598    /// The string is stripped of leading/trailing whitespace before parsing.
1599    /// If the value is a sequence of U8 bytes,
1600    /// the bytes are individually interpreted as independent numbers.
1601    /// Otherwise, the operation fails.
1602    ///
1603    /// # Example
1604    ///
1605    /// ```
1606    /// # use dicom_core::value::{C, PrimitiveValue};
1607    /// # use smallvec::smallvec;
1608    ///
1609    /// assert_eq!(
1610    ///     PrimitiveValue::F64(smallvec![
1611    ///         1.5, 2., 5.,
1612    ///     ])
1613    ///     .to_float64().ok(),
1614    ///     Some(1.5_f64),
1615    /// );
1616    ///
1617    /// assert_eq!(
1618    ///     PrimitiveValue::from("-6.75 ").to_float64().ok(),
1619    ///     Some(-6.75),
1620    /// );
1621    /// ```
1622    pub fn to_float64(&self) -> Result<f64, ConvertValueError> {
1623        match self {
1624            PrimitiveValue::Str(s) => {
1625                s.trim_matches(whitespace_or_null)
1626                    .parse()
1627                    .context(ParseFloatSnafu)
1628                    .map_err(|err| ConvertValueError {
1629                        requested: "float64",
1630                        original: self.value_type(),
1631                        cause: Some(Box::from(err)),
1632                    })
1633            }
1634            PrimitiveValue::Strs(s) if !s.is_empty() => s[0]
1635                .trim_matches(whitespace_or_null)
1636                .parse()
1637                .context(ParseFloatSnafu)
1638                .map_err(|err| ConvertValueError {
1639                    requested: "float64",
1640                    original: self.value_type(),
1641                    cause: Some(Box::from(err)),
1642                }),
1643            PrimitiveValue::U8(bytes) if !bytes.is_empty() => {
1644                NumCast::from(bytes[0]).ok_or_else(|| ConvertValueError {
1645                    requested: "float64",
1646                    original: self.value_type(),
1647                    cause: Some(
1648                        NarrowConvertSnafu {
1649                            value: bytes[0].to_string(),
1650                        }
1651                        .build()
1652                        .into(),
1653                    ),
1654                })
1655            }
1656            PrimitiveValue::U16(s) if !s.is_empty() => {
1657                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1658                    requested: "float64",
1659                    original: self.value_type(),
1660                    cause: Some(
1661                        NarrowConvertSnafu {
1662                            value: s[0].to_string(),
1663                        }
1664                        .build()
1665                        .into(),
1666                    ),
1667                })
1668            }
1669            PrimitiveValue::I16(s) if !s.is_empty() => {
1670                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1671                    requested: "float64",
1672                    original: self.value_type(),
1673                    cause: Some(
1674                        NarrowConvertSnafu {
1675                            value: s[0].to_string(),
1676                        }
1677                        .build()
1678                        .into(),
1679                    ),
1680                })
1681            }
1682            PrimitiveValue::U32(s) if !s.is_empty() => {
1683                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1684                    requested: "float64",
1685                    original: self.value_type(),
1686                    cause: Some(
1687                        NarrowConvertSnafu {
1688                            value: s[0].to_string(),
1689                        }
1690                        .build()
1691                        .into(),
1692                    ),
1693                })
1694            }
1695            PrimitiveValue::I32(s) if !s.is_empty() => {
1696                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1697                    requested: "float64",
1698                    original: self.value_type(),
1699                    cause: Some(
1700                        NarrowConvertSnafu {
1701                            value: s[0].to_string(),
1702                        }
1703                        .build()
1704                        .into(),
1705                    ),
1706                })
1707            }
1708            PrimitiveValue::U64(s) if !s.is_empty() => {
1709                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1710                    requested: "float64",
1711                    original: self.value_type(),
1712                    cause: Some(
1713                        NarrowConvertSnafu {
1714                            value: s[0].to_string(),
1715                        }
1716                        .build()
1717                        .into(),
1718                    ),
1719                })
1720            }
1721            PrimitiveValue::I64(s) if !s.is_empty() => {
1722                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1723                    requested: "float64",
1724                    original: self.value_type(),
1725                    cause: Some(
1726                        NarrowConvertSnafu {
1727                            value: s[0].to_string(),
1728                        }
1729                        .build()
1730                        .into(),
1731                    ),
1732                })
1733            }
1734            PrimitiveValue::F32(s) if !s.is_empty() => {
1735                NumCast::from(s[0]).ok_or_else(|| ConvertValueError {
1736                    requested: "float64",
1737                    original: self.value_type(),
1738                    cause: Some(
1739                        NarrowConvertSnafu {
1740                            value: s[0].to_string(),
1741                        }
1742                        .build()
1743                        .into(),
1744                    ),
1745                })
1746            }
1747            PrimitiveValue::F64(s) if !s.is_empty() => Ok(s[0]),
1748            _ => Err(ConvertValueError {
1749                requested: "float64",
1750                original: self.value_type(),
1751                cause: None,
1752            }),
1753        }
1754    }
1755
1756    /// Retrieve a sequence of double-precision floating point numbers
1757    /// from this value.
1758    ///
1759    /// If the value is already represented as numbers,
1760    /// they are returned after a conversion to `f64`.
1761    /// An error is returned if any of the numbers cannot be represented
1762    /// by an `f64`.
1763    /// If the value is a string or sequence of strings,
1764    /// the strings are parsed to obtain a number,
1765    /// potentially failing if the string does not represent a valid number.
1766    /// The string is stripped of leading/trailing whitespace before parsing.
1767    /// If the value is a sequence of U8 bytes,
1768    /// the bytes are individually interpreted as independent numbers.
1769    /// Otherwise, the operation fails.
1770    ///
1771    /// # Example
1772    ///
1773    /// ```
1774    /// # use dicom_core::value::{C, PrimitiveValue};
1775    /// # use smallvec::smallvec;
1776    ///
1777    /// assert_eq!(
1778    ///     PrimitiveValue::F64(smallvec![
1779    ///         1.5, 2., 5.,
1780    ///     ])
1781    ///     .to_multi_float64().ok(),
1782    ///     Some(vec![1.5_f64, 2., 5.]),
1783    /// );
1784    ///
1785    /// assert_eq!(
1786    ///     PrimitiveValue::from("-6.75 ").to_multi_float64().ok(),
1787    ///     Some(vec![-6.75]),
1788    /// );
1789    /// ```
1790    pub fn to_multi_float64(&self) -> Result<Vec<f64>, ConvertValueError> {
1791        match self {
1792            PrimitiveValue::Str(s) => {
1793                let out =
1794                    s.trim_matches(whitespace_or_null)
1795                        .parse()
1796                        .context(ParseFloatSnafu)
1797                        .map_err(|err| ConvertValueError {
1798                            requested: "float64",
1799                            original: self.value_type(),
1800                            cause: Some(Box::from(err)),
1801                        })?;
1802                Ok(vec![out])
1803            }
1804            PrimitiveValue::Strs(s) => s
1805                .iter()
1806                .map(|v| {
1807                    v.trim_matches(whitespace_or_null)
1808                        .parse()
1809                        .context(ParseFloatSnafu)
1810                        .map_err(|err| ConvertValueError {
1811                            requested: "float64",
1812                            original: self.value_type(),
1813                            cause: Some(Box::from(err)),
1814                        })
1815                })
1816                .collect::<Result<Vec<_>, _>>(),
1817            PrimitiveValue::U8(bytes) => bytes
1818                .iter()
1819                .map(|v| {
1820                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1821                        requested: "float64",
1822                        original: self.value_type(),
1823                        cause: Some(
1824                            NarrowConvertSnafu {
1825                                value: v.to_string(),
1826                            }
1827                            .build()
1828                            .into(),
1829                        ),
1830                    })
1831                })
1832                .collect::<Result<Vec<_>, _>>(),
1833            PrimitiveValue::U16(s) => s
1834                .iter()
1835                .map(|v| {
1836                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1837                        requested: "float64",
1838                        original: self.value_type(),
1839                        cause: Some(
1840                            NarrowConvertSnafu {
1841                                value: v.to_string(),
1842                            }
1843                            .build()
1844                            .into(),
1845                        ),
1846                    })
1847                })
1848                .collect::<Result<Vec<_>, _>>(),
1849            PrimitiveValue::I16(s) => s
1850                .iter()
1851                .map(|v| {
1852                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1853                        requested: "float64",
1854                        original: self.value_type(),
1855                        cause: Some(
1856                            NarrowConvertSnafu {
1857                                value: v.to_string(),
1858                            }
1859                            .build()
1860                            .into(),
1861                        ),
1862                    })
1863                })
1864                .collect::<Result<Vec<_>, _>>(),
1865            PrimitiveValue::U32(s) => s
1866                .iter()
1867                .map(|v| {
1868                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1869                        requested: "float64",
1870                        original: self.value_type(),
1871                        cause: Some(
1872                            NarrowConvertSnafu {
1873                                value: v.to_string(),
1874                            }
1875                            .build()
1876                            .into(),
1877                        ),
1878                    })
1879                })
1880                .collect::<Result<Vec<_>, _>>(),
1881            PrimitiveValue::I32(s) => s
1882                .iter()
1883                .map(|v| {
1884                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1885                        requested: "float64",
1886                        original: self.value_type(),
1887                        cause: Some(
1888                            NarrowConvertSnafu {
1889                                value: v.to_string(),
1890                            }
1891                            .build()
1892                            .into(),
1893                        ),
1894                    })
1895                })
1896                .collect::<Result<Vec<_>, _>>(),
1897            PrimitiveValue::U64(s) => s
1898                .iter()
1899                .map(|v| {
1900                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1901                        requested: "float64",
1902                        original: self.value_type(),
1903                        cause: Some(
1904                            NarrowConvertSnafu {
1905                                value: v.to_string(),
1906                            }
1907                            .build()
1908                            .into(),
1909                        ),
1910                    })
1911                })
1912                .collect::<Result<Vec<_>, _>>(),
1913            PrimitiveValue::I64(s) => s
1914                .iter()
1915                .map(|v| {
1916                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1917                        requested: "float64",
1918                        original: self.value_type(),
1919                        cause: Some(
1920                            NarrowConvertSnafu {
1921                                value: v.to_string(),
1922                            }
1923                            .build()
1924                            .into(),
1925                        ),
1926                    })
1927                })
1928                .collect::<Result<Vec<_>, _>>(),
1929            PrimitiveValue::F32(s) => s
1930                .iter()
1931                .map(|v| {
1932                    NumCast::from(*v).ok_or_else(|| ConvertValueError {
1933                        requested: "float64",
1934                        original: self.value_type(),
1935                        cause: Some(
1936                            NarrowConvertSnafu {
1937                                value: v.to_string(),
1938                            }
1939                            .build()
1940                            .into(),
1941                        ),
1942                    })
1943                })
1944                .collect::<Result<Vec<_>, _>>(),
1945            PrimitiveValue::F64(s) => Ok(s[..].to_owned()),
1946            _ => Err(ConvertValueError {
1947                requested: "float32",
1948                original: self.value_type(),
1949                cause: None,
1950            }),
1951        }
1952    }
1953
1954    /// Retrieve a single `chrono::NaiveDate` from this value.
1955    ///
1956    /// Please note, that this is a shortcut to obtain a usable date from a primitive value.
1957    /// As per standard, the stored value might not be precise. It is highly recommended to
1958    /// use [`.to_date()`](PrimitiveValue::to_date) as the only way to obtain dates.
1959    ///
1960    /// If the value is already represented as a precise `DicomDate`, it is converted
1961    ///  to a `NaiveDate` value. It fails for imprecise values.
1962    /// If the value is a string or sequence of strings,
1963    /// the first string is decoded to obtain a date, potentially failing if the
1964    /// string does not represent a valid date.
1965    /// If the value is a sequence of U8 bytes, the bytes are
1966    /// first interpreted as an ASCII character string.
1967    ///
1968    /// Users are advised that this method is DICOM compliant and a full
1969    /// date representation of YYYYMMDD is required. Otherwise, the operation fails.
1970    ///  
1971    /// Partial precision dates are handled by `DicomDate`, which can be retrieved
1972    /// by [`.to_date()`](PrimitiveValue::to_date).
1973    ///
1974    /// # Example
1975    ///
1976    /// ```
1977    /// # use dicom_core::value::{C, PrimitiveValue, DicomDate};
1978    /// # use smallvec::smallvec;
1979    /// # use chrono::NaiveDate;
1980    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1981    ///
1982    /// assert_eq!(
1983    ///     PrimitiveValue::Date(smallvec![
1984    ///         DicomDate::from_ymd(2014, 10, 12)?,
1985    ///     ])
1986    ///     .to_naive_date().ok(),
1987    ///     Some(NaiveDate::from_ymd(2014, 10, 12)),
1988    /// );
1989    ///
1990    /// assert_eq!(
1991    ///     PrimitiveValue::Strs(smallvec![
1992    ///         "20141012".to_string(),
1993    ///     ])
1994    ///     .to_naive_date().ok(),
1995    ///     Some(NaiveDate::from_ymd(2014, 10, 12)),
1996    /// );
1997    ///
1998    /// assert!(
1999    ///     PrimitiveValue::Str("201410".to_string())
2000    ///     .to_naive_date().is_err()
2001    /// );
2002    /// # Ok(())
2003    /// # }
2004    /// ```
2005    pub fn to_naive_date(&self) -> Result<NaiveDate, ConvertValueError> {
2006        match self {
2007            PrimitiveValue::Date(v) if !v.is_empty() => v[0]
2008                .to_naive_date()
2009                .context(ParseDateRangeSnafu)
2010                .map_err(|err| ConvertValueError {
2011                    requested: "NaiveDate",
2012                    original: self.value_type(),
2013                    cause: Some(Box::from(err)),
2014                }),
2015            PrimitiveValue::Str(s) => super::deserialize::parse_date(s.as_bytes())
2016                .context(ParseDateSnafu)
2017                .map_err(|err| ConvertValueError {
2018                    requested: "NaiveDate",
2019                    original: self.value_type(),
2020                    cause: Some(Box::from(err)),
2021                }),
2022            PrimitiveValue::Strs(s) => {
2023                super::deserialize::parse_date(s.first().map(|s| s.as_bytes()).unwrap_or(&[]))
2024                    .context(ParseDateSnafu)
2025                    .map_err(|err| ConvertValueError {
2026                        requested: "NaiveDate",
2027                        original: self.value_type(),
2028                        cause: Some(Box::from(err)),
2029                    })
2030            }
2031            PrimitiveValue::U8(bytes) => super::deserialize::parse_date(bytes)
2032                .context(ParseDateSnafu)
2033                .map_err(|err| ConvertValueError {
2034                    requested: "NaiveDate",
2035                    original: self.value_type(),
2036                    cause: Some(Box::from(err)),
2037                }),
2038            _ => Err(ConvertValueError {
2039                requested: "NaiveDate",
2040                original: self.value_type(),
2041                cause: None,
2042            }),
2043        }
2044    }
2045
2046    /// Retrieve the full sequence of `chrono::NaiveDate`s from this value.
2047    ///
2048    /// Please note, that this is a shortcut to obtain usable dates from a primitive value.
2049    /// As per standard, the stored values might not be precise. It is highly recommended to
2050    /// use [`.to_multi_date()`](PrimitiveValue::to_multi_date) as the only way to obtain dates.
2051    ///
2052    /// If the value is already represented as a sequence of precise `DicomDate` values,
2053    /// it is converted. It fails for imprecise values.
2054    /// If the value is a string or sequence of strings,
2055    /// the strings are decoded to obtain a date, potentially failing if
2056    /// any of the strings does not represent a valid date.
2057    /// If the value is a sequence of U8 bytes, the bytes are
2058    /// first interpreted as an ASCII character string,
2059    /// then as a backslash-separated list of dates.
2060    ///  
2061    /// Users are advised that this method is DICOM compliant and a full
2062    /// date representation of YYYYMMDD is required. Otherwise, the operation fails.
2063    ///  
2064    /// Partial precision dates are handled by `DicomDate`, which can be retrieved
2065    /// by [`.to_multi_date()`](PrimitiveValue::to_multi_date).
2066    ///
2067    /// # Example
2068    ///
2069    /// ```
2070    /// # use dicom_core::value::{C, PrimitiveValue, DicomDate};
2071    /// # use smallvec::smallvec;
2072    /// # use chrono::NaiveDate;
2073    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2074    ///
2075    /// assert_eq!(
2076    ///     PrimitiveValue::Date(smallvec![
2077    ///         DicomDate::from_ymd(2014, 10, 12)?,
2078    ///     ]).to_multi_naive_date().ok(),
2079    ///     Some(vec![NaiveDate::from_ymd(2014, 10, 12)]),
2080    /// );
2081    ///
2082    /// assert_eq!(
2083    ///     PrimitiveValue::Strs(smallvec![
2084    ///         "20141012".to_string(),
2085    ///         "20200828".to_string(),
2086    ///     ]).to_multi_naive_date().ok(),
2087    ///     Some(vec![
2088    ///         NaiveDate::from_ymd(2014, 10, 12),
2089    ///         NaiveDate::from_ymd(2020, 8, 28),
2090    ///     ]),
2091    /// );
2092    /// # Ok(())
2093    /// # }
2094    /// ```
2095    pub fn to_multi_naive_date(&self) -> Result<Vec<NaiveDate>, ConvertValueError> {
2096        match self {
2097            PrimitiveValue::Date(v) if !v.is_empty() => v
2098                .into_iter()
2099                .map(|d| d.to_naive_date())
2100                .collect::<Result<Vec<_>, _>>()
2101                .context(ParseDateRangeSnafu)
2102                .map_err(|err| ConvertValueError {
2103                    requested: "NaiveDate",
2104                    original: self.value_type(),
2105                    cause: Some(Box::from(err)),
2106                }),
2107            PrimitiveValue::Str(s) => super::deserialize::parse_date(s.trim_end_matches(whitespace_or_null).as_bytes())
2108                .map(|date| vec![date])
2109                .context(ParseDateSnafu)
2110                .map_err(|err| ConvertValueError {
2111                    requested: "NaiveDate",
2112                    original: self.value_type(),
2113                    cause: Some(Box::from(err)),
2114                }),
2115            PrimitiveValue::Strs(s) => s
2116                .into_iter()
2117                .map(|s| super::deserialize::parse_date(s.trim_end_matches(whitespace_or_null).as_bytes()))
2118                .collect::<Result<Vec<_>, _>>()
2119                .context(ParseDateSnafu)
2120                .map_err(|err| ConvertValueError {
2121                    requested: "NaiveDate",
2122                    original: self.value_type(),
2123                    cause: Some(Box::from(err)),
2124                }),
2125            PrimitiveValue::U8(bytes) => trim_last_whitespace(bytes)
2126                .split(|c| *c == b'\\')
2127                .map(super::deserialize::parse_date)
2128                .collect::<Result<Vec<_>, _>>()
2129                .context(ParseDateSnafu)
2130                .map_err(|err| ConvertValueError {
2131                    requested: "NaiveDate",
2132                    original: self.value_type(),
2133                    cause: Some(Box::from(err)),
2134                }),
2135            _ => Err(ConvertValueError {
2136                requested: "NaiveDate",
2137                original: self.value_type(),
2138                cause: None,
2139            }),
2140        }
2141    }
2142
2143    /// Retrieve a single `DicomDate` from this value.
2144    ///
2145    /// If the value is already represented as a `DicomDate`, it is returned.
2146    /// If the value is a string or sequence of strings,
2147    /// the first string is decoded to obtain a DicomDate, potentially failing if the
2148    /// string does not represent a valid DicomDate.
2149    /// If the value is a sequence of U8 bytes, the bytes are
2150    /// first interpreted as an ASCII character string.
2151    ///
2152    /// Unlike Rust's `chrono::NaiveDate`, `DicomDate` allows for missing date components.
2153    /// DicomDate implements `AsRange` trait, so specific `chrono::NaiveDate` values can be retrieved.
2154    /// - [`.exact()`](crate::value::range::AsRange::exact)
2155    /// - [`.earliest()`](crate::value::range::AsRange::earliest)
2156    /// - [`.latest()`](crate::value::range::AsRange::latest)
2157    /// - [`.range()`](crate::value::range::AsRange::range)
2158    ///
2159    /// # Example
2160    ///
2161    /// ```
2162    /// # use dicom_core::value::{C, PrimitiveValue};
2163    /// # use smallvec::smallvec;
2164    /// # use chrono::NaiveDate;
2165    /// # use std::error::Error;
2166    /// use dicom_core::value::{AsRange, DicomDate};
2167    /// # fn main() -> Result<(), Box<dyn Error>> {
2168    ///
2169    ///  let value = PrimitiveValue::Str("200002".into());
2170    ///  let date = value.to_date()?;
2171    ///
2172    ///  // it is not precise, day of month is unspecified
2173    ///  assert_eq!(
2174    ///     date.is_precise(),
2175    ///     false
2176    ///     );
2177    ///  assert_eq!(
2178    ///     date.earliest()?,
2179    ///     NaiveDate::from_ymd(2000,2,1)
2180    ///     );
2181    ///  assert_eq!(
2182    ///     date.latest()?,
2183    ///     NaiveDate::from_ymd(2000,2,29)
2184    ///     );
2185    ///  assert!(date.exact().is_err());
2186    ///
2187    ///  let date = PrimitiveValue::Str("20000201".into()).to_date()?;
2188    ///  assert_eq!(
2189    ///     date.is_precise(),
2190    ///     true
2191    ///     );
2192    ///  // .to_naive_date() works only for precise values
2193    ///  assert_eq!(
2194    ///     date.exact()?,
2195    ///     date.to_naive_date()?
2196    ///  );
2197    /// # Ok(())
2198    /// # }
2199    ///
2200    /// ```
2201    pub fn to_date(&self) -> Result<DicomDate, ConvertValueError> {
2202        match self {
2203            PrimitiveValue::Date(d) if !d.is_empty() => Ok(d[0]),
2204            PrimitiveValue::Str(s) => super::deserialize::parse_date_partial(s.as_bytes())
2205                .map(|(date, _)| date)
2206                .context(ParseDateSnafu)
2207                .map_err(|err| ConvertValueError {
2208                    requested: "DicomDate",
2209                    original: self.value_type(),
2210                    cause: Some(Box::from(err)),
2211                }),
2212            PrimitiveValue::Strs(s) => super::deserialize::parse_date_partial(
2213                s.first().map(|s| s.as_bytes()).unwrap_or(&[]),
2214            )
2215            .map(|(date, _)| date)
2216            .context(ParseDateSnafu)
2217            .map_err(|err| ConvertValueError {
2218                requested: "DicomDate",
2219                original: self.value_type(),
2220                cause: Some(Box::from(err)),
2221            }),
2222            PrimitiveValue::U8(bytes) => super::deserialize::parse_date_partial(bytes)
2223                .map(|(date, _)| date)
2224                .context(ParseDateSnafu)
2225                .map_err(|err| ConvertValueError {
2226                    requested: "DicomDate",
2227                    original: self.value_type(),
2228                    cause: Some(Box::from(err)),
2229                }),
2230            _ => Err(ConvertValueError {
2231                requested: "DicomDate",
2232                original: self.value_type(),
2233                cause: None,
2234            }),
2235        }
2236    }
2237
2238    /// Retrieve the full sequence of `DicomDate`s from this value.
2239    ///
2240    /// # Example
2241    /// ```
2242    /// # use dicom_core::value::{PrimitiveValue};
2243    /// # use dicom_core::dicom_value;
2244    /// use dicom_core::value::DicomDate;
2245    /// # use std::error::Error;
2246    /// # fn main() -> Result<(), Box<dyn Error>> {
2247    ///
2248    /// assert_eq!(
2249    ///     dicom_value!(Strs, ["201410", "2020", "20200101"])
2250    ///         .to_multi_date()?,
2251    ///     vec![
2252    ///         DicomDate::from_ym(2014, 10)?,
2253    ///         DicomDate::from_y(2020)?,
2254    ///         DicomDate::from_ymd(2020, 1, 1)?
2255    ///     ]);
2256    ///
2257    /// # Ok(())
2258    /// # }
2259    /// ```
2260    ///
2261    pub fn to_multi_date(&self) -> Result<Vec<DicomDate>, ConvertValueError> {
2262        match self {
2263            PrimitiveValue::Date(d) => Ok(d.to_vec()),
2264            PrimitiveValue::Str(s) => {
2265                super::deserialize::parse_date_partial(s.trim_end_matches(whitespace_or_null).as_bytes())
2266                    .map(|(date, _)| vec![date])
2267                    .context(ParseDateSnafu)
2268                    .map_err(|err| ConvertValueError {
2269                        requested: "DicomDate",
2270                        original: self.value_type(),
2271                        cause: Some(Box::from(err)),
2272                    })
2273            }
2274            PrimitiveValue::Strs(s) => s
2275                .into_iter()
2276                .map(|s| {
2277                    super::deserialize::parse_date_partial(s.trim_end_matches(whitespace_or_null).as_bytes())
2278                        .map(|(date, _rest)| date)
2279                })
2280                .collect::<Result<Vec<_>, _>>()
2281                .context(ParseDateSnafu)
2282                .map_err(|err| ConvertValueError {
2283                    requested: "DicomDate",
2284                    original: self.value_type(),
2285                    cause: Some(Box::from(err)),
2286                }),
2287            PrimitiveValue::U8(bytes) => trim_last_whitespace(bytes)
2288                .split(|c| *c == b'\\')
2289                .map(|s| super::deserialize::parse_date_partial(s).map(|(date, _rest)| date))
2290                .collect::<Result<Vec<_>, _>>()
2291                .context(ParseDateSnafu)
2292                .map_err(|err| ConvertValueError {
2293                    requested: "DicomDate",
2294                    original: self.value_type(),
2295                    cause: Some(Box::from(err)),
2296                }),
2297            _ => Err(ConvertValueError {
2298                requested: "DicomDate",
2299                original: self.value_type(),
2300                cause: None,
2301            }),
2302        }
2303    }
2304
2305    /// Retrieve a single `chrono::NaiveTime` from this value.
2306    ///
2307    /// Please note, that this is a shortcut to obtain a usable time from a primitive value.
2308    /// As per standard, the stored value might not be precise. It is highly recommended to
2309    /// use [`.to_time()`](PrimitiveValue::to_time) as the only way to obtain times.
2310    ///
2311    /// If the value is represented as a precise `DicomTime`,
2312    /// it is converted to a `NaiveTime`.
2313    /// It fails for imprecise values,
2314    /// as in, those which do not specify up to at least the seconds.
2315    /// If the value is a string or sequence of strings,
2316    /// the first string is decoded to obtain a time, potentially failing if the
2317    /// string does not represent a valid time.
2318    /// If the value is a sequence of U8 bytes, the bytes are
2319    /// first interpreted as an ASCII character string.
2320    /// Otherwise, the operation fails.
2321    ///
2322    /// Partial precision times are handled by `DicomTime`,
2323    /// which can be retrieved by [`.to_time()`](PrimitiveValue::to_time).
2324    ///
2325    /// # Example
2326    ///
2327    /// ```
2328    /// # use dicom_core::value::{C, PrimitiveValue, DicomTime};
2329    /// # use smallvec::smallvec;
2330    /// # use chrono::NaiveTime;
2331    /// # use std::error::Error;
2332    /// # fn main() -> Result<(), Box<dyn Error>> {
2333    ///
2334    /// assert_eq!(
2335    ///     PrimitiveValue::from(DicomTime::from_hms(11, 2, 45)?).to_naive_time().ok(),
2336    ///     Some(NaiveTime::from_hms(11, 2, 45)),
2337    /// );
2338    ///
2339    /// assert_eq!(
2340    ///     PrimitiveValue::from("110245.78").to_naive_time().ok(),
2341    ///     Some(NaiveTime::from_hms_milli(11, 2, 45, 780)),
2342    /// );
2343    /// # Ok(())
2344    /// # }
2345    /// ```
2346    pub fn to_naive_time(&self) -> Result<NaiveTime, ConvertValueError> {
2347        match self {
2348            PrimitiveValue::Time(v) if !v.is_empty() => v[0]
2349                .to_naive_time()
2350                .context(ParseTimeRangeSnafu)
2351                .map_err(|err| ConvertValueError {
2352                    requested: "NaiveTime",
2353                    original: self.value_type(),
2354                    cause: Some(Box::from(err)),
2355                }),
2356            PrimitiveValue::Str(s) => super::deserialize::parse_time(s.trim_end_matches(whitespace_or_null).as_bytes())
2357                .map(|(date, _rest)| date)
2358                .context(ParseTimeSnafu)
2359                .map_err(|err| ConvertValueError {
2360                    requested: "NaiveTime",
2361                    original: self.value_type(),
2362                    cause: Some(Box::from(err)),
2363                }),
2364            PrimitiveValue::Strs(s) => super::deserialize::parse_time(
2365                s.first().map(|s| s.trim_end_matches(whitespace_or_null).as_bytes()).unwrap_or(&[]),
2366            )
2367            .map(|(date, _rest)| date)
2368            .context(ParseTimeSnafu)
2369            .map_err(|err| ConvertValueError {
2370                requested: "NaiveTime",
2371                original: self.value_type(),
2372                cause: Some(Box::from(err)),
2373            }),
2374            PrimitiveValue::U8(bytes) => {
2375                super::deserialize::parse_time(trim_last_whitespace(bytes))
2376                    .map(|(date, _rest)| date)
2377                    .context(ParseTimeSnafu)
2378                    .map_err(|err| ConvertValueError {
2379                        requested: "NaiveTime",
2380                        original: self.value_type(),
2381                        cause: Some(Box::from(err)),
2382                    })
2383            }
2384            _ => Err(ConvertValueError {
2385                requested: "NaiveTime",
2386                original: self.value_type(),
2387                cause: None,
2388            }),
2389        }
2390    }
2391
2392    /// Retrieve the full sequence of `chrono::NaiveTime`s from this value.
2393    ///
2394    /// Please note, that this is a shortcut to obtain a usable time from a primitive value.
2395    /// As per standard, the stored values might not be precise. It is highly recommended to
2396    /// use [`.to_multi_time()`](PrimitiveValue::to_multi_time) as the only way to obtain times.
2397    ///
2398    /// If the value is already represented as a sequence of precise `DicomTime` values,
2399    /// it is converted to a sequence of `NaiveTime` values. It fails for imprecise values.
2400    /// If the value is a string or sequence of strings,
2401    /// the strings are decoded to obtain a date, potentially failing if
2402    /// any of the strings does not represent a valid date.
2403    /// If the value is a sequence of U8 bytes, the bytes are
2404    /// first interpreted as an ASCII character string,
2405    /// then as a backslash-separated list of times.
2406    /// Otherwise, the operation fails.
2407    ///
2408    /// Users are advised that this method requires at least 1 out of 6 digits of the second
2409    /// fraction .F to be present. Otherwise, the operation fails.
2410    ///
2411    /// Partial precision times are handled by `DicomTime`,
2412    /// which can be retrieved by [`.to_multi_time()`](PrimitiveValue::to_multi_time).
2413    ///
2414    /// # Example
2415    ///
2416    /// ```
2417    /// # use dicom_core::value::{C, PrimitiveValue, DicomTime};
2418    /// # use smallvec::smallvec;
2419    /// # use chrono::NaiveTime;
2420    /// # use std::error::Error;
2421    /// # fn main() -> Result<(), Box<dyn Error>> {
2422    ///
2423    /// assert_eq!(
2424    ///     PrimitiveValue::from(DicomTime::from_hms(22, 58, 2)?).to_multi_naive_time().ok(),
2425    ///     Some(vec![NaiveTime::from_hms(22, 58, 2)]),
2426    /// );
2427    ///
2428    /// assert_eq!(
2429    ///     PrimitiveValue::Strs(smallvec![
2430    ///         "225802.1".to_string(),
2431    ///         "225916.742388".to_string(),
2432    ///     ]).to_multi_naive_time().ok(),
2433    ///     Some(vec![
2434    ///         NaiveTime::from_hms_micro(22, 58, 2, 100_000),
2435    ///         NaiveTime::from_hms_micro(22, 59, 16, 742_388),
2436    ///     ]),
2437    /// );
2438    /// # Ok(())
2439    /// # }
2440    /// ```
2441    pub fn to_multi_naive_time(&self) -> Result<Vec<NaiveTime>, ConvertValueError> {
2442        match self {
2443            PrimitiveValue::Time(v) if !v.is_empty() => v
2444                .into_iter()
2445                .map(|t| t.to_naive_time())
2446                .collect::<Result<Vec<_>, _>>()
2447                .context(ParseTimeRangeSnafu)
2448                .map_err(|err| ConvertValueError {
2449                    requested: "NaiveTime",
2450                    original: self.value_type(),
2451                    cause: Some(Box::from(err)),
2452                }),
2453            PrimitiveValue::Str(s) => super::deserialize::parse_time(s.trim_end_matches(whitespace_or_null).as_bytes())
2454                .map(|(date, _rest)| vec![date])
2455                .context(ParseDateSnafu)
2456                .map_err(|err| ConvertValueError {
2457                    requested: "NaiveTime",
2458                    original: self.value_type(),
2459                    cause: Some(Box::from(err)),
2460                }),
2461            PrimitiveValue::Strs(s) => s
2462                .into_iter()
2463                .map(|s| {
2464                    super::deserialize::parse_time(s.trim_end_matches(whitespace_or_null).as_bytes())
2465                        .map(|(date, _rest)| date)
2466                })
2467                .collect::<Result<Vec<_>, _>>()
2468                .context(ParseDateSnafu)
2469                .map_err(|err| ConvertValueError {
2470                    requested: "NaiveTime",
2471                    original: self.value_type(),
2472                    cause: Some(Box::from(err)),
2473                }),
2474            PrimitiveValue::U8(bytes) => trim_last_whitespace(bytes)
2475                .split(|c| *c == b'\\')
2476                .map(|s| super::deserialize::parse_time(s).map(|(date, _rest)| date))
2477                .collect::<Result<Vec<_>, _>>()
2478                .context(ParseDateSnafu)
2479                .map_err(|err| ConvertValueError {
2480                    requested: "NaiveTime",
2481                    original: self.value_type(),
2482                    cause: Some(Box::from(err)),
2483                }),
2484            _ => Err(ConvertValueError {
2485                requested: "NaiveTime",
2486                original: self.value_type(),
2487                cause: None,
2488            }),
2489        }
2490    }
2491
2492    /// Retrieve a single `DicomTime` from this value.
2493    ///
2494    /// If the value is already represented as a time, it is converted into DicomTime.
2495    /// If the value is a string or sequence of strings,
2496    /// the first string is decoded to obtain a DicomTime, potentially failing if the
2497    /// string does not represent a valid DicomTime.
2498    /// If the value is a sequence of U8 bytes, the bytes are
2499    /// first interpreted as an ASCII character string.
2500    ///
2501    /// Unlike Rust's `chrono::NaiveTime`, `DicomTime` allows for missing time components.
2502    /// DicomTime implements `AsRange` trait, so specific `chrono::NaiveTime` values can be retrieved.
2503    /// - [`.exact()`](crate::value::range::AsRange::exact)
2504    /// - [`.earliest()`](crate::value::range::AsRange::earliest)
2505    /// - [`.latest()`](crate::value::range::AsRange::latest)
2506    /// - [`.range()`](crate::value::range::AsRange::range)
2507    ///
2508    /// # Example
2509    ///
2510    /// ```
2511    /// # use dicom_core::value::{C, PrimitiveValue};
2512    /// # use chrono::NaiveTime;
2513    /// use dicom_core::value::{AsRange, DicomTime};
2514    /// # use std::error::Error;
2515    /// # fn main() -> Result<(), Box<dyn Error>> {
2516    ///
2517    ///  let value = PrimitiveValue::Str("10".into());
2518    ///  let time = value.to_time()?;
2519    ///
2520    ///  // is not precise, minute, second and second fraction are unspecified
2521    ///  assert_eq!(
2522    ///     time.is_precise(),
2523    ///     false
2524    ///     );
2525    ///  assert_eq!(
2526    ///     time.earliest()?,
2527    ///     NaiveTime::from_hms(10,0,0)
2528    ///     );
2529    ///  assert_eq!(
2530    ///     time.latest()?,
2531    ///     NaiveTime::from_hms_micro(10,59,59,999_999)
2532    ///     );
2533    ///  assert!(time.exact().is_err());
2534    ///
2535    ///  let second = PrimitiveValue::Str("101259".into());
2536    ///  // not a precise value, fraction of second is unspecified
2537    ///  assert!(second.to_time()?.exact().is_err());
2538    ///
2539    ///  // .to_naive_time() yields a result, for at least second precision values
2540    ///  // second fraction defaults to zeros
2541    ///  assert_eq!(
2542    ///     second.to_time()?.to_naive_time()?,
2543    ///     NaiveTime::from_hms(10,12,59)
2544    ///  );
2545    ///
2546    ///  let fraction6 = PrimitiveValue::Str("101259.123456".into());
2547    ///  let fraction5 = PrimitiveValue::Str("101259.12345".into());
2548    ///  
2549    ///  // is not precise, last digit of second fraction is unspecified
2550    ///  assert!(
2551    ///     fraction5.to_time()?.exact().is_err()
2552    ///  );
2553    ///  assert!(
2554    ///     fraction6.to_time()?.exact().is_ok()
2555    ///  );
2556    ///  
2557    ///  assert_eq!(
2558    ///     fraction6.to_time()?.exact()?,
2559    ///     fraction6.to_time()?.to_naive_time()?
2560    ///  );
2561    ///
2562    /// # Ok(())
2563    /// # }
2564    /// ```
2565    pub fn to_time(&self) -> Result<DicomTime, ConvertValueError> {
2566        match self {
2567            PrimitiveValue::Time(t) if !t.is_empty() => Ok(t[0]),
2568            PrimitiveValue::Str(s) => {
2569                super::deserialize::parse_time_partial(s.trim_end_matches(whitespace_or_null).as_bytes())
2570                    .map(|(date, _rest)| date)
2571                    .context(ParseTimeSnafu)
2572                    .map_err(|err| ConvertValueError {
2573                        requested: "DicomTime",
2574                        original: self.value_type(),
2575                        cause: Some(Box::from(err)),
2576                    })
2577            }
2578            PrimitiveValue::Strs(s) => super::deserialize::parse_time_partial(
2579                s.first().map(|s| s.trim_end_matches(whitespace_or_null).as_bytes()).unwrap_or(&[]),
2580            )
2581            .map(|(date, _rest)| date)
2582            .context(ParseTimeSnafu)
2583            .map_err(|err| ConvertValueError {
2584                requested: "DicomTime",
2585                original: self.value_type(),
2586                cause: Some(Box::from(err)),
2587            }),
2588            PrimitiveValue::U8(bytes) => {
2589                super::deserialize::parse_time_partial(trim_last_whitespace(bytes))
2590                    .map(|(date, _rest)| date)
2591                    .context(ParseTimeSnafu)
2592                    .map_err(|err| ConvertValueError {
2593                        requested: "DicomTime",
2594                        original: self.value_type(),
2595                        cause: Some(Box::from(err)),
2596                    })
2597            }
2598            _ => Err(ConvertValueError {
2599                requested: "DicomTime",
2600                original: self.value_type(),
2601                cause: None,
2602            }),
2603        }
2604    }
2605
2606    /// Retrieve the full sequence of `DicomTime`s from this value.
2607    ///
2608    /// If the value is already represented as a time, it is converted into DicomTime.
2609    /// If the value is a string or sequence of strings,
2610    /// the first string is decoded to obtain a DicomTime, potentially failing if the
2611    /// string does not represent a valid DicomTime.
2612    /// If the value is a sequence of U8 bytes, the bytes are
2613    /// first interpreted as an ASCII character string.
2614    ///
2615    /// Unlike Rust's `chrono::NaiveTime`, `DicomTime` allows for missing time components.
2616    /// DicomTime implements `AsRange` trait, so specific `chrono::NaiveTime` values can be retrieved.
2617    /// - [`.exact()`](crate::value::range::AsRange::exact)
2618    /// - [`.earliest()`](crate::value::range::AsRange::earliest)
2619    /// - [`.latest()`](crate::value::range::AsRange::latest)
2620    /// - [`.range()`](crate::value::range::AsRange::range)
2621    ///
2622    /// # Example
2623    ///
2624    /// ```
2625    /// # use std::error::Error;
2626    /// # use dicom_core::value::{C, PrimitiveValue};
2627    /// # use smallvec::smallvec;
2628    /// use dicom_core::value::DicomTime;
2629    /// # fn main() -> Result<(), Box<dyn Error>> {
2630    ///
2631    /// assert_eq!(
2632    ///     PrimitiveValue::Strs(smallvec![
2633    ///         "2258".to_string(),
2634    ///         "225916.000742".to_string(),
2635    ///     ]).to_multi_time()?,
2636    ///     vec![
2637    ///         DicomTime::from_hm(22, 58)?,
2638    ///         DicomTime::from_hms_micro(22, 59, 16, 742)?,
2639    ///     ],
2640    /// );
2641    ///
2642    /// # Ok(())
2643    /// # }
2644    /// ```
2645    pub fn to_multi_time(&self) -> Result<Vec<DicomTime>, ConvertValueError> {
2646        match self {
2647            PrimitiveValue::Time(t) => Ok(t.to_vec()),
2648            PrimitiveValue::Str(s) => {
2649                super::deserialize::parse_time_partial(s.trim_end_matches(whitespace_or_null).as_bytes())
2650                    .map(|(date, _rest)| vec![date])
2651                    .context(ParseDateSnafu)
2652                    .map_err(|err| ConvertValueError {
2653                        requested: "DicomTime",
2654                        original: self.value_type(),
2655                        cause: Some(Box::from(err)),
2656                    })
2657            }
2658            PrimitiveValue::Strs(s) => s
2659                .into_iter()
2660                .map(|s| {
2661                    super::deserialize::parse_time_partial(s.trim_end_matches(whitespace_or_null).as_bytes())
2662                        .map(|(date, _rest)| date)
2663                })
2664                .collect::<Result<Vec<_>, _>>()
2665                .context(ParseDateSnafu)
2666                .map_err(|err| ConvertValueError {
2667                    requested: "DicomTime",
2668                    original: self.value_type(),
2669                    cause: Some(Box::from(err)),
2670                }),
2671            PrimitiveValue::U8(bytes) => trim_last_whitespace(bytes)
2672                .split(|c| *c == b'\\')
2673                .map(|s| super::deserialize::parse_time_partial(s).map(|(date, _rest)| date))
2674                .collect::<Result<Vec<_>, _>>()
2675                .context(ParseDateSnafu)
2676                .map_err(|err| ConvertValueError {
2677                    requested: "DicomTime",
2678                    original: self.value_type(),
2679                    cause: Some(Box::from(err)),
2680                }),
2681            _ => Err(ConvertValueError {
2682                requested: "DicomTime",
2683                original: self.value_type(),
2684                cause: None,
2685            }),
2686        }
2687    }
2688
2689    #[deprecated(since = "0.7.0", note = "Use `to_datetime` instead")]
2690    pub fn to_chrono_datetime(&self) {}
2691    #[deprecated(since = "0.7.0", note = "Use `to_multi_datetime` instead")]
2692    pub fn to_multi_chrono_datetime(&self) {}
2693
2694    /// Retrieve a single `DicomDateTime` from this value.
2695    ///
2696    /// If the value is already represented as a date-time, it is converted into DicomDateTime.
2697    /// If the value is a string or sequence of strings,
2698    /// the first string is decoded to obtain a DicomDateTime, potentially failing if the
2699    /// string does not represent a valid DicomDateTime.
2700    /// If the value is a sequence of U8 bytes, the bytes are
2701    /// first interpreted as an ASCII character string.
2702    ///
2703    /// Unlike Rust's `chrono::DateTime`, `DicomDateTime` allows for missing date or time components.
2704    /// DicomDateTime implements `AsRange` trait, so specific `chrono::DateTime` values can be retrieved.
2705    /// - [`.exact()`](crate::value::range::AsRange::exact)
2706    /// - [`.earliest()`](crate::value::range::AsRange::earliest)
2707    /// - [`.latest()`](crate::value::range::AsRange::latest)
2708    /// - [`.range()`](crate::value::range::AsRange::range)
2709    /// # Example
2710    ///
2711    /// ```
2712    /// # use dicom_core::value::{C, PrimitiveValue};
2713    /// # use smallvec::smallvec;
2714    /// # use chrono::{DateTime, FixedOffset, TimeZone, NaiveDateTime, NaiveDate, NaiveTime};
2715    /// # use std::error::Error;
2716    /// use dicom_core::value::{DicomDateTime, AsRange, DateTimeRange, PreciseDateTime};
2717    ///
2718    /// # fn main() -> Result<(), Box<dyn Error>> {
2719    ///
2720    /// // let's parse a date-time text value with 0.1 second precision without a time-zone.
2721    /// let dt_value = PrimitiveValue::from("20121221093001.1").to_datetime()?;
2722    ///
2723    /// assert_eq!(
2724    ///     dt_value.earliest()?,
2725    ///     PreciseDateTime::Naive(NaiveDateTime::new(
2726    ///      NaiveDate::from_ymd_opt(2012, 12, 21).unwrap(),
2727    ///      NaiveTime::from_hms_micro_opt(9, 30, 1, 100_000).unwrap()
2728    ///         ))
2729    /// );
2730    /// assert_eq!(
2731    ///     dt_value.latest()?,
2732    ///     PreciseDateTime::Naive(NaiveDateTime::new(
2733    ///      NaiveDate::from_ymd_opt(2012, 12, 21).unwrap(),
2734    ///      NaiveTime::from_hms_micro_opt(9, 30, 1, 199_999).unwrap()
2735    ///         ))
2736    /// );
2737    ///
2738    /// let default_offset = FixedOffset::east_opt(3600).unwrap();
2739    /// // let's parse a date-time text value with full precision with a time-zone east +01:00.
2740    /// let dt_value = PrimitiveValue::from("20121221093001.123456+0100").to_datetime()?;
2741    ///
2742    /// // date-time has all components
2743    /// assert_eq!(dt_value.is_precise(), true);
2744    ///
2745    /// assert_eq!(
2746    ///     dt_value.exact()?,
2747    ///     PreciseDateTime::TimeZone(
2748    ///     default_offset
2749    ///     .ymd_opt(2012, 12, 21).unwrap()
2750    ///     .and_hms_micro_opt(9, 30, 1, 123_456).unwrap()
2751    ///     )
2752    ///        
2753    /// );
2754    ///
2755    /// // ranges are inclusive, for a precise value, two identical values are returned
2756    /// assert_eq!(
2757    ///     dt_value.range()?,
2758    ///     DateTimeRange::from_start_to_end_with_time_zone(
2759    ///         FixedOffset::east_opt(3600).unwrap()
2760    ///             .ymd_opt(2012, 12, 21).unwrap()
2761    ///             .and_hms_micro_opt(9, 30, 1, 123_456).unwrap(),
2762    ///         FixedOffset::east_opt(3600).unwrap()
2763    ///             .ymd_opt(2012, 12, 21).unwrap()
2764    ///             .and_hms_micro_opt(9, 30, 1, 123_456).unwrap()
2765    ///     )?
2766    ///     
2767    /// );
2768    /// # Ok(())
2769    /// # }
2770    /// ```
2771    pub fn to_datetime(&self) -> Result<DicomDateTime, ConvertValueError> {
2772        match self {
2773            PrimitiveValue::DateTime(v) if !v.is_empty() => Ok(v[0]),
2774            PrimitiveValue::Str(s) => {
2775                super::deserialize::parse_datetime_partial(s.trim_end_matches(whitespace_or_null).as_bytes())
2776                    .context(ParseDateTimeSnafu)
2777                    .map_err(|err| ConvertValueError {
2778                        requested: "DicomDateTime",
2779                        original: self.value_type(),
2780                        cause: Some(Box::from(err)),
2781                    })
2782            }
2783            PrimitiveValue::Strs(s) => super::deserialize::parse_datetime_partial(
2784                s.first().map(|s| s.trim_end_matches(whitespace_or_null).as_bytes()).unwrap_or(&[]),
2785            )
2786            .context(ParseDateTimeSnafu)
2787            .map_err(|err| ConvertValueError {
2788                requested: "DicomDateTime",
2789                original: self.value_type(),
2790                cause: Some(Box::from(err)),
2791            }),
2792            PrimitiveValue::U8(bytes) => {
2793                super::deserialize::parse_datetime_partial(trim_last_whitespace(bytes))
2794                    .context(ParseDateTimeSnafu)
2795                    .map_err(|err| ConvertValueError {
2796                        requested: "DicomDateTime",
2797                        original: self.value_type(),
2798                        cause: Some(Box::from(err)),
2799                    })
2800            }
2801            _ => Err(ConvertValueError {
2802                requested: "DicomDateTime",
2803                original: self.value_type(),
2804                cause: None,
2805            }),
2806        }
2807    }
2808
2809    /// Retrieve the full sequence of `DicomDateTime`s from this value.
2810    ///
2811    pub fn to_multi_datetime(&self) -> Result<Vec<DicomDateTime>, ConvertValueError> {
2812        match self {
2813            PrimitiveValue::DateTime(v) => Ok(v.to_vec()),
2814            PrimitiveValue::Str(s) => {
2815                super::deserialize::parse_datetime_partial(s.trim_end_matches(whitespace_or_null).as_bytes())
2816                    .map(|date| vec![date])
2817                    .context(ParseDateSnafu)
2818                    .map_err(|err| ConvertValueError {
2819                        requested: "DicomDateTime",
2820                        original: self.value_type(),
2821                        cause: Some(Box::from(err)),
2822                    })
2823            }
2824            PrimitiveValue::Strs(s) => s
2825                .into_iter()
2826                .map(|s| super::deserialize::parse_datetime_partial(s.trim_end_matches(whitespace_or_null).as_bytes()))
2827                .collect::<Result<Vec<_>, _>>()
2828                .context(ParseDateSnafu)
2829                .map_err(|err| ConvertValueError {
2830                    requested: "DicomDateTime",
2831                    original: self.value_type(),
2832                    cause: Some(Box::from(err)),
2833                }),
2834            PrimitiveValue::U8(bytes) => trim_last_whitespace(bytes)
2835                .split(|c| *c == b'\\')
2836                .map(super::deserialize::parse_datetime_partial)
2837                .collect::<Result<Vec<_>, _>>()
2838                .context(ParseDateSnafu)
2839                .map_err(|err| ConvertValueError {
2840                    requested: "DicomDateTime",
2841                    original: self.value_type(),
2842                    cause: Some(Box::from(err)),
2843                }),
2844            _ => Err(ConvertValueError {
2845                requested: "DicomDateTime",
2846                original: self.value_type(),
2847                cause: None,
2848            }),
2849        }
2850    }
2851    /// Retrieve a single `DateRange` from this value.
2852    ///
2853    /// If the value is already represented as a `DicomDate`, it is converted into `DateRange`.
2854    /// If the value is a string or sequence of strings,
2855    /// the first string is decoded to obtain a `DateRange`, potentially failing if the
2856    /// string does not represent a valid `DateRange`.
2857    /// If the value is a sequence of U8 bytes, the bytes are
2858    /// first interpreted as an ASCII character string.
2859    ///
2860    /// # Example
2861    ///
2862    /// ```
2863    /// # use dicom_core::value::{C, PrimitiveValue};
2864    /// use chrono::{NaiveDate};
2865    /// # use std::error::Error;
2866    /// use dicom_core::value::{DateRange};
2867    ///
2868    /// # fn main() -> Result<(), Box<dyn Error>> {
2869    ///
2870    /// let da_range = PrimitiveValue::from("2012-201305").to_date_range()?;
2871    ///
2872    /// assert_eq!(
2873    ///     da_range.start(),
2874    ///     Some(&NaiveDate::from_ymd(2012, 1, 1))
2875    /// );
2876    /// assert_eq!(
2877    ///     da_range.end(),
2878    ///     Some(&NaiveDate::from_ymd(2013, 05, 31))
2879    /// );
2880    ///
2881    /// let range_from = PrimitiveValue::from("2012-").to_date_range()?;
2882    ///
2883    /// assert!(range_from.end().is_none());
2884    ///
2885    /// # Ok(())
2886    /// # }
2887    /// ```
2888    pub fn to_date_range(&self) -> Result<DateRange, ConvertValueError> {
2889        match self {
2890            PrimitiveValue::Date(da) if !da.is_empty() => da[0]
2891                .range()
2892                .context(ParseDateRangeSnafu)
2893                .map_err(|err| ConvertValueError {
2894                    requested: "DateRange",
2895                    original: self.value_type(),
2896                    cause: Some(Box::from(err)),
2897                }),
2898            PrimitiveValue::Str(s) => super::range::parse_date_range(s.trim_end_matches(whitespace_or_null).as_bytes())
2899                .context(ParseDateRangeSnafu)
2900                .map_err(|err| ConvertValueError {
2901                    requested: "DateRange",
2902                    original: self.value_type(),
2903                    cause: Some(Box::from(err)),
2904                }),
2905            PrimitiveValue::Strs(s) => super::range::parse_date_range(
2906                s.first().map(|s| s.trim_end_matches(whitespace_or_null).as_bytes()).unwrap_or(&[]),
2907            )
2908            .context(ParseDateRangeSnafu)
2909            .map_err(|err| ConvertValueError {
2910                requested: "DateRange",
2911                original: self.value_type(),
2912                cause: Some(Box::from(err)),
2913            }),
2914            PrimitiveValue::U8(bytes) => {
2915                super::range::parse_date_range(trim_last_whitespace(bytes))
2916                    .context(ParseDateRangeSnafu)
2917                    .map_err(|err| ConvertValueError {
2918                        requested: "DateRange",
2919                        original: self.value_type(),
2920                        cause: Some(Box::from(err)),
2921                    })
2922            }
2923            _ => Err(ConvertValueError {
2924                requested: "DateRange",
2925                original: self.value_type(),
2926                cause: None,
2927            }),
2928        }
2929    }
2930
2931    /// Retrieve a single `TimeRange` from this value.
2932    ///
2933    /// If the value is already represented as a `DicomTime`, it is converted into a `TimeRange`.
2934    /// If the value is a string or sequence of strings,
2935    /// the first string is decoded to obtain a `TimeRange`, potentially failing if the
2936    /// string does not represent a valid `DateRange`.
2937    /// If the value is a sequence of U8 bytes, the bytes are
2938    /// first interpreted as an ASCII character string.
2939    ///
2940    /// # Example
2941    ///
2942    /// ```
2943    /// # use dicom_core::value::{C, PrimitiveValue};
2944    /// use chrono::{NaiveTime};
2945    /// # use std::error::Error;
2946    /// use dicom_core::value::{TimeRange};
2947    ///
2948    /// # fn main() -> Result<(), Box<dyn Error>> {
2949    ///
2950    /// let tm_range = PrimitiveValue::from("02-153000.123").to_time_range()?;
2951    ///
2952    /// // null components default to zeros
2953    /// assert_eq!(
2954    ///     tm_range.start(),
2955    ///     Some(&NaiveTime::from_hms(2, 0, 0))
2956    /// );
2957    ///
2958    /// // unspecified part of second fraction defaults to latest possible
2959    /// assert_eq!(
2960    ///     tm_range.end(),
2961    ///     Some(&NaiveTime::from_hms_micro(15, 30, 0, 123_999))
2962    /// );
2963    ///
2964    /// let range_from = PrimitiveValue::from("01-").to_time_range()?;
2965    ///
2966    /// assert!(range_from.end().is_none());
2967    ///
2968    /// # Ok(())
2969    /// # }
2970    /// ```
2971    pub fn to_time_range(&self) -> Result<TimeRange, ConvertValueError> {
2972        match self {
2973            PrimitiveValue::Time(t) if !t.is_empty() => t[0]
2974                .range()
2975                .context(ParseTimeRangeSnafu)
2976                .map_err(|err| ConvertValueError {
2977                    requested: "TimeRange",
2978                    original: self.value_type(),
2979                    cause: Some(Box::from(err)),
2980                }),
2981            PrimitiveValue::Str(s) => super::range::parse_time_range(s.trim_end_matches(whitespace_or_null).as_bytes())
2982                .context(ParseTimeRangeSnafu)
2983                .map_err(|err| ConvertValueError {
2984                    requested: "TimeRange",
2985                    original: self.value_type(),
2986                    cause: Some(Box::from(err)),
2987                }),
2988            PrimitiveValue::Strs(s) => super::range::parse_time_range(
2989                s.first().map(|s| s.trim_end_matches(whitespace_or_null).as_bytes()).unwrap_or(&[]),
2990            )
2991            .context(ParseTimeRangeSnafu)
2992            .map_err(|err| ConvertValueError {
2993                requested: "TimeRange",
2994                original: self.value_type(),
2995                cause: Some(Box::from(err)),
2996            }),
2997            PrimitiveValue::U8(bytes) => {
2998                super::range::parse_time_range(trim_last_whitespace(bytes))
2999                    .context(ParseTimeRangeSnafu)
3000                    .map_err(|err| ConvertValueError {
3001                        requested: "TimeRange",
3002                        original: self.value_type(),
3003                        cause: Some(Box::from(err)),
3004                    })
3005            }
3006            _ => Err(ConvertValueError {
3007                requested: "TimeRange",
3008                original: self.value_type(),
3009                cause: None,
3010            }),
3011        }
3012    }
3013
3014    /// Retrieve a single `DateTimeRange` from this value.
3015    ///
3016    /// If the value is already represented as a `DicomDateTime`, it is converted into `DateTimeRange`.
3017    /// If the value is a string or sequence of strings,
3018    /// the first string is decoded to obtain a `DateTimeRange`, potentially failing if the
3019    /// string does not represent a valid `DateTimeRange`.
3020    /// If the value is a sequence of U8 bytes, the bytes are
3021    /// first interpreted as an ASCII character string.
3022    ///
3023    /// # Example
3024    ///
3025    /// ```
3026    /// # use dicom_core::value::{C, PrimitiveValue};
3027    /// use chrono::{DateTime, NaiveDate, NaiveTime, NaiveDateTime, FixedOffset, TimeZone, Local};
3028    /// # use std::error::Error;
3029    /// use dicom_core::value::{DateTimeRange, PreciseDateTime};
3030    ///
3031    /// # fn main() -> Result<(), Box<dyn Error>> {
3032    ///
3033    /// // let's parse a text representation of a date-time range, where the lower bound is a microsecond
3034    /// // precision value with a time-zone (east +05:00) and the upper bound is a minimum precision value
3035    /// // with a time-zone
3036    /// let dt_range = PrimitiveValue::from("19920101153020.123+0500-1993+0300").to_datetime_range()?;
3037    ///
3038    /// // lower bound of range is parsed into a PreciseDateTimeResult::TimeZone variant
3039    /// assert_eq!(
3040    ///     dt_range.start(),
3041    ///     Some(PreciseDateTime::TimeZone(
3042    ///         FixedOffset::east_opt(5*3600).unwrap().ymd_opt(1992, 1, 1).unwrap()
3043    ///         .and_hms_micro_opt(15, 30, 20, 123_000).unwrap()
3044    ///         )  
3045    ///     )
3046    /// );
3047    ///
3048    /// // upper bound of range is parsed into a PreciseDateTimeResult::TimeZone variant
3049    /// assert_eq!(
3050    ///     dt_range.end(),
3051    ///     Some(PreciseDateTime::TimeZone(
3052    ///         FixedOffset::east_opt(3*3600).unwrap().ymd_opt(1993, 12, 31).unwrap()
3053    ///         .and_hms_micro_opt(23, 59, 59, 999_999).unwrap()
3054    ///         )  
3055    ///     )
3056    /// );
3057    ///
3058    /// let lower = PrimitiveValue::from("2012-").to_datetime_range()?;
3059    ///
3060    /// // range has no upper bound
3061    /// assert!(lower.end().is_none());
3062    ///
3063    /// // One time-zone in a range is missing
3064    /// let dt_range = PrimitiveValue::from("1992+0500-1993").to_datetime_range()?;
3065    ///
3066    /// // It will be replaced with the local clock time-zone offset
3067    /// // This can be customized with [to_datetime_range_custom()]
3068    /// assert_eq!(
3069    ///   dt_range,
3070    ///   DateTimeRange::TimeZone{
3071    ///         start: Some(FixedOffset::east_opt(5*3600).unwrap()
3072    ///             .ymd_opt(1992, 1, 1).unwrap()
3073    ///             .and_hms_micro_opt(0, 0, 0, 0).unwrap()
3074    ///         ),
3075    ///         end: Some(Local::now().offset()
3076    ///             .ymd_opt(1993, 12, 31).unwrap()
3077    ///             .and_hms_micro_opt(23, 59, 59, 999_999).unwrap()
3078    ///         )
3079    ///     }
3080    /// );
3081    ///
3082    /// # Ok(())
3083    /// # }
3084    /// ```
3085    pub fn to_datetime_range(&self) -> Result<DateTimeRange, ConvertValueError> {
3086        match self {
3087            PrimitiveValue::DateTime(dt) if !dt.is_empty() => dt[0]
3088                .range()
3089                .context(ParseDateTimeRangeSnafu)
3090                .map_err(|err| ConvertValueError {
3091                    requested: "DateTimeRange",
3092                    original: self.value_type(),
3093                    cause: Some(Box::from(err)),
3094                }),
3095            PrimitiveValue::Str(s) => super::range::parse_datetime_range(s.trim_end_matches(whitespace_or_null).as_bytes())
3096                .context(ParseDateTimeRangeSnafu)
3097                .map_err(|err| ConvertValueError {
3098                    requested: "DateTimeRange",
3099                    original: self.value_type(),
3100                    cause: Some(Box::from(err)),
3101                }),
3102            PrimitiveValue::Strs(s) => super::range::parse_datetime_range(
3103                s.first().map(|s| s.trim_end_matches(whitespace_or_null).as_bytes()).unwrap_or(&[]),
3104            )
3105            .context(ParseDateTimeRangeSnafu)
3106            .map_err(|err| ConvertValueError {
3107                requested: "DateTimeRange",
3108                original: self.value_type(),
3109                cause: Some(Box::from(err)),
3110            }),
3111            PrimitiveValue::U8(bytes) => {
3112                super::range::parse_datetime_range(trim_last_whitespace(bytes))
3113                    .context(ParseDateTimeRangeSnafu)
3114                    .map_err(|err| ConvertValueError {
3115                        requested: "DateTimeRange",
3116                        original: self.value_type(),
3117                        cause: Some(Box::from(err)),
3118                    })
3119            }
3120            _ => Err(ConvertValueError {
3121                requested: "DateTimeRange",
3122                original: self.value_type(),
3123                cause: None,
3124            }),
3125        }
3126    }
3127
3128    /// Retrieve a single `DateTimeRange` from this value.
3129    ///
3130    /// Use a custom ambiguous date-time range parser.
3131    ///
3132    /// For full description see [PrimitiveValue::to_datetime_range] and [AmbiguousDtRangeParser].
3133    /// # Example
3134    ///
3135    /// ```
3136    /// # use dicom_core::value::{C, PrimitiveValue};
3137    /// # use std::error::Error;
3138    /// use dicom_core::value::range::{AmbiguousDtRangeParser, ToKnownTimeZone, IgnoreTimeZone, FailOnAmbiguousRange, DateTimeRange};
3139    /// use chrono::{NaiveDate, NaiveTime, NaiveDateTime};
3140    /// # fn main() -> Result<(), Box<dyn Error>> {
3141    ///
3142    /// // The upper bound time-zone is missing
3143    /// // the default behavior in this case is to use the local clock time-zone.
3144    /// // But we want to use the known (parsed) time-zone from the lower bound instead.
3145    /// let dt_range = PrimitiveValue::from("1992+0500-1993")
3146    ///     .to_datetime_range_custom::<ToKnownTimeZone>()?;
3147    ///
3148    /// // values are in the same time-zone
3149    /// assert_eq!(
3150    ///     dt_range.start().unwrap()
3151    ///         .as_datetime().unwrap()
3152    ///         .offset(),
3153    ///     dt_range.end().unwrap()
3154    ///         .as_datetime().unwrap()
3155    ///         .offset()
3156    /// );
3157    ///
3158    /// // ignore parsed time-zone, retrieve a time-zone naive range
3159    /// let naive_range = PrimitiveValue::from("1992+0599-1993")
3160    ///     .to_datetime_range_custom::<IgnoreTimeZone>()?;
3161    ///
3162    /// assert_eq!(
3163    ///     naive_range,
3164    ///     DateTimeRange::from_start_to_end(
3165    ///         NaiveDateTime::new(
3166    ///             NaiveDate::from_ymd_opt(1992, 1, 1).unwrap(),
3167    ///             NaiveTime::from_hms_micro_opt(0, 0, 0, 0).unwrap()
3168    ///         ),
3169    ///         NaiveDateTime::new(
3170    ///             NaiveDate::from_ymd_opt(1993, 12, 31).unwrap(),
3171    ///             NaiveTime::from_hms_micro_opt(23, 59, 59, 999_999).unwrap()
3172    ///         )
3173    ///     ).unwrap()
3174    /// );
3175    ///
3176    /// // always fail upon parsing an ambiguous DT range
3177    /// assert!(
3178    /// PrimitiveValue::from("1992+0599-1993")
3179    ///     .to_datetime_range_custom::<FailOnAmbiguousRange>().is_err()
3180    /// );
3181    ///
3182    ///
3183    ///
3184    /// # Ok(())
3185    /// # }
3186    /// ```
3187    pub fn to_datetime_range_custom<T: AmbiguousDtRangeParser>(
3188        &self,
3189    ) -> Result<DateTimeRange, ConvertValueError> {
3190        match self {
3191            PrimitiveValue::DateTime(dt) if !dt.is_empty() => dt[0]
3192                .range()
3193                .context(ParseDateTimeRangeSnafu)
3194                .map_err(|err| ConvertValueError {
3195                    requested: "DateTimeRange",
3196                    original: self.value_type(),
3197                    cause: Some(Box::from(err)),
3198                }),
3199            PrimitiveValue::Str(s) => {
3200                super::range::parse_datetime_range_custom::<T>(s.trim_end_matches(whitespace_or_null).as_bytes())
3201                    .context(ParseDateTimeRangeSnafu)
3202                    .map_err(|err| ConvertValueError {
3203                        requested: "DateTimeRange",
3204                        original: self.value_type(),
3205                        cause: Some(Box::from(err)),
3206                    })
3207            }
3208            PrimitiveValue::Strs(s) => super::range::parse_datetime_range_custom::<T>(
3209                s.first().map(|s| s.trim_end_matches(whitespace_or_null).as_bytes()).unwrap_or(&[]),
3210            )
3211            .context(ParseDateTimeRangeSnafu)
3212            .map_err(|err| ConvertValueError {
3213                requested: "DateTimeRange",
3214                original: self.value_type(),
3215                cause: Some(Box::from(err)),
3216            }),
3217            PrimitiveValue::U8(bytes) => {
3218                super::range::parse_datetime_range_custom::<T>(trim_last_whitespace(bytes))
3219                    .context(ParseDateTimeRangeSnafu)
3220                    .map_err(|err| ConvertValueError {
3221                        requested: "DateTimeRange",
3222                        original: self.value_type(),
3223                        cause: Some(Box::from(err)),
3224                    })
3225            }
3226            _ => Err(ConvertValueError {
3227                requested: "DateTimeRange",
3228                original: self.value_type(),
3229                cause: None,
3230            }),
3231        }
3232    }
3233
3234    /// Retrieve a single [`PersonName`][1] from this value.
3235    ///
3236    /// If the value is a string or sequence of strings,
3237    /// the first string is split to obtain a `PersonName`.
3238    ///
3239    /// [1]: super::person_name::PersonName
3240    ///
3241    /// # Example
3242    ///
3243    /// ```
3244    /// # use dicom_core::value::{C, PrimitiveValue};
3245    /// # use std::error::Error;
3246    /// use dicom_core::value::PersonName;
3247    /// # fn main() -> Result<(), Box<dyn Error>> {
3248    ///
3249    /// let value = PrimitiveValue::from("Tooms^Victor^Eugene");
3250    /// // PersonName contains borrowed values
3251    /// let pn = value.to_person_name()?;
3252    ///
3253    /// assert_eq!(pn.given(), Some("Victor"));
3254    /// assert_eq!(pn.middle(), Some("Eugene"));
3255    /// assert!(pn.prefix().is_none());
3256    ///
3257    /// let value2 = PrimitiveValue::from(pn);
3258    ///
3259    /// assert_eq!(value, value2);
3260    ///
3261    /// # Ok(())
3262    /// # }
3263    /// ```
3264    pub fn to_person_name(&self) -> Result<PersonName<'_>, ConvertValueError> {
3265        match self {
3266            PrimitiveValue::Str(s) => Ok(PersonName::from_text(s)),
3267            PrimitiveValue::Strs(s) => s.first().map_or_else(
3268                || {
3269                    Err(ConvertValueError {
3270                        requested: "PersonName",
3271                        original: self.value_type(),
3272                        cause: None,
3273                    })
3274                },
3275                |s| Ok(PersonName::from_text(s)),
3276            ),
3277            _ => Err(ConvertValueError {
3278                requested: "PersonName",
3279                original: self.value_type(),
3280                cause: None,
3281            }),
3282        }
3283    }
3284}
3285
3286/// Macro for implementing getters to single and multi-values of each variant.
3287///
3288/// Should be placed inside `PrimitiveValue`'s impl block.
3289macro_rules! impl_primitive_getters {
3290    ($name_single: ident, $name_multi: ident, $variant: ident, $ret: ty) => {
3291        /// Get a single value of the requested type.
3292        /// If it contains multiple values,
3293        /// only the first one is returned.
3294        /// An error is returned if the variant is not compatible.
3295        pub fn $name_single(&self) -> Result<$ret, CastValueError> {
3296            match self {
3297                PrimitiveValue::$variant(c) if c.is_empty() => Err(CastValueError {
3298                    requested: stringify!($name_single),
3299                    got: ValueType::Empty,
3300                }),
3301                PrimitiveValue::$variant(c) => Ok(c[0]),
3302                value => Err(CastValueError {
3303                    requested: stringify!($name_single),
3304                    got: value.value_type(),
3305                }),
3306            }
3307        }
3308
3309        /// Get a sequence of values of the requested type without copying.
3310        /// An error is returned if the variant is not compatible.
3311        pub fn $name_multi(&self) -> Result<&[$ret], CastValueError> {
3312            match self {
3313                PrimitiveValue::$variant(c) => Ok(&c),
3314                value => Err(CastValueError {
3315                    requested: stringify!($name_multi),
3316                    got: value.value_type(),
3317                }),
3318            }
3319        }
3320    };
3321}
3322
3323/// Per variant, strongly checked getters to DICOM values.
3324///
3325/// Conversions from one representation to another do not take place
3326/// when using these methods.
3327impl PrimitiveValue {
3328    /// Get a single string value.
3329    ///
3330    /// If it contains multiple strings,
3331    /// only the first one is returned.
3332    ///
3333    /// An error is returned if the variant is not compatible.
3334    ///
3335    /// To enable conversions of other variants to a textual representation,
3336    /// see [`to_str()`] instead.
3337    ///
3338    /// [`to_str()`]: #method.to_str
3339    pub fn string(&self) -> Result<&str, CastValueError> {
3340        use self::PrimitiveValue::*;
3341        match self {
3342            Strs(c) if c.is_empty() => Err(CastValueError {
3343                requested: "Str",
3344                got: ValueType::Empty,
3345            }),
3346            Strs(c) if !c.is_empty() => Ok(&c[0]),
3347            Str(s) => Ok(s),
3348            value => Err(CastValueError {
3349                requested: "Str",
3350                got: value.value_type(),
3351            }),
3352        }
3353    }
3354
3355    /// Get the inner sequence of string values
3356    /// if the variant is either `Str` or `Strs`.
3357    ///
3358    /// An error is returned if the variant is not compatible.
3359    ///
3360    /// To enable conversions of other variants to a textual representation,
3361    /// see [`to_str()`] instead.
3362    ///
3363    /// [`to_str()`]: #method.to_str
3364    pub fn strings(&self) -> Result<&[String], CastValueError> {
3365        use self::PrimitiveValue::*;
3366        match self {
3367            Strs(c) => Ok(c),
3368            Str(s) => Ok(std::slice::from_ref(s)),
3369            value => Err(CastValueError {
3370                requested: "strings",
3371                got: value.value_type(),
3372            }),
3373        }
3374    }
3375
3376    impl_primitive_getters!(tag, tags, Tags, Tag);
3377    impl_primitive_getters!(date, dates, Date, DicomDate);
3378    impl_primitive_getters!(time, times, Time, DicomTime);
3379    impl_primitive_getters!(datetime, datetimes, DateTime, DicomDateTime);
3380    impl_primitive_getters!(uint8, uint8_slice, U8, u8);
3381    impl_primitive_getters!(uint16, uint16_slice, U16, u16);
3382    impl_primitive_getters!(int16, int16_slice, I16, i16);
3383    impl_primitive_getters!(uint32, uint32_slice, U32, u32);
3384    impl_primitive_getters!(int32, int32_slice, I32, i32);
3385    impl_primitive_getters!(int64, int64_slice, I64, i64);
3386    impl_primitive_getters!(uint64, uint64_slice, U64, u64);
3387    impl_primitive_getters!(float32, float32_slice, F32, f32);
3388    impl_primitive_getters!(float64, float64_slice, F64, f64);
3389
3390    /// Extend a textual value by appending
3391    /// more strings to an existing text or empty value.
3392    ///
3393    /// An error is returned if the current value is not textual.
3394    ///
3395    /// # Example
3396    ///
3397    /// ```
3398    /// use dicom_core::dicom_value;
3399    /// # use dicom_core::value::ModifyValueError;
3400    ///
3401    /// # fn main() -> Result<(), ModifyValueError> {
3402    /// let mut value = dicom_value!(Strs, ["Hello"]);
3403    /// value.extend_str(["DICOM"])?;
3404    /// assert_eq!(value.to_string(), "Hello\\DICOM");
3405    /// # Ok(())
3406    /// # }
3407    /// ```
3408    pub fn extend_str<T>(
3409        &mut self,
3410        strings: impl IntoIterator<Item = T>,
3411    ) -> Result<(), ModifyValueError>
3412    where
3413        T: Into<String>,
3414    {
3415        match self {
3416            PrimitiveValue::Empty => {
3417                *self = PrimitiveValue::Strs(strings.into_iter().map(T::into).collect());
3418                Ok(())
3419            }
3420            PrimitiveValue::Strs(elements) => {
3421                elements.extend(strings.into_iter().map(T::into));
3422                Ok(())
3423            }
3424            PrimitiveValue::Str(s) => {
3425                // for lack of better ways to move the string out from the mutable borrow,
3426                // we create a copy for now
3427                let s = s.clone();
3428                *self = PrimitiveValue::Strs(
3429                    std::iter::once(s)
3430                        .chain(strings.into_iter().map(T::into))
3431                        .collect(),
3432                );
3433                Ok(())
3434            }
3435            PrimitiveValue::Tags(_)
3436            | PrimitiveValue::U8(_)
3437            | PrimitiveValue::I16(_)
3438            | PrimitiveValue::U16(_)
3439            | PrimitiveValue::I32(_)
3440            | PrimitiveValue::U32(_)
3441            | PrimitiveValue::I64(_)
3442            | PrimitiveValue::U64(_)
3443            | PrimitiveValue::F32(_)
3444            | PrimitiveValue::F64(_)
3445            | PrimitiveValue::Date(_)
3446            | PrimitiveValue::DateTime(_)
3447            | PrimitiveValue::Time(_) => IncompatibleStringTypeSnafu {
3448                original: self.value_type(),
3449            }
3450            .fail(),
3451        }
3452    }
3453
3454    /// Extend a value of numbers by appending
3455    /// 16-bit unsigned integers to an existing value.
3456    ///
3457    /// The value may be empty
3458    /// or already contain numeric or textual values.
3459    ///
3460    /// If the current value is textual,
3461    /// the numbers provided are converted to text.
3462    /// For the case of numeric values,
3463    /// the given numbers are _converted to the current number type
3464    /// through casting_,
3465    /// meaning that loss of precision may occur.
3466    /// If this is undesirable,
3467    /// read the current value and replace it manually.
3468    ///
3469    /// An error is returned
3470    /// if the current value is not compatible with the insertion of integers,
3471    /// such as `Tag` or `Date`.
3472    ///
3473    /// # Example
3474    ///
3475    /// ```
3476    /// use dicom_core::dicom_value;
3477    ///
3478    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
3479    /// let mut value = dicom_value!(U16, [1, 2]);
3480    /// value.extend_u16([5])?;
3481    /// assert_eq!(value.to_multi_int::<u16>()?, vec![1, 2, 5]);
3482    ///
3483    /// let mut value = dicom_value!(Strs, ["City"]);
3484    /// value.extend_u16([17])?;
3485    /// assert_eq!(value.to_string(), "City\\17");
3486    /// # Ok(())
3487    /// # }
3488    /// ```
3489    pub fn extend_u16(
3490        &mut self,
3491        numbers: impl IntoIterator<Item = u16>,
3492    ) -> Result<(), ModifyValueError> {
3493        match self {
3494            PrimitiveValue::Empty => {
3495                *self = PrimitiveValue::U16(numbers.into_iter().collect());
3496                Ok(())
3497            }
3498            PrimitiveValue::Strs(elements) => {
3499                elements.extend(numbers.into_iter().map(|n| n.to_string()));
3500                Ok(())
3501            }
3502            PrimitiveValue::Str(s) => {
3503                // for lack of better ways to move the string out from the mutable borrow,
3504                // we create a copy for now
3505                let s = s.clone();
3506                *self = PrimitiveValue::Strs(
3507                    std::iter::once(s)
3508                        .chain(numbers.into_iter().map(|n| n.to_string()))
3509                        .collect(),
3510                );
3511                Ok(())
3512            }
3513            PrimitiveValue::U16(elements) => {
3514                elements.extend(numbers);
3515                Ok(())
3516            }
3517            PrimitiveValue::U8(elements) => {
3518                elements.extend(numbers.into_iter().map(|n| n as u8));
3519                Ok(())
3520            }
3521            PrimitiveValue::I16(elements) => {
3522                elements.extend(numbers.into_iter().map(|n| n as i16));
3523                Ok(())
3524            }
3525            PrimitiveValue::U32(elements) => {
3526                elements.extend(numbers.into_iter().map(|n| n as u32));
3527                Ok(())
3528            }
3529            PrimitiveValue::I32(elements) => {
3530                elements.extend(numbers.into_iter().map(|n| n as i32));
3531                Ok(())
3532            }
3533            PrimitiveValue::I64(elements) => {
3534                elements.extend(numbers.into_iter().map(|n| n as i64));
3535                Ok(())
3536            }
3537            PrimitiveValue::U64(elements) => {
3538                elements.extend(numbers.into_iter().map(|n| n as u64));
3539                Ok(())
3540            }
3541            PrimitiveValue::F32(elements) => {
3542                elements.extend(numbers.into_iter().map(|n| n as f32));
3543                Ok(())
3544            }
3545            PrimitiveValue::F64(elements) => {
3546                elements.extend(numbers.into_iter().map(|n| n as f64));
3547                Ok(())
3548            }
3549            PrimitiveValue::Tags(_)
3550            | PrimitiveValue::Date(_)
3551            | PrimitiveValue::DateTime(_)
3552            | PrimitiveValue::Time(_) => IncompatibleNumberTypeSnafu {
3553                original: self.value_type(),
3554            }
3555            .fail(),
3556        }
3557    }
3558
3559    /// Extend a value of numbers by appending
3560    /// 16-bit signed integers to an existing value.
3561    ///
3562    /// The value may be empty
3563    /// or already contain numeric or textual values.
3564    ///
3565    /// If the current value is textual,
3566    /// the numbers provided are converted to text.
3567    /// For the case of numeric values,
3568    /// the given numbers are _converted to the current number type
3569    /// through casting_,
3570    /// meaning that loss of precision may occur.
3571    /// If this is undesirable,
3572    /// read the current value and replace it manually.
3573    ///
3574    /// An error is returned
3575    /// if the current value is not compatible with the insertion of integers,
3576    /// such as `Tag` or `Date`.
3577    ///
3578    /// # Example
3579    ///
3580    /// ```
3581    /// use dicom_core::dicom_value;
3582    ///
3583    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
3584    /// let mut value = dicom_value!(I16, [1, 2]);
3585    /// value.extend_i16([-5])?;
3586    /// assert_eq!(value.to_multi_int::<i16>()?, vec![1, 2, -5]);
3587    ///
3588    /// let mut value = dicom_value!(Strs, ["City"]);
3589    /// value.extend_i16([17])?;
3590    /// assert_eq!(value.to_string(), "City\\17");
3591    /// # Ok(())
3592    /// # }
3593    /// ```
3594    pub fn extend_i16(
3595        &mut self,
3596        numbers: impl IntoIterator<Item = i16>,
3597    ) -> Result<(), ModifyValueError> {
3598        match self {
3599            PrimitiveValue::Empty => {
3600                *self = PrimitiveValue::I16(numbers.into_iter().collect());
3601                Ok(())
3602            }
3603            PrimitiveValue::Strs(elements) => {
3604                elements.extend(numbers.into_iter().map(|n| n.to_string()));
3605                Ok(())
3606            }
3607            PrimitiveValue::Str(s) => {
3608                // for lack of better ways to move the string out from the mutable borrow,
3609                // we create a copy for now
3610                let s = s.clone();
3611                *self = PrimitiveValue::Strs(
3612                    std::iter::once(s)
3613                        .chain(numbers.into_iter().map(|n| n.to_string()))
3614                        .collect(),
3615                );
3616                Ok(())
3617            }
3618            PrimitiveValue::I16(elements) => {
3619                elements.extend(numbers);
3620                Ok(())
3621            }
3622            PrimitiveValue::U8(elements) => {
3623                elements.extend(numbers.into_iter().map(|n| n as u8));
3624                Ok(())
3625            }
3626            PrimitiveValue::U16(elements) => {
3627                elements.extend(numbers.into_iter().map(|n| n as u16));
3628                Ok(())
3629            }
3630            PrimitiveValue::U32(elements) => {
3631                elements.extend(numbers.into_iter().map(|n| n as u32));
3632                Ok(())
3633            }
3634            PrimitiveValue::I32(elements) => {
3635                elements.extend(numbers.into_iter().map(|n| n as i32));
3636                Ok(())
3637            }
3638            PrimitiveValue::I64(elements) => {
3639                elements.extend(numbers.into_iter().map(|n| n as i64));
3640                Ok(())
3641            }
3642            PrimitiveValue::U64(elements) => {
3643                elements.extend(numbers.into_iter().map(|n| n as u64));
3644                Ok(())
3645            }
3646            PrimitiveValue::F32(elements) => {
3647                elements.extend(numbers.into_iter().map(|n| n as f32));
3648                Ok(())
3649            }
3650            PrimitiveValue::F64(elements) => {
3651                elements.extend(numbers.into_iter().map(|n| n as f64));
3652                Ok(())
3653            }
3654            PrimitiveValue::Tags(_)
3655            | PrimitiveValue::Date(_)
3656            | PrimitiveValue::DateTime(_)
3657            | PrimitiveValue::Time(_) => IncompatibleNumberTypeSnafu {
3658                original: self.value_type(),
3659            }
3660            .fail(),
3661        }
3662    }
3663
3664    /// Extend a value of numbers by appending
3665    /// 32-bit signed integers to an existing value.
3666    ///
3667    /// The value may be empty
3668    /// or already contain numeric or textual values.
3669    ///
3670    /// If the current value is textual,
3671    /// the numbers provided are converted to text.
3672    /// For the case of numeric values,
3673    /// the given numbers are _converted to the current number type
3674    /// through casting_,
3675    /// meaning that loss of precision may occur.
3676    /// If this is undesirable,
3677    /// read the current value and replace it manually.
3678    ///
3679    /// An error is returned
3680    /// if the current value is not compatible with the insertion of integers,
3681    /// such as `Tag` or `Date`.
3682    ///
3683    /// # Example
3684    ///
3685    /// ```
3686    /// use dicom_core::dicom_value;
3687    ///
3688    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
3689    /// let mut value = dicom_value!(I32, [1, 2]);
3690    /// value.extend_i32([5])?;
3691    /// assert_eq!(value.to_multi_int::<i32>()?, vec![1, 2, 5]);
3692    ///
3693    /// let mut value = dicom_value!(Strs, ["City"]);
3694    /// value.extend_i32([17])?;
3695    /// assert_eq!(value.to_string(), "City\\17");
3696    /// # Ok(())
3697    /// # }
3698    /// ```
3699    pub fn extend_i32(
3700        &mut self,
3701        numbers: impl IntoIterator<Item = i32>,
3702    ) -> Result<(), ModifyValueError> {
3703        match self {
3704            PrimitiveValue::Empty => {
3705                *self = PrimitiveValue::I32(numbers.into_iter().collect());
3706                Ok(())
3707            }
3708            PrimitiveValue::Strs(elements) => {
3709                elements.extend(numbers.into_iter().map(|n| n.to_string()));
3710                Ok(())
3711            }
3712            PrimitiveValue::Str(s) => {
3713                // for lack of better ways to move the string out from the mutable borrow,
3714                // we create a copy for now
3715                let s = s.clone();
3716                *self = PrimitiveValue::Strs(
3717                    std::iter::once(s)
3718                        .chain(numbers.into_iter().map(|n| n.to_string()))
3719                        .collect(),
3720                );
3721                Ok(())
3722            }
3723            PrimitiveValue::I32(elements) => {
3724                elements.extend(numbers);
3725                Ok(())
3726            }
3727            PrimitiveValue::U8(elements) => {
3728                elements.extend(numbers.into_iter().map(|n| n as u8));
3729                Ok(())
3730            }
3731            PrimitiveValue::I16(elements) => {
3732                elements.extend(numbers.into_iter().map(|n| n as i16));
3733                Ok(())
3734            }
3735            PrimitiveValue::U16(elements) => {
3736                elements.extend(numbers.into_iter().map(|n| n as u16));
3737                Ok(())
3738            }
3739            PrimitiveValue::U32(elements) => {
3740                elements.extend(numbers.into_iter().map(|n| n as u32));
3741                Ok(())
3742            }
3743            PrimitiveValue::I64(elements) => {
3744                elements.extend(numbers.into_iter().map(|n| n as i64));
3745                Ok(())
3746            }
3747            PrimitiveValue::U64(elements) => {
3748                elements.extend(numbers.into_iter().map(|n| n as u64));
3749                Ok(())
3750            }
3751            PrimitiveValue::F32(elements) => {
3752                elements.extend(numbers.into_iter().map(|n| n as f32));
3753                Ok(())
3754            }
3755            PrimitiveValue::F64(elements) => {
3756                elements.extend(numbers.into_iter().map(|n| n as f64));
3757                Ok(())
3758            }
3759            PrimitiveValue::Tags(_)
3760            | PrimitiveValue::Date(_)
3761            | PrimitiveValue::DateTime(_)
3762            | PrimitiveValue::Time(_) => IncompatibleNumberTypeSnafu {
3763                original: self.value_type(),
3764            }
3765            .fail(),
3766        }
3767    }
3768
3769    /// Extend a value of numbers by appending
3770    /// 32-bit unsigned integers to an existing value.
3771    ///
3772    /// The value may be empty
3773    /// or already contain numeric or textual values.
3774    ///
3775    /// If the current value is textual,
3776    /// the numbers provided are converted to text.
3777    /// For the case of numeric values,
3778    /// the given numbers are _converted to the current number type
3779    /// through casting_,
3780    /// meaning that loss of precision may occur.
3781    /// If this is undesirable,
3782    /// read the current value and replace it manually.
3783    ///
3784    /// An error is returned
3785    /// if the current value is not compatible with the insertion of integers,
3786    /// such as `Tag` or `Date`.
3787    ///
3788    /// # Example
3789    ///
3790    /// ```
3791    /// use dicom_core::dicom_value;
3792    ///
3793    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
3794    /// let mut value = dicom_value!(U32, [1, 2]);
3795    /// value.extend_u32([5])?;
3796    /// assert_eq!(value.to_multi_int::<u32>()?, vec![1, 2, 5]);
3797    ///
3798    /// let mut value = dicom_value!(Strs, ["City"]);
3799    /// value.extend_u32([17])?;
3800    /// assert_eq!(value.to_string(), "City\\17");
3801    /// # Ok(())
3802    /// # }
3803    /// ```
3804    pub fn extend_u32(
3805        &mut self,
3806        numbers: impl IntoIterator<Item = u32>,
3807    ) -> Result<(), ModifyValueError> {
3808        match self {
3809            PrimitiveValue::Empty => {
3810                *self = PrimitiveValue::U32(numbers.into_iter().collect());
3811                Ok(())
3812            }
3813            PrimitiveValue::Strs(elements) => {
3814                elements.extend(numbers.into_iter().map(|n| n.to_string()));
3815                Ok(())
3816            }
3817            PrimitiveValue::Str(s) => {
3818                // for lack of better ways to move the string out from the mutable borrow,
3819                // we create a copy for now
3820                let s = s.clone();
3821                *self = PrimitiveValue::Strs(
3822                    std::iter::once(s)
3823                        .chain(numbers.into_iter().map(|n| n.to_string()))
3824                        .collect(),
3825                );
3826                Ok(())
3827            }
3828            PrimitiveValue::U32(elements) => {
3829                elements.extend(numbers);
3830                Ok(())
3831            }
3832            PrimitiveValue::U8(elements) => {
3833                elements.extend(numbers.into_iter().map(|n| n as u8));
3834                Ok(())
3835            }
3836            PrimitiveValue::I16(elements) => {
3837                elements.extend(numbers.into_iter().map(|n| n as i16));
3838                Ok(())
3839            }
3840            PrimitiveValue::U16(elements) => {
3841                elements.extend(numbers.into_iter().map(|n| n as u16));
3842                Ok(())
3843            }
3844            PrimitiveValue::I32(elements) => {
3845                elements.extend(numbers.into_iter().map(|n| n as i32));
3846                Ok(())
3847            }
3848            PrimitiveValue::I64(elements) => {
3849                elements.extend(numbers.into_iter().map(|n| n as i64));
3850                Ok(())
3851            }
3852            PrimitiveValue::U64(elements) => {
3853                elements.extend(numbers.into_iter().map(|n| n as u64));
3854                Ok(())
3855            }
3856            PrimitiveValue::F32(elements) => {
3857                elements.extend(numbers.into_iter().map(|n| n as f32));
3858                Ok(())
3859            }
3860            PrimitiveValue::F64(elements) => {
3861                elements.extend(numbers.into_iter().map(|n| n as f64));
3862                Ok(())
3863            }
3864            PrimitiveValue::Tags(_)
3865            | PrimitiveValue::Date(_)
3866            | PrimitiveValue::DateTime(_)
3867            | PrimitiveValue::Time(_) => IncompatibleNumberTypeSnafu {
3868                original: self.value_type(),
3869            }
3870            .fail(),
3871        }
3872    }
3873
3874    /// Extend a value of numbers by appending
3875    /// 32-bit floating point numbers to an existing value.
3876    ///
3877    /// The value may be empty
3878    /// or already contain numeric or textual values.
3879    ///
3880    /// If the current value is textual,
3881    /// the numbers provided are converted to text.
3882    /// For the case of numeric values,
3883    /// the given numbers are _converted to the current number type
3884    /// through casting_,
3885    /// meaning that loss of precision may occur.
3886    /// If this is undesirable,
3887    /// read the current value and replace it manually.
3888    ///
3889    /// An error is returned
3890    /// if the current value is not compatible with the insertion of integers,
3891    /// such as `Tag` or `Date`.
3892    ///
3893    /// # Example
3894    ///
3895    /// ```
3896    /// use dicom_core::dicom_value;
3897    ///
3898    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
3899    /// let mut value = dicom_value!(F32, [1., 2.]);
3900    /// value.extend_f32([5.])?;
3901    /// assert_eq!(value.to_multi_float32()?, vec![1., 2., 5.]);
3902    ///
3903    /// let mut value = dicom_value!(Strs, ["1.25"]);
3904    /// value.extend_f32([0.5])?;
3905    /// assert_eq!(value.to_string(), "1.25\\0.5");
3906    /// # Ok(())
3907    /// # }
3908    /// ```
3909    pub fn extend_f32(
3910        &mut self,
3911        numbers: impl IntoIterator<Item = f32>,
3912    ) -> Result<(), ModifyValueError> {
3913        match self {
3914            PrimitiveValue::Empty => {
3915                *self = PrimitiveValue::F32(numbers.into_iter().collect());
3916                Ok(())
3917            }
3918            PrimitiveValue::Strs(elements) => {
3919                elements.extend(numbers.into_iter().map(|n| n.to_string()));
3920                Ok(())
3921            }
3922            PrimitiveValue::Str(s) => {
3923                // for lack of better ways to move the string out from the mutable borrow,
3924                // we create a copy for now
3925                let s = s.clone();
3926                *self = PrimitiveValue::Strs(
3927                    std::iter::once(s)
3928                        .chain(numbers.into_iter().map(|n| n.to_string()))
3929                        .collect(),
3930                );
3931                Ok(())
3932            }
3933            PrimitiveValue::F32(elements) => {
3934                elements.extend(numbers);
3935                Ok(())
3936            }
3937            PrimitiveValue::U8(elements) => {
3938                elements.extend(numbers.into_iter().map(|n| n as u8));
3939                Ok(())
3940            }
3941            PrimitiveValue::I16(elements) => {
3942                elements.extend(numbers.into_iter().map(|n| n as i16));
3943                Ok(())
3944            }
3945            PrimitiveValue::U16(elements) => {
3946                elements.extend(numbers.into_iter().map(|n| n as u16));
3947                Ok(())
3948            }
3949            PrimitiveValue::I32(elements) => {
3950                elements.extend(numbers.into_iter().map(|n| n as i32));
3951                Ok(())
3952            }
3953            PrimitiveValue::I64(elements) => {
3954                elements.extend(numbers.into_iter().map(|n| n as i64));
3955                Ok(())
3956            }
3957            PrimitiveValue::U32(elements) => {
3958                elements.extend(numbers.into_iter().map(|n| n as u32));
3959                Ok(())
3960            }
3961            PrimitiveValue::U64(elements) => {
3962                elements.extend(numbers.into_iter().map(|n| n as u64));
3963                Ok(())
3964            }
3965            PrimitiveValue::F64(elements) => {
3966                elements.extend(numbers.into_iter().map(|n| n as f64));
3967                Ok(())
3968            }
3969            PrimitiveValue::Tags(_)
3970            | PrimitiveValue::Date(_)
3971            | PrimitiveValue::DateTime(_)
3972            | PrimitiveValue::Time(_) => IncompatibleNumberTypeSnafu {
3973                original: self.value_type(),
3974            }
3975            .fail(),
3976        }
3977    }
3978
3979    /// Extend a value of numbers by appending
3980    /// 64-bit floating point numbers to an existing value.
3981    ///
3982    /// The value may be empty
3983    /// or already contain numeric or textual values.
3984    ///
3985    /// If the current value is textual,
3986    /// the numbers provided are converted to text.
3987    /// For the case of numeric values,
3988    /// the given numbers are _converted to the current number type
3989    /// through casting_,
3990    /// meaning that loss of precision may occur.
3991    /// If this is undesirable,
3992    /// read the current value and replace it manually.
3993    ///
3994    /// An error is returned
3995    /// if the current value is not compatible with the insertion of integers,
3996    /// such as `Tag` or `Date`.
3997    ///
3998    /// # Example
3999    ///
4000    /// ```
4001    /// use dicom_core::dicom_value;
4002    ///
4003    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
4004    /// let mut value = dicom_value!(F64, [1., 2.]);
4005    /// value.extend_f64([5.])?;
4006    /// assert_eq!(value.to_multi_float64()?, vec![1., 2., 5.]);
4007    ///
4008    /// let mut value = dicom_value!(Strs, ["1.25"]);
4009    /// value.extend_f64([0.5])?;
4010    /// assert_eq!(value.to_string(), "1.25\\0.5");
4011    /// # Ok(())
4012    /// # }
4013    /// ```
4014    pub fn extend_f64(
4015        &mut self,
4016        numbers: impl IntoIterator<Item = f64>,
4017    ) -> Result<(), ModifyValueError> {
4018        match self {
4019            PrimitiveValue::Empty => {
4020                *self = PrimitiveValue::F64(numbers.into_iter().collect());
4021                Ok(())
4022            }
4023            PrimitiveValue::Strs(elements) => {
4024                elements.extend(numbers.into_iter().map(|n| n.to_string()));
4025                Ok(())
4026            }
4027            PrimitiveValue::Str(s) => {
4028                // for lack of better ways to move the string out from the mutable borrow,
4029                // we create a copy for now
4030                let s = s.clone();
4031                *self = PrimitiveValue::Strs(
4032                    std::iter::once(s)
4033                        .chain(numbers.into_iter().map(|n| n.to_string()))
4034                        .collect(),
4035                );
4036                Ok(())
4037            }
4038            PrimitiveValue::F64(elements) => {
4039                elements.extend(numbers);
4040                Ok(())
4041            }
4042            PrimitiveValue::U8(elements) => {
4043                elements.extend(numbers.into_iter().map(|n| n as u8));
4044                Ok(())
4045            }
4046            PrimitiveValue::I16(elements) => {
4047                elements.extend(numbers.into_iter().map(|n| n as i16));
4048                Ok(())
4049            }
4050            PrimitiveValue::U16(elements) => {
4051                elements.extend(numbers.into_iter().map(|n| n as u16));
4052                Ok(())
4053            }
4054            PrimitiveValue::I32(elements) => {
4055                elements.extend(numbers.into_iter().map(|n| n as i32));
4056                Ok(())
4057            }
4058            PrimitiveValue::I64(elements) => {
4059                elements.extend(numbers.into_iter().map(|n| n as i64));
4060                Ok(())
4061            }
4062            PrimitiveValue::U32(elements) => {
4063                elements.extend(numbers.into_iter().map(|n| n as u32));
4064                Ok(())
4065            }
4066            PrimitiveValue::U64(elements) => {
4067                elements.extend(numbers.into_iter().map(|n| n as u64));
4068                Ok(())
4069            }
4070            PrimitiveValue::F32(elements) => {
4071                elements.extend(numbers.into_iter().map(|n| n as f32));
4072                Ok(())
4073            }
4074            PrimitiveValue::Tags(_)
4075            | PrimitiveValue::Date(_)
4076            | PrimitiveValue::DateTime(_)
4077            | PrimitiveValue::Time(_) => Err(IncompatibleNumberTypeSnafu {
4078                original: self.value_type(),
4079            }
4080            .build()),
4081        }
4082    }
4083
4084    /// Shorten this value by removing trailing elements
4085    /// to fit the given limit.
4086    ///
4087    /// Elements are counted by the number of individual value items
4088    /// (note that bytes in a [`PrimitiveValue::U8`]
4089    /// are treated as individual items).
4090    ///
4091    /// Nothing is done if the value's cardinality
4092    /// is already lower than or equal to the limit.
4093    ///
4094    /// # Example
4095    ///
4096    /// ```
4097    /// # use dicom_core::dicom_value;
4098    /// # use dicom_core::value::PrimitiveValue;
4099    /// let mut value = dicom_value!(I32, [1, 2, 5]);
4100    /// value.truncate(2);
4101    /// assert_eq!(value.to_multi_int::<i32>()?, vec![1, 2]);
4102    ///
4103    /// value.truncate(0);
4104    /// assert_eq!(value.multiplicity(), 0);
4105    /// # Ok::<_, Box<dyn std::error::Error>>(())
4106    /// ```
4107    pub fn truncate(&mut self, limit: usize) {
4108        match self {
4109            PrimitiveValue::Empty | PrimitiveValue::Str(_) => { /* no-op */ }
4110            PrimitiveValue::Strs(l) => l.truncate(limit),
4111            PrimitiveValue::Tags(l) => l.truncate(limit),
4112            PrimitiveValue::U8(l) => l.truncate(limit),
4113            PrimitiveValue::I16(l) => l.truncate(limit),
4114            PrimitiveValue::U16(l) => l.truncate(limit),
4115            PrimitiveValue::I32(l) => l.truncate(limit),
4116            PrimitiveValue::U32(l) => l.truncate(limit),
4117            PrimitiveValue::I64(l) => l.truncate(limit),
4118            PrimitiveValue::U64(l) => l.truncate(limit),
4119            PrimitiveValue::F32(l) => l.truncate(limit),
4120            PrimitiveValue::F64(l) => l.truncate(limit),
4121            PrimitiveValue::Date(l) => l.truncate(limit),
4122            PrimitiveValue::DateTime(l) => l.truncate(limit),
4123            PrimitiveValue::Time(l) => l.truncate(limit),
4124        }
4125    }
4126}
4127
4128/// The output of this method is equivalent to calling the method `to_str`
4129impl Display for PrimitiveValue {
4130    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4131        /// Auxiliary function for turning a sequence of values
4132        /// into a backslash-delimited string.
4133        fn seq_to_str<I>(iter: I) -> String
4134        where
4135            I: IntoIterator,
4136            I::Item: Display,
4137        {
4138            iter.into_iter().map(|x| x.to_string()).join("\\")
4139        }
4140
4141        match self {
4142            PrimitiveValue::Empty => Ok(()),
4143            PrimitiveValue::Str(_) => f.write_str(&self.to_str()),
4144            PrimitiveValue::Strs(_) => f.write_str(&self.to_str()),
4145            PrimitiveValue::Date(values) => {
4146                f.write_str(&values.into_iter().map(|date| date.to_string()).join("\\"))
4147            }
4148            PrimitiveValue::Time(values) => {
4149                f.write_str(&values.into_iter().map(|time| time.to_string()).join("\\"))
4150            }
4151            PrimitiveValue::DateTime(values) => f.write_str(
4152                &values
4153                    .into_iter()
4154                    .map(|datetime| datetime.to_string())
4155                    .join("\\"),
4156            ),
4157            PrimitiveValue::U8(values) => f.write_str(&seq_to_str(values)),
4158            PrimitiveValue::U16(values) => f.write_str(&seq_to_str(values)),
4159            PrimitiveValue::U32(values) => f.write_str(&seq_to_str(values)),
4160            PrimitiveValue::I16(values) => f.write_str(&seq_to_str(values)),
4161            PrimitiveValue::I32(values) => f.write_str(&seq_to_str(values)),
4162            PrimitiveValue::U64(values) => f.write_str(&seq_to_str(values)),
4163            PrimitiveValue::I64(values) => f.write_str(&seq_to_str(values)),
4164            PrimitiveValue::F32(values) => f.write_str(&seq_to_str(values)),
4165            PrimitiveValue::F64(values) => f.write_str(&seq_to_str(values)),
4166            PrimitiveValue::Tags(values) => f.write_str(&seq_to_str(values)),
4167        }
4168    }
4169}
4170
4171impl HasLength for PrimitiveValue {
4172    fn length(&self) -> Length {
4173        Length::defined(self.calculate_byte_len() as u32)
4174    }
4175}
4176
4177impl PartialEq for PrimitiveValue {
4178    fn eq(&self, other: &Self) -> bool {
4179        match (self, other) {
4180            (PrimitiveValue::Empty, PrimitiveValue::Empty) => true,
4181            (PrimitiveValue::Strs(v1), PrimitiveValue::Str(_)) => {
4182                v1.len() == 1 && self.to_str() == other.to_str()
4183            }
4184            (PrimitiveValue::Str(_), PrimitiveValue::Strs(v2)) => {
4185                v2.len() == 1 && self.to_str() == other.to_str()
4186            }
4187            (PrimitiveValue::Strs(_), PrimitiveValue::Strs(_)) => self.to_str() == other.to_str(),
4188            (PrimitiveValue::Str(_), PrimitiveValue::Str(_)) => self.to_str() == other.to_str(),
4189            (PrimitiveValue::Tags(v1), PrimitiveValue::Tags(v2)) => v1 == v2,
4190            (PrimitiveValue::U8(v1), PrimitiveValue::U8(v2)) => v1 == v2,
4191            (PrimitiveValue::I16(v1), PrimitiveValue::I16(v2)) => v1 == v2,
4192            (PrimitiveValue::U16(v1), PrimitiveValue::U16(v2)) => v1 == v2,
4193            (PrimitiveValue::I32(v1), PrimitiveValue::I32(v2)) => v1 == v2,
4194            (PrimitiveValue::U32(v1), PrimitiveValue::U32(v2)) => v1 == v2,
4195            (PrimitiveValue::I64(v1), PrimitiveValue::I64(v2)) => v1 == v2,
4196            (PrimitiveValue::U64(v1), PrimitiveValue::U64(v2)) => v1 == v2,
4197            (PrimitiveValue::F32(v1), PrimitiveValue::F32(v2)) => v1 == v2,
4198            (PrimitiveValue::F64(v1), PrimitiveValue::F64(v2)) => v1 == v2,
4199            (PrimitiveValue::Date(v1), PrimitiveValue::Date(v2)) => v1 == v2,
4200            (PrimitiveValue::DateTime(v1), PrimitiveValue::DateTime(v2)) => v1 == v2,
4201            (PrimitiveValue::Time(v1), PrimitiveValue::Time(v2)) => v1 == v2,
4202            _ => false,
4203        }
4204    }
4205}
4206
4207impl PartialEq<str> for PrimitiveValue {
4208    fn eq(&self, other: &str) -> bool {
4209        match self {
4210            PrimitiveValue::Strs(v) => v.len() == 1 && v[0] == other,
4211            PrimitiveValue::Str(v) => v == other,
4212            _ => false,
4213        }
4214    }
4215}
4216
4217impl PartialEq<&str> for PrimitiveValue {
4218    fn eq(&self, other: &&str) -> bool {
4219        self.eq(*other)
4220    }
4221}
4222
4223/// An enum representing an abstraction of a DICOM element's data value type.
4224/// This should be the equivalent of `PrimitiveValue` without the content,
4225/// plus the `DataSetSequence` and `PixelSequence` entries.
4226#[derive(Debug, PartialEq, Eq, Clone, Copy)]
4227pub enum ValueType {
4228    /// No data. Used for any value of length 0.
4229    Empty,
4230
4231    /// A data set sequence.
4232    /// Used for values with the SQ representation when not empty.
4233    DataSetSequence,
4234
4235    /// An item. Used for the values of encapsulated pixel data.
4236    PixelSequence,
4237
4238    /// A sequence of strings.
4239    /// Used for AE, AS, PN, SH, CS, LO, UI and UC.
4240    /// Can also be used for IS, SS, DS, DA, DT and TM when decoding
4241    /// with format preservation.
4242    Strs,
4243
4244    /// A single string.
4245    /// Used for ST, LT, UT and UR, which are never multi-valued.
4246    Str,
4247
4248    /// A sequence of attribute tags.
4249    /// Used specifically for AT.
4250    Tags,
4251
4252    /// The value is a sequence of unsigned 8-bit integers.
4253    /// Used for OB and UN.
4254    U8,
4255
4256    /// The value is a sequence of signed 16-bit integers.
4257    /// Used for SS.
4258    I16,
4259
4260    /// A sequence of unsigned 16-bit integers.
4261    /// Used for US and OW.
4262    U16,
4263
4264    /// A sequence of signed 32-bit integers.
4265    /// Used for SL and IS.
4266    I32,
4267
4268    /// A sequence of unsigned 32-bit integers.
4269    /// Used for UL and OL.
4270    U32,
4271
4272    /// A sequence of signed 64-bit integers.
4273    /// Used for SV.
4274    I64,
4275
4276    /// A sequence of unsigned 64-bit integers.
4277    /// Used for UV and OV.
4278    U64,
4279
4280    /// The value is a sequence of 32-bit floating point numbers.
4281    /// Used for OF and FL.
4282    F32,
4283
4284    /// The value is a sequence of 64-bit floating point numbers.
4285    /// Used for OD, FD and DS.
4286    F64,
4287
4288    /// A sequence of dates.
4289    /// Used for the DA representation.
4290    Date,
4291
4292    /// A sequence of date-time values.
4293    /// Used for the DT representation.
4294    DateTime,
4295
4296    /// A sequence of time values.
4297    /// Used for the TM representation.
4298    Time,
4299}
4300
4301impl DicomValueType for PrimitiveValue {
4302    fn value_type(&self) -> ValueType {
4303        match *self {
4304            PrimitiveValue::Empty => ValueType::Empty,
4305            PrimitiveValue::Date(_) => ValueType::Date,
4306            PrimitiveValue::DateTime(_) => ValueType::DateTime,
4307            PrimitiveValue::F32(_) => ValueType::F32,
4308            PrimitiveValue::F64(_) => ValueType::F64,
4309            PrimitiveValue::I16(_) => ValueType::I16,
4310            PrimitiveValue::I32(_) => ValueType::I32,
4311            PrimitiveValue::I64(_) => ValueType::I64,
4312            PrimitiveValue::Str(_) => ValueType::Str,
4313            PrimitiveValue::Strs(_) => ValueType::Strs,
4314            PrimitiveValue::Tags(_) => ValueType::Tags,
4315            PrimitiveValue::Time(_) => ValueType::Time,
4316            PrimitiveValue::U16(_) => ValueType::U16,
4317            PrimitiveValue::U32(_) => ValueType::U32,
4318            PrimitiveValue::U64(_) => ValueType::U64,
4319            PrimitiveValue::U8(_) => ValueType::U8,
4320        }
4321    }
4322
4323    fn cardinality(&self) -> usize {
4324        match self {
4325            PrimitiveValue::Empty => 0,
4326            PrimitiveValue::Str(_) => 1,
4327            PrimitiveValue::Date(b) => b.len(),
4328            PrimitiveValue::DateTime(b) => b.len(),
4329            PrimitiveValue::F32(b) => b.len(),
4330            PrimitiveValue::F64(b) => b.len(),
4331            PrimitiveValue::I16(b) => b.len(),
4332            PrimitiveValue::I32(b) => b.len(),
4333            PrimitiveValue::I64(b) => b.len(),
4334            PrimitiveValue::Strs(b) => b.len(),
4335            PrimitiveValue::Tags(b) => b.len(),
4336            PrimitiveValue::Time(b) => b.len(),
4337            PrimitiveValue::U16(b) => b.len(),
4338            PrimitiveValue::U32(b) => b.len(),
4339            PrimitiveValue::U64(b) => b.len(),
4340            PrimitiveValue::U8(b) => b.len(),
4341        }
4342    }
4343}
4344
4345fn trim_last_whitespace(x: &[u8]) -> &[u8] {
4346    match x.last() {
4347        Some(b' ') | Some(b'\0') => &x[..x.len() - 1],
4348        _ => x,
4349    }
4350}
4351
4352#[inline]
4353fn whitespace_or_null(c: char) -> bool {
4354    c.is_whitespace() || c == '\0'
4355}
4356
4357#[cfg(test)]
4358mod tests {
4359    use super::{CastValueError, ConvertValueError, InvalidValueReadError};
4360    use crate::dicom_value;
4361    use crate::value::partial::{DicomDate, DicomDateTime, DicomTime};
4362    use crate::value::range::{DateRange, DateTimeRange, TimeRange};
4363    use crate::value::{PrimitiveValue, ValueType};
4364    use chrono::{FixedOffset, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone};
4365    use smallvec::smallvec;
4366
4367    #[test]
4368    fn primitive_value_to_str() {
4369        assert_eq!(PrimitiveValue::Empty.to_str(), "");
4370
4371        // does not copy on a single string
4372        let value = PrimitiveValue::Str("Smith^John".to_string());
4373        let string = value.to_str();
4374        assert_eq!(string, "Smith^John",);
4375        match string {
4376            std::borrow::Cow::Borrowed(_) => {} // good
4377            _ => panic!("expected string to be borrowed, but was owned"),
4378        }
4379
4380        assert_eq!(
4381            PrimitiveValue::Date(smallvec![DicomDate::from_ymd(2014, 10, 12).unwrap()]).to_str(),
4382            "2014-10-12",
4383        );
4384        assert_eq!(
4385            dicom_value!(Strs, ["DERIVED", "PRIMARY", "WHOLE BODY", "EMISSION"]).to_str(),
4386            "DERIVED\\PRIMARY\\WHOLE BODY\\EMISSION",
4387        );
4388
4389        // sequence of numbers
4390        let value = PrimitiveValue::from(vec![10, 11, 12]);
4391        assert_eq!(value.to_str(), "10\\11\\12",);
4392
4393        // now test that trailing whitespace is trimmed
4394        // removes whitespace at the end of a string
4395        let value = PrimitiveValue::from("1.2.345\0".to_string());
4396        assert_eq!(&value.to_str(), "1.2.345");
4397        let value = PrimitiveValue::from("1.2.345 ".to_string());
4398        assert_eq!(&value.to_str(), "1.2.345");
4399
4400        // removes whitespace at the end on multiple strings
4401        let value = dicom_value!(Strs, ["ONE ", "TWO", "THREE", "SIX "]);
4402        assert_eq!(&value.to_str(), "ONE\\TWO\\THREE\\SIX");
4403
4404        // maintains the leading whitespace on a string and removes at the end
4405        let value = PrimitiveValue::from("\01.2.345\0".to_string());
4406        assert_eq!(&value.to_str(), "\01.2.345");
4407
4408        // maintains the leading whitespace on multiple strings and removes at the end
4409        let value = dicom_value!(Strs, [" ONE", "TWO", "THREE", " SIX "]);
4410        assert_eq!(&value.to_str(), " ONE\\TWO\\THREE\\ SIX");
4411    }
4412
4413    #[test]
4414    fn primitive_value_to_raw_str() {
4415        // maintains whitespace at the end of a string
4416        let value = PrimitiveValue::from("1.2.345\0".to_string());
4417        assert_eq!(&value.to_raw_str(), "1.2.345\0");
4418
4419        // maintains whitespace at the end on multiple strings
4420        let value = dicom_value!(Strs, ["ONE", "TWO", "THREE", "SIX "]);
4421        assert_eq!(&value.to_raw_str(), "ONE\\TWO\\THREE\\SIX ");
4422
4423        // maintains the leading whitespace on a string and maintains at the end
4424        let value = PrimitiveValue::from("\01.2.345\0".to_string());
4425        assert_eq!(&value.to_raw_str(), "\01.2.345\0");
4426
4427        // maintains the leading whitespace on multiple strings and maintains at the end
4428        let value = dicom_value!(Strs, [" ONE", "TWO", "THREE", " SIX "]);
4429        assert_eq!(&value.to_raw_str(), " ONE\\TWO\\THREE\\ SIX ");
4430    }
4431
4432    #[test]
4433    fn primitive_value_to_bytes() {
4434        assert_eq!(PrimitiveValue::Empty.to_bytes(), &[][..]);
4435
4436        if cfg!(target_endian = "little") {
4437            assert_eq!(
4438                PrimitiveValue::U16(smallvec![1, 2, 0x0601,]).to_bytes(),
4439                &[0x01, 0x00, 0x02, 0x00, 0x01, 0x06][..],
4440            );
4441        } else {
4442            assert_eq!(
4443                PrimitiveValue::U16(smallvec![0x0001, 0x0002, 0x0601,]).to_bytes(),
4444                &[0x00, 0x01, 0x00, 0x02, 0x06, 0x01][..],
4445            );
4446        }
4447
4448        // does not copy on a single string
4449        let value = PrimitiveValue::from("Smith^John");
4450        let bytes = value.to_bytes();
4451        assert_eq!(bytes, &b"Smith^John"[..],);
4452        match bytes {
4453            std::borrow::Cow::Borrowed(_) => {} // good
4454            _ => panic!("expected bytes to be borrowed, but are owned"),
4455        }
4456
4457        assert_eq!(
4458            PrimitiveValue::Date(smallvec![DicomDate::from_ym(2014, 10).unwrap()]).to_bytes(),
4459            &b"2014-10"[..],
4460        );
4461        assert_eq!(
4462            dicom_value!(Strs, ["DERIVED", "PRIMARY", "WHOLE BODY", "EMISSION",]).to_bytes(),
4463            &b"DERIVED\\PRIMARY\\WHOLE BODY\\EMISSION"[..],
4464        );
4465
4466        // does not copy on bytes
4467        let value = PrimitiveValue::from(vec![0x99; 16]);
4468        let bytes = value.to_bytes();
4469        assert_eq!(bytes, &[0x99; 16][..],);
4470        match bytes {
4471            std::borrow::Cow::Borrowed(_) => {} // good
4472            _ => panic!("expected bytes to be borrowed, but are owned"),
4473        }
4474    }
4475
4476    #[test]
4477    fn primitive_value_to_float() {
4478        // DS conversion to f32
4479        assert_eq!(dicom_value!(Str, "-73.4 ").to_float32().ok(), Some(-73.4));
4480
4481        // DS conversion with leading whitespaces
4482        assert_eq!(dicom_value!(Str, " -73.4 ").to_float32().ok(), Some(-73.4));
4483
4484        // DS conversion with leading whitespaces
4485        assert_eq!(dicom_value!(Str, " -73.4 ").to_float64().ok(), Some(-73.4));
4486
4487        // DS conversion with exponential
4488        assert_eq!(dicom_value!(Str, "1e1").to_float32().ok(), Some(10.0));
4489    }
4490
4491    #[test]
4492    fn primitive_value_to_int() {
4493        assert!(PrimitiveValue::Empty.to_int::<i32>().is_err());
4494
4495        // exact match
4496        assert_eq!(
4497            PrimitiveValue::from(0x0601_u16).to_int().ok(),
4498            Some(0x0601_u16),
4499        );
4500        // conversions are automatically applied
4501        assert_eq!(
4502            PrimitiveValue::from(0x0601_u16).to_int().ok(),
4503            Some(0x0601_u32),
4504        );
4505        assert_eq!(
4506            PrimitiveValue::from(0x0601_u16).to_int().ok(),
4507            Some(0x0601_i64),
4508        );
4509        assert_eq!(
4510            PrimitiveValue::from(0x0601_u16).to_int().ok(),
4511            Some(0x0601_u64),
4512        );
4513
4514        // takes the first number
4515        assert_eq!(dicom_value!(I32, [1, 2, 5]).to_int().ok(), Some(1),);
4516
4517        // admits an integer as text
4518        assert_eq!(dicom_value!(Strs, ["-73", "2"]).to_int().ok(), Some(-73),);
4519
4520        // admits an integer as text with leading spaces
4521        assert_eq!(dicom_value!(Strs, [" -73", " 2"]).to_int().ok(), Some(-73),);
4522
4523        // does not admit destructive conversions
4524        assert!(PrimitiveValue::from(-1).to_int::<u32>().is_err());
4525
4526        // does not admit strings which are not numbers
4527        assert!(matches!(
4528            dicom_value!(Strs, ["Smith^John"]).to_int::<u8>(),
4529            Err(ConvertValueError {
4530                requested: _,
4531                original: ValueType::Strs,
4532                // would try to parse as an integer and fail
4533                cause: Some(cause),
4534            }) if matches!(&*cause, InvalidValueReadError::ParseInteger { .. })
4535        ));
4536    }
4537
4538    #[test]
4539    fn primitive_value_to_multi_int() {
4540        assert_eq!(PrimitiveValue::Empty.to_multi_int::<i32>().unwrap(), vec![]);
4541
4542        let test_value = dicom_value!(U16, [0x0601, 0x5353, 3, 4]);
4543        // exact match
4544        let numbers = test_value.to_multi_int::<u16>().unwrap();
4545        assert_eq!(numbers, vec![0x0601, 0x5353, 3, 4],);
4546        // type is inferred on context
4547        let numbers: Vec<u32> = test_value.to_multi_int().unwrap();
4548        assert_eq!(numbers, vec![0x0601_u32, 0x5353, 3, 4],);
4549        let numbers: Vec<i64> = test_value.to_multi_int().unwrap();
4550        assert_eq!(numbers, vec![0x0601_i64, 0x5353, 3, 4],);
4551        assert_eq!(
4552            test_value.to_multi_int::<u64>().unwrap(),
4553            vec![0x0601_u64, 0x5353, 3, 4],
4554        );
4555
4556        // takes all numbers
4557        assert_eq!(
4558            dicom_value!(I32, [1, 2, 5]).to_multi_int().ok(),
4559            Some(vec![1, 2, 5]),
4560        );
4561
4562        // admits a integer as text, trailing space too
4563        assert_eq!(
4564            dicom_value!(Strs, ["-73", "2 "]).to_multi_int().ok(),
4565            Some(vec![-73, 2]),
4566        );
4567
4568        // does not admit destructive conversions
4569        assert!(matches!(
4570            dicom_value!(I32, [0, 1, -1]).to_multi_int::<u64>(),
4571            Err(ConvertValueError {
4572                original: ValueType::I32,
4573                // the cast from -1_i32 to u32 would fail
4574                cause: Some(cause),
4575                ..
4576            }) if matches!(&*cause,
4577                InvalidValueReadError::NarrowConvert {
4578                value: x,
4579               ..
4580            } if x == "-1")
4581        ));
4582
4583        // not even from strings
4584        assert!(matches!(
4585            dicom_value!(Strs, ["0", "1", "-1"]).to_multi_int::<u16>(),
4586            Err(ConvertValueError {
4587                original: ValueType::Strs,
4588                // the conversion from "-1" to u32 would fail
4589                cause: Some(cause),
4590                ..
4591            }) if matches!(&*cause, InvalidValueReadError::ParseInteger { .. })
4592        ));
4593
4594        // does not admit strings which are not numbers
4595        assert!(matches!(
4596            dicom_value!(Strs, ["Smith^John"]).to_int::<u8>(),
4597            Err(ConvertValueError {
4598                requested: _,
4599                original: ValueType::Strs,
4600                // would try to parse as an integer and fail
4601                cause: Some(cause),
4602            }) if matches!(&*cause, InvalidValueReadError::ParseInteger { .. })
4603        ));
4604    }
4605
4606    #[test]
4607    fn primitive_value_to_multi_floats() {
4608        assert_eq!(PrimitiveValue::Empty.to_multi_float32().ok(), Some(vec![]));
4609
4610        let test_value = dicom_value!(U16, [1, 2, 3, 4]);
4611
4612        assert_eq!(
4613            test_value.to_multi_float32().ok(),
4614            Some(vec![1., 2., 3., 4.]),
4615        );
4616        assert_eq!(
4617            test_value.to_multi_float64().ok(),
4618            Some(vec![1., 2., 3., 4.]),
4619        );
4620
4621        // admits a number as text, trailing space too
4622        assert_eq!(
4623            dicom_value!(Strs, ["7.25", "-12.5 "])
4624                .to_multi_float64()
4625                .ok(),
4626            Some(vec![7.25, -12.5]),
4627        );
4628
4629        // does not admit strings which are not numbers
4630        assert!(matches!(
4631            dicom_value!(Strs, ["Smith^John"]).to_multi_float64(),
4632            Err(ConvertValueError {
4633                requested: _,
4634                original: ValueType::Strs,
4635                // would try to parse as a float and fail
4636                cause: Some(cause),
4637            }) if matches!(&*cause, InvalidValueReadError::ParseFloat { .. })
4638        ));
4639    }
4640
4641    #[test]
4642    fn primitive_value_to_naive_date() {
4643        // to NaiveDate
4644        assert_eq!(
4645            PrimitiveValue::Date(smallvec![DicomDate::from_ymd(2014, 10, 12).unwrap()])
4646                .to_naive_date()
4647                .unwrap(),
4648            NaiveDate::from_ymd_opt(2014, 10, 12).unwrap(),
4649        );
4650        // from text (Str)
4651        assert_eq!(
4652            dicom_value!(Str, "20141012").to_naive_date().unwrap(),
4653            NaiveDate::from_ymd_opt(2014, 10, 12).unwrap(),
4654        );
4655        // from text (Strs)
4656        assert_eq!(
4657            dicom_value!(Strs, ["20141012"]).to_naive_date().unwrap(),
4658            NaiveDate::from_ymd_opt(2014, 10, 12).unwrap(),
4659        );
4660        // from bytes
4661        assert_eq!(
4662            PrimitiveValue::from(b"20200229").to_naive_date().unwrap(),
4663            NaiveDate::from_ymd_opt(2020, 2, 29).unwrap(),
4664        );
4665        // not a date
4666        assert!(matches!(
4667            PrimitiveValue::Str("Smith^John".to_string()).to_naive_date(),
4668            Err(ConvertValueError {
4669                requested: "NaiveDate",
4670                original: ValueType::Str,
4671                // would try to parse as a date and fail
4672                cause: Some(_),
4673            })
4674        ));
4675    }
4676
4677    #[test]
4678    fn primitive_value_to_dicom_date() {
4679        // primitive conversion
4680        assert_eq!(
4681            PrimitiveValue::Date(smallvec![DicomDate::from_ymd(2014, 10, 12).unwrap()])
4682                .to_date()
4683                .ok(),
4684            Some(DicomDate::from_ymd(2014, 10, 12).unwrap()),
4685        );
4686
4687        // from Strs
4688        assert_eq!(
4689            dicom_value!(Strs, ["201410", "2020", "20200101"])
4690                .to_date()
4691                .unwrap(),
4692            DicomDate::from_ym(2014, 10).unwrap()
4693        );
4694
4695        // from bytes
4696        assert_eq!(
4697            PrimitiveValue::from(b"202002").to_date().ok(),
4698            Some(DicomDate::from_ym(2020, 2).unwrap())
4699        );
4700    }
4701
4702    #[test]
4703    fn primitive_value_to_multi_dicom_date() {
4704        assert_eq!(
4705            dicom_value!(Strs, ["201410", "2020", "20200101"])
4706                .to_multi_date()
4707                .unwrap(),
4708            vec![
4709                DicomDate::from_ym(2014, 10).unwrap(),
4710                DicomDate::from_y(2020).unwrap(),
4711                DicomDate::from_ymd(2020, 1, 1).unwrap()
4712            ]
4713        );
4714
4715        assert!(dicom_value!(Strs, ["-44"]).to_multi_date().is_err());
4716    }
4717
4718    #[test]
4719    fn primitive_value_to_naive_time() {
4720        // trivial conversion
4721        assert_eq!(
4722            PrimitiveValue::from(DicomTime::from_hms(11, 9, 26).unwrap())
4723                .to_naive_time()
4724                .unwrap(),
4725            NaiveTime::from_hms_opt(11, 9, 26).unwrap(),
4726        );
4727        // from text (Str)
4728        assert_eq!(
4729            dicom_value!(Str, "110926.3").to_naive_time().unwrap(),
4730            NaiveTime::from_hms_milli_opt(11, 9, 26, 300).unwrap(),
4731        );
4732        // from text with fraction of a second + padding
4733        assert_eq!(
4734            PrimitiveValue::from(&"110926.38 "[..])
4735                .to_naive_time()
4736                .unwrap(),
4737            NaiveTime::from_hms_milli_opt(11, 9, 26, 380).unwrap(),
4738        );
4739        // from text (Strs)
4740        assert_eq!(
4741            dicom_value!(Strs, ["110926.38"]).to_naive_time().unwrap(),
4742            NaiveTime::from_hms_milli_opt(11, 9, 26, 380).unwrap(),
4743        );
4744
4745        // from text without fraction of a second (assumes 0 ms in fraction)
4746        assert_eq!(
4747            dicom_value!(Str, "110926").to_naive_time().unwrap(),
4748            NaiveTime::from_hms_opt(11, 9, 26).unwrap(),
4749        );
4750
4751        // absence of seconds is considered to be an incomplete value
4752        assert!(PrimitiveValue::from(&"1109"[..]).to_naive_time().is_err(),);
4753        assert!(dicom_value!(Strs, ["1109"]).to_naive_time().is_err());
4754        assert!(dicom_value!(Strs, ["11"]).to_naive_time().is_err());
4755
4756        // not a time
4757        assert!(matches!(
4758            PrimitiveValue::Str("Smith^John".to_string()).to_naive_time(),
4759            Err(ConvertValueError {
4760                requested: "NaiveTime",
4761                original: ValueType::Str,
4762                ..
4763            })
4764        ));
4765    }
4766
4767    #[test]
4768    fn primitive_value_to_dicom_time() {
4769        // from NaiveTime - results in exact DicomTime with default fraction
4770        assert_eq!(
4771            PrimitiveValue::from(DicomTime::from_hms_micro(11, 9, 26, 0).unwrap())
4772                .to_time()
4773                .unwrap(),
4774            DicomTime::from_hms_micro(11, 9, 26, 0).unwrap(),
4775        );
4776        // from NaiveTime with milli precision
4777        assert_eq!(
4778            PrimitiveValue::from(DicomTime::from_hms_milli(11, 9, 26, 123).unwrap())
4779                .to_time()
4780                .unwrap(),
4781            DicomTime::from_hms_milli(11, 9, 26, 123).unwrap(),
4782        );
4783        // from NaiveTime with micro precision
4784        assert_eq!(
4785            PrimitiveValue::from(DicomTime::from_hms_micro(11, 9, 26, 123).unwrap())
4786                .to_time()
4787                .unwrap(),
4788            DicomTime::from_hms_micro(11, 9, 26, 123).unwrap(),
4789        );
4790        // from text (Str)
4791        assert_eq!(
4792            dicom_value!(Str, "110926").to_time().unwrap(),
4793            DicomTime::from_hms(11, 9, 26).unwrap(),
4794        );
4795        // from text with fraction of a second + padding
4796        assert_eq!(
4797            PrimitiveValue::from(&"110926.38 "[..]).to_time().unwrap(),
4798            DicomTime::from_hmsf(11, 9, 26, 38, 2).unwrap(),
4799        );
4800        // from text (Strs)
4801        assert_eq!(
4802            dicom_value!(Strs, ["110926"]).to_time().unwrap(),
4803            DicomTime::from_hms(11, 9, 26).unwrap(),
4804        );
4805        // from text (Strs) with fraction of a second
4806        assert_eq!(
4807            dicom_value!(Strs, ["110926.123456"]).to_time().unwrap(),
4808            DicomTime::from_hms_micro(11, 9, 26, 123_456).unwrap(),
4809        );
4810        // from bytes with fraction of a second
4811        assert_eq!(
4812            PrimitiveValue::from(&b"110926.987"[..]).to_time().unwrap(),
4813            DicomTime::from_hms_milli(11, 9, 26, 987).unwrap(),
4814        );
4815        // from bytes with fraction of a second + padding
4816        assert_eq!(
4817            PrimitiveValue::from(&b"110926.38 "[..]).to_time().unwrap(),
4818            DicomTime::from_hmsf(11, 9, 26, 38, 2).unwrap(),
4819        );
4820        // not a time
4821        assert!(matches!(
4822            PrimitiveValue::Str("Smith^John".to_string()).to_time(),
4823            Err(ConvertValueError {
4824                requested: "DicomTime",
4825                original: ValueType::Str,
4826                ..
4827            })
4828        ));
4829    }
4830
4831    #[test]
4832    fn primitive_value_to_dicom_datetime() {
4833        let offset = FixedOffset::east_opt(1).unwrap();
4834
4835        // try from chrono::DateTime<FixedOffset>
4836        assert_eq!(
4837            PrimitiveValue::from(
4838                DicomDateTime::from_date_and_time_with_time_zone(
4839                    DicomDate::from_ymd(2012, 12, 21).unwrap(),
4840                    DicomTime::from_hms_micro(11, 9, 26, 000123).unwrap(),
4841                    offset
4842                )
4843                .unwrap()
4844            )
4845            .to_datetime()
4846            .unwrap(),
4847            DicomDateTime::from_date_and_time_with_time_zone(
4848                DicomDate::from_ymd(2012, 12, 21).unwrap(),
4849                DicomTime::from_hms_micro(11, 9, 26, 000123).unwrap(),
4850                offset
4851            )
4852            .unwrap()
4853        );
4854        // try from chrono::NaiveDateTime
4855        assert_eq!(
4856            PrimitiveValue::from(
4857                DicomDateTime::from_date_and_time(
4858                    DicomDate::from_ymd(2012, 12, 21).unwrap(),
4859                    DicomTime::from_hms_micro(11, 9, 26, 000123).unwrap()
4860                )
4861                .unwrap()
4862            )
4863            .to_datetime()
4864            .unwrap(),
4865            DicomDateTime::from_date_and_time(
4866                DicomDate::from_ymd(2012, 12, 21).unwrap(),
4867                DicomTime::from_hms_micro(11, 9, 26, 000123).unwrap()
4868            )
4869            .unwrap()
4870        );
4871        // from text (Str) - minimum allowed is a YYYY
4872        assert_eq!(
4873            dicom_value!(Str, "2012").to_datetime().unwrap(),
4874            DicomDateTime::from_date(DicomDate::from_y(2012).unwrap())
4875        );
4876        // from text with fraction of a second + padding
4877        assert_eq!(
4878            PrimitiveValue::from("20121221110926.38 ")
4879                .to_datetime()
4880                .unwrap(),
4881            DicomDateTime::from_date_and_time(
4882                DicomDate::from_ymd(2012, 12, 21).unwrap(),
4883                DicomTime::from_hmsf(11, 9, 26, 38, 2).unwrap()
4884            )
4885            .unwrap()
4886        );
4887        // from text (Strs) with fraction of a second + padding
4888        assert_eq!(
4889            dicom_value!(Strs, ["20121221110926.38 "])
4890                .to_datetime()
4891                .unwrap(),
4892            DicomDateTime::from_date_and_time(
4893                DicomDate::from_ymd(2012, 12, 21).unwrap(),
4894                DicomTime::from_hmsf(11, 9, 26, 38, 2).unwrap()
4895            )
4896            .unwrap()
4897        );
4898        // not a dicom_datetime
4899        assert!(matches!(
4900            PrimitiveValue::from("Smith^John").to_datetime(),
4901            Err(ConvertValueError {
4902                requested: "DicomDateTime",
4903                original: ValueType::Str,
4904                ..
4905            })
4906        ));
4907    }
4908
4909    #[test]
4910    fn primitive_value_to_multi_dicom_datetime() {
4911        // from text (Strs)
4912        assert_eq!(
4913            dicom_value!(
4914                Strs,
4915                ["20121221110926.38 ", "1992", "19901010-0500", "1990+0501"]
4916            )
4917            .to_multi_datetime()
4918            .unwrap(),
4919            vec!(
4920                DicomDateTime::from_date_and_time(
4921                    DicomDate::from_ymd(2012, 12, 21).unwrap(),
4922                    DicomTime::from_hmsf(11, 9, 26, 38, 2).unwrap()
4923                )
4924                .unwrap(),
4925                DicomDateTime::from_date(DicomDate::from_y(1992).unwrap()),
4926                DicomDateTime::from_date_with_time_zone(
4927                    DicomDate::from_ymd(1990, 10, 10).unwrap(),
4928                    FixedOffset::west_opt(5 * 3600).unwrap()
4929                ),
4930                DicomDateTime::from_date_with_time_zone(
4931                    DicomDate::from_y(1990).unwrap(),
4932                    FixedOffset::east_opt(5 * 3600 + 60).unwrap()
4933                )
4934            )
4935        );
4936    }
4937
4938    #[test]
4939    fn primitive_value_to_date_range() {
4940        // converts first value of sequence
4941        assert_eq!(
4942            dicom_value!(Strs, ["20121221-", "1992-", "1990-1992", "1990+0501"])
4943                .to_date_range()
4944                .unwrap(),
4945            DateRange::from_start(NaiveDate::from_ymd_opt(2012, 12, 21).unwrap())
4946        );
4947    }
4948
4949    #[test]
4950    fn primitive_value_to_time_range() {
4951        assert_eq!(
4952            dicom_value!(Str, "-153012.123").to_time_range().unwrap(),
4953            TimeRange::from_end(NaiveTime::from_hms_micro_opt(15, 30, 12, 123_999).unwrap())
4954        );
4955        assert_eq!(
4956            PrimitiveValue::from(&b"1015-"[..]).to_time_range().unwrap(),
4957            TimeRange::from_start(NaiveTime::from_hms_opt(10, 15, 0).unwrap())
4958        );
4959    }
4960
4961    #[test]
4962    fn primitive_value_to_datetime_range() {
4963        assert_eq!(
4964            dicom_value!(Str, "202002-20210228153012.123")
4965                .to_datetime_range()
4966                .unwrap(),
4967            DateTimeRange::from_start_to_end(
4968                NaiveDateTime::new(
4969                    NaiveDate::from_ymd_opt(2020, 2, 1).unwrap(),
4970                    NaiveTime::from_hms_opt(0, 0, 0).unwrap()
4971                ),
4972                NaiveDateTime::new(
4973                    NaiveDate::from_ymd_opt(2021, 2, 28).unwrap(),
4974                    NaiveTime::from_hms_micro_opt(15, 30, 12, 123_999).unwrap()
4975                )
4976            )
4977            .unwrap()
4978        );
4979        // East UTC offset gets parsed and the missing lower bound time-zone
4980        // will be the local clock time-zone offset
4981        assert_eq!(
4982            PrimitiveValue::from(&b"2020-2030+0800"[..])
4983                .to_datetime_range()
4984                .unwrap(),
4985            DateTimeRange::TimeZone {
4986                start: Some(
4987                    Local::now()
4988                        .offset()
4989                        .from_local_datetime(&NaiveDateTime::new(
4990                            NaiveDate::from_ymd_opt(2020, 1, 1).unwrap(),
4991                            NaiveTime::from_hms_opt(0, 0, 0).unwrap()
4992                        ))
4993                        .unwrap()
4994                ),
4995                end: Some(
4996                    FixedOffset::east_opt(8 * 3600)
4997                        .unwrap()
4998                        .from_local_datetime(&NaiveDateTime::new(
4999                            NaiveDate::from_ymd_opt(2030, 12, 31).unwrap(),
5000                            NaiveTime::from_hms_micro_opt(23, 59, 59, 999_999).unwrap()
5001                        ))
5002                        .unwrap()
5003                )
5004            }
5005        );
5006    }
5007
5008    #[test]
5009    fn calculate_byte_len() {
5010        // single even string
5011        // b"ABCD"
5012        let val = dicom_value!("ABCD");
5013        assert_eq!(val.calculate_byte_len(), 4);
5014
5015        // multi string, no padding
5016        // b"ABCD\\EFG"
5017        let val = dicom_value!(Strs, ["ABCD", "EFG"]);
5018        assert_eq!(val.calculate_byte_len(), 8);
5019
5020        // multi string with padding
5021        // b"ABCD\\EFGH "
5022        let val = dicom_value!(Strs, ["ABCD", "EFGH"]);
5023        assert_eq!(val.calculate_byte_len(), 10);
5024
5025        // multi date, no padding
5026        // b"20141012\\202009\\20180101"
5027        let val = dicom_value!(
5028            Date,
5029            [
5030                DicomDate::from_ymd(2014, 10, 12).unwrap(),
5031                DicomDate::from_ym(2020, 9).unwrap(),
5032                DicomDate::from_ymd(2018, 1, 1).unwrap()
5033            ]
5034        );
5035        assert_eq!(val.calculate_byte_len(), 24);
5036
5037        // multi date with padding
5038        // b"20141012\\2020 "
5039        let val = dicom_value!(
5040            Date,
5041            [
5042                DicomDate::from_ymd(2014, 10, 12).unwrap(),
5043                DicomDate::from_y(2020).unwrap()
5044            ]
5045        );
5046        assert_eq!(val.calculate_byte_len(), 14);
5047
5048        // single time with second fragment - full precision
5049        // b"185530.475600 "
5050        let val = dicom_value!(DicomTime::from_hms_micro(18, 55, 30, 475_600).unwrap());
5051        assert_eq!(val.calculate_byte_len(), 14);
5052
5053        // multi time with padding
5054        // b"185530\\185530 "
5055        let val = dicom_value!(
5056            Time,
5057            [
5058                DicomTime::from_hms(18, 55, 30).unwrap(),
5059                DicomTime::from_hms(18, 55, 30).unwrap()
5060            ]
5061        );
5062        assert_eq!(val.calculate_byte_len(), 14);
5063
5064        // single date-time with time zone, no second fragment
5065        // b"20121221093001+0100 "
5066        let offset = FixedOffset::east_opt(1 * 3600).unwrap();
5067        let val = PrimitiveValue::from(
5068            DicomDateTime::from_date_and_time_with_time_zone(
5069                DicomDate::from_ymd(2012, 12, 21).unwrap(),
5070                DicomTime::from_hms(9, 30, 1).unwrap(),
5071                offset,
5072            )
5073            .unwrap(),
5074        );
5075        assert_eq!(val.calculate_byte_len(), 20);
5076
5077        // single date-time without time zone, no second fragment
5078        // b"20121221093001 "
5079        let val = PrimitiveValue::from(
5080            DicomDateTime::from_date_and_time(
5081                DicomDate::from_ymd(2012, 12, 21).unwrap(),
5082                DicomTime::from_hms(9, 30, 1).unwrap(),
5083            )
5084            .unwrap(),
5085        );
5086        assert_eq!(val.calculate_byte_len(), 14);
5087
5088        // very precise date time, 0 microseconds
5089        let dicom_date_time = DicomDateTime::from_date_and_time_with_time_zone(
5090            DicomDate::from_ymd(2024, 8, 26).unwrap(),
5091            DicomTime::from_hms_micro(19, 41, 38, 0).unwrap(),
5092            FixedOffset::west_opt(0).unwrap(),
5093        ).unwrap();
5094        let val = PrimitiveValue::from(dicom_date_time);
5095        assert_eq!(val.calculate_byte_len(), 26);
5096    }
5097
5098    #[test]
5099    fn primitive_value_get() {
5100        assert_eq!(
5101            dicom_value!(Strs, ["Smith^John"]).string().unwrap(),
5102            "Smith^John"
5103        );
5104
5105        assert_eq!(
5106            dicom_value!(Strs, ["Smith^John"]).strings().unwrap(),
5107            &["Smith^John"]
5108        );
5109
5110        assert_eq!(dicom_value!(I32, [1, 2, 5]).int32().unwrap(), 1,);
5111
5112        assert_eq!(
5113            dicom_value!(I32, [1, 2, 5]).int32_slice().unwrap(),
5114            &[1, 2, 5],
5115        );
5116
5117        assert!(matches!(
5118            dicom_value!(I32, [1, 2, 5]).uint32(),
5119            Err(CastValueError {
5120                requested: "uint32",
5121                got: ValueType::I32,
5122                ..
5123            })
5124        ));
5125
5126        assert!(matches!(
5127            dicom_value!(I32, [1, 2, 5]).strings(),
5128            Err(CastValueError {
5129                requested: "strings",
5130                got: ValueType::I32,
5131                ..
5132            })
5133        ));
5134
5135        assert_eq!(
5136            PrimitiveValue::Date(smallvec![DicomDate::from_ymd(2014, 10, 12).unwrap()])
5137                .date()
5138                .unwrap(),
5139            DicomDate::from_ymd(2014, 10, 12).unwrap(),
5140        );
5141
5142        assert!(matches!(
5143            PrimitiveValue::Date(smallvec![DicomDate::from_ymd(2014, 10, 12).unwrap()]).time(),
5144            Err(CastValueError {
5145                requested: "time",
5146                got: ValueType::Date,
5147                ..
5148            })
5149        ));
5150    }
5151
5152    /// Expect Str to be comparable to 1-element Strs.
5153    #[test]
5154    fn eq_ignores_multi_variants() {
5155        assert_eq!(dicom_value!(Str, "abc123"), dicom_value!(Strs, ["abc123"]),);
5156
5157        assert_eq!(dicom_value!(Strs, ["abc123"]), dicom_value!(Str, "abc123"),);
5158
5159        assert_eq!(dicom_value!(Str, "ABC123"), PrimitiveValue::from("ABC123"),);
5160
5161        assert_eq!(dicom_value!(Str, ""), PrimitiveValue::from(""),);
5162    }
5163
5164    #[test]
5165    fn eq_str() {
5166        assert_eq!(PrimitiveValue::from("Doe^John"), "Doe^John");
5167        assert_eq!(dicom_value!(Strs, ["Doe^John"]), "Doe^John");
5168        assert_eq!(PrimitiveValue::from("Doe^John"), &*"Doe^John".to_owned());
5169
5170        assert_ne!(dicom_value!(Strs, ["Doe^John", "Silva^João"]), "Doe^John");
5171    }
5172}