Skip to main content

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