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}