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