dicom_core/header.rs
1//! This modules contains an assortment of types required for interpreting DICOM data elements.
2//! It comprises a variety of basic data types, such as the DICOM attribute tag, the
3//! element header, and element composite types.
4
5use crate::value::{
6 CastValueError, ConvertValueError, DataSetSequence, DicomDate, DicomDateTime, DicomTime,
7 InMemFragment, PrimitiveValue, Value, C,
8};
9use num_traits::NumCast;
10use snafu::{ensure, Backtrace, Snafu};
11use std::borrow::Cow;
12use std::cmp::Ordering;
13use std::fmt;
14use std::str::{from_utf8, FromStr};
15
16/// Error type for issues constructing a sequence item header.
17#[derive(Debug, Snafu)]
18#[non_exhaustive]
19pub enum SequenceItemHeaderError {
20 /// Unexpected header tag.
21 /// Only Item (0xFFFE, 0xE000),
22 /// Item Delimiter (0xFFFE, 0xE00D),
23 /// or Sequence Delimiter (0xFFFE, 0xE0DD)
24 /// are admitted.
25 #[snafu(display("Unexpected tag {}", tag))]
26 UnexpectedTag { tag: Tag, backtrace: Backtrace },
27 /// Unexpected delimiter value length.
28 /// Must be zero for item delimiters.
29 #[snafu(display("Unexpected delimiter length {}", len))]
30 UnexpectedDelimiterLength { len: Length, backtrace: Backtrace },
31}
32
33type Result<T, E = SequenceItemHeaderError> = std::result::Result<T, E>;
34
35/// Trait for any DICOM entity (element or item) which may have a length.
36pub trait HasLength {
37 /// Retrieve the value data's length as specified by the data element or
38 /// item, in bytes.
39 ///
40 /// It is named `length` to make it distinct from the conventional method
41 /// signature `len(&self) -> usize` for the number of elements of a
42 /// collection.
43 ///
44 /// According to the standard, the concrete value size may be undefined,
45 /// which can be the case for sequence elements or specific primitive
46 /// values.
47 fn length(&self) -> Length;
48
49 /// Check whether the value is empty (0 length).
50 fn is_empty(&self) -> bool {
51 self.length() == Length(0)
52 }
53}
54
55/// A trait for a data type containing a DICOM header.
56#[allow(clippy::len_without_is_empty)]
57pub trait Header: HasLength {
58 /// Retrieve the element's tag as a `(group, element)` tuple.
59 fn tag(&self) -> Tag;
60
61 /// Check whether this is the header of an item.
62 fn is_item(&self) -> bool {
63 self.tag() == Tag(0xFFFE, 0xE000)
64 }
65
66 /// Check whether this is the header of an item delimiter.
67 fn is_item_delimiter(&self) -> bool {
68 self.tag() == Tag(0xFFFE, 0xE00D)
69 }
70
71 /// Check whether this is the header of a sequence delimiter.
72 fn is_sequence_delimiter(&self) -> bool {
73 self.tag() == Tag(0xFFFE, 0xE0DD)
74 }
75
76 /// Check whether this is the header of an encapsulated pixel data.
77 fn is_encapsulated_pixeldata(&self) -> bool {
78 self.tag() == Tag(0x7FE0, 0x0010) && self.length().is_undefined()
79 }
80}
81
82/// Stub type representing a non-existing DICOM object.
83///
84/// This type implements [`HasLength`], but cannot be instantiated.
85/// This makes it so that [`Value<EmptyObject>`] is sure to be either
86/// a primitive value,
87/// a pixel data fragment sequence,
88/// or a sequence with no items.
89#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
90pub enum EmptyObject {}
91
92impl HasLength for EmptyObject {
93 fn length(&self) -> Length {
94 unreachable!()
95 }
96}
97
98/// A data type that represents and owns a DICOM data element.
99///
100/// This type is capable of representing any data element fully in memory,
101/// whether it be a primitive value,
102/// a nested data set (where `I` is the object type for data set items),
103/// or an encapsulated pixel data sequence (each item of type `P`).
104/// The type parameter `I` should usually implement [`HasLength`],
105/// whereas `P` should usually implement `AsRef<[u8]>`.
106#[derive(Debug, PartialEq, Clone)]
107pub struct DataElement<I = EmptyObject, P = InMemFragment> {
108 header: DataElementHeader,
109 value: Value<I, P>,
110}
111
112/// A data type that represents and owns a DICOM data element
113/// containing a primitive value.
114#[derive(Debug, PartialEq, Clone)]
115pub struct PrimitiveDataElement {
116 header: DataElementHeader,
117 value: PrimitiveValue,
118}
119
120impl PrimitiveDataElement {
121 /// Main constructor for a primitive data element.
122 pub fn new(header: DataElementHeader, value: PrimitiveValue) -> Self {
123 PrimitiveDataElement { header, value }
124 }
125}
126
127impl<I, P> From<PrimitiveDataElement> for DataElement<I, P> {
128 fn from(o: PrimitiveDataElement) -> Self {
129 DataElement {
130 header: o.header,
131 value: o.value.into(),
132 }
133 }
134}
135
136/// A data type that represents a DICOM data element with
137/// a borrowed value.
138#[derive(Debug, PartialEq, Clone)]
139pub struct DataElementRef<'v, I: 'v, P: 'v> {
140 header: DataElementHeader,
141 value: &'v Value<I, P>,
142}
143
144/// A data type that represents a DICOM data element with
145/// a borrowed primitive value.
146#[derive(Debug, PartialEq, Clone)]
147pub struct PrimitiveDataElementRef<'v> {
148 header: DataElementHeader,
149 value: &'v PrimitiveValue,
150}
151
152impl<'a> PrimitiveDataElementRef<'a> {
153 /// Main constructor for a primitive data element reference.
154 pub fn new(header: DataElementHeader, value: &'a PrimitiveValue) -> Self {
155 PrimitiveDataElementRef { header, value }
156 }
157}
158impl<I, P> HasLength for DataElement<I, P> {
159 #[inline]
160 fn length(&self) -> Length {
161 self.header.length()
162 }
163}
164
165impl<I, P> Header for DataElement<I, P> {
166 #[inline]
167 fn tag(&self) -> Tag {
168 self.header.tag()
169 }
170}
171
172impl<I, P> HasLength for &DataElement<I, P> {
173 #[inline]
174 fn length(&self) -> Length {
175 (**self).length()
176 }
177}
178
179impl<'a, I, P> Header for &'a DataElement<I, P> {
180 #[inline]
181 fn tag(&self) -> Tag {
182 (**self).tag()
183 }
184}
185
186impl<'v, I, P> HasLength for DataElementRef<'v, I, P> {
187 #[inline]
188 fn length(&self) -> Length {
189 self.header.length()
190 }
191}
192
193impl<'v, I, P> Header for DataElementRef<'v, I, P> {
194 #[inline]
195 fn tag(&self) -> Tag {
196 self.header.tag()
197 }
198}
199
200impl<I, P> DataElement<I, P> {
201 /// Create an empty data element.
202 pub fn empty(tag: Tag, vr: VR) -> Self {
203 DataElement {
204 header: DataElementHeader {
205 tag,
206 vr,
207 len: Length(0),
208 },
209 value: if vr == VR::SQ {
210 DataSetSequence::empty().into()
211 } else {
212 PrimitiveValue::Empty.into()
213 },
214 }
215 }
216
217 /// Retrieve the element header.
218 pub fn header(&self) -> &DataElementHeader {
219 &self.header
220 }
221
222 /// Retrieve the value representation, which may be unknown or not
223 /// applicable.
224 pub fn vr(&self) -> VR {
225 self.header.vr()
226 }
227
228 /// Retrieve the data value.
229 pub fn value(&self) -> &Value<I, P> {
230 &self.value
231 }
232
233 /// Move the data value out of the element, discarding the rest. If the
234 /// value is a sequence, its lifetime may still be bound to its original
235 /// source.
236 pub fn into_value(self) -> Value<I, P> {
237 self.value
238 }
239
240 /// Split the constituent parts of this element into a tuple.
241 /// If the value is a sequence,
242 /// its lifetime may still be bound to the original source.
243 pub fn into_parts(self) -> (DataElementHeader, Value<I, P>) {
244 (self.header, self.value)
245 }
246
247 /// Obtain a temporary mutable reference to the value,
248 /// so that mutations can be applied within.
249 ///
250 /// Once updated, the header is automatically updated
251 /// based on this set of rules:
252 ///
253 /// - if the value is a data set sequence,
254 /// the VR is set to `SQ` and the length is reset to undefined;
255 /// - if the value is a pixel data fragment sequence,
256 /// the VR is set to `OB` and the lenght is reset to undefined;
257 /// - if the value is primitive,
258 /// the length is recalculated, leaving the VR as is.
259 ///
260 /// If these rules do not result in a valid element,
261 /// consider reconstructing the data element instead.
262 pub fn update_value(&mut self, mut f: impl FnMut(&mut Value<I, P>)) {
263 f(&mut self.value);
264 match &mut self.value {
265 Value::Primitive(v) => {
266 let byte_len = v.calculate_byte_len();
267 self.header.len = Length(byte_len as u32);
268 }
269 Value::Sequence(_) => {
270 self.header.vr = VR::SQ;
271 self.header.len = Length::UNDEFINED;
272 }
273 Value::PixelSequence(_) => {
274 self.header.vr = VR::OB;
275 self.header.len = Length::UNDEFINED;
276 }
277 }
278 }
279}
280
281impl<I, P> DataElement<I, P>
282where
283 I: HasLength,
284{
285 /// Create a data element from the given parts,
286 /// where the length is inferred from the value's byte length.
287 ///
288 /// If the value is textual,
289 /// the byte length of that value encoded in UTF-8 is assumed.
290 /// If you already have a length in this context,
291 /// prefer calling `new_with_len` instead.
292 ///
293 /// This method will not check whether the value representation is
294 /// compatible with the given value.
295 pub fn new<T>(tag: Tag, vr: VR, value: T) -> Self
296 where
297 T: Into<Value<I, P>>,
298 {
299 let value = value.into();
300 DataElement {
301 header: DataElementHeader {
302 tag,
303 vr,
304 len: value.length(),
305 },
306 value,
307 }
308 }
309
310 /// Create a primitive data element from the given parts.
311 ///
312 /// This method will not check
313 /// whether the length accurately represents the given value's byte length,
314 /// nor whether the value representation is compatible with the value.
315 pub fn new_with_len<T>(tag: Tag, vr: VR, length: Length, value: T) -> Self
316 where
317 T: Into<Value<I, P>>,
318 {
319 let value = value.into();
320 DataElement {
321 header: DataElementHeader {
322 tag,
323 vr,
324 len: length,
325 },
326 value,
327 }
328 }
329
330 /// Retrieve the element's value as a single clean string,
331 /// with no trailing whitespace.
332 ///
333 /// Returns an error if the value is not primitive.
334 pub fn to_str(&self) -> Result<Cow<str>, ConvertValueError> {
335 self.value.to_str()
336 }
337
338 /// Retrieve the element's value as a single raw string,
339 /// with trailing whitespace kept.
340 ///
341 /// Returns an error if the value is not primitive.
342 pub fn to_raw_str(&self) -> Result<Cow<str>, ConvertValueError> {
343 self.value.to_raw_str()
344 }
345
346 /// Convert the full primitive value into raw bytes.
347 ///
348 /// String values already encoded with the `Str` and `Strs` variants
349 /// are provided in UTF-8.
350 ///
351 /// Returns an error if the value is not primitive.
352 pub fn to_bytes(&self) -> Result<Cow<[u8]>, ConvertValueError> {
353 self.value.to_bytes()
354 }
355
356 /// Convert the full value of the data element into a sequence of strings.
357 ///
358 /// If the value is a primitive, it will be converted into
359 /// a vector of strings as described in [`PrimitiveValue::to_multi_str`].
360 ///
361 /// Returns an error if the value is not primitive.
362 ///
363 /// [`PrimitiveValue::to_multi_str`]: ../enum.PrimitiveValue.html#to_multi_str
364 pub fn to_multi_str(&self) -> Result<Cow<[String]>, CastValueError> {
365 self.value().to_multi_str()
366 }
367
368 /// Retrieve and convert the value of the data element into an integer.
369 ///
370 /// If the value is a primitive,
371 /// it will be converted into an integer
372 /// as described in [`PrimitiveValue::to_int`].
373 ///
374 /// Returns an error if the value is not primitive.
375 ///
376 /// [`PrimitiveValue::to_int`]: ../enum.PrimitiveValue.html#to_int
377 pub fn to_int<T>(&self) -> Result<T, ConvertValueError>
378 where
379 T: Clone,
380 T: NumCast,
381 T: FromStr<Err = std::num::ParseIntError>,
382 {
383 self.value().to_int()
384 }
385
386 /// Retrieve and convert the value of the data element
387 /// into a sequence of integers.
388 ///
389 /// If the value is a primitive, it will be converted into
390 /// a vector of integers as described in [PrimitiveValue::to_multi_int].
391 ///
392 /// [PrimitiveValue::to_multi_int]: ../enum.PrimitiveValue.html#to_multi_int
393 pub fn to_multi_int<T>(&self) -> Result<Vec<T>, ConvertValueError>
394 where
395 T: Clone,
396 T: NumCast,
397 T: FromStr<Err = std::num::ParseIntError>,
398 {
399 self.value().to_multi_int()
400 }
401
402 /// Retrieve and convert the value of the data element
403 /// into a single-precision floating point number.
404 ///
405 /// If the value is a primitive, it will be converted into
406 /// a number as described in [`PrimitiveValue::to_float32`].
407 ///
408 /// Returns an error if the value is not primitive.
409 ///
410 /// [`PrimitiveValue::to_float32`]: ../enum.PrimitiveValue.html#to_float32
411 pub fn to_float32(&self) -> Result<f32, ConvertValueError> {
412 self.value().to_float32()
413 }
414
415 /// Retrieve and convert the value of the data element
416 /// into a sequence of single-precision floating point numbers.
417 ///
418 /// If the value is a primitive, it will be converted into
419 /// a vector of numbers as described in [`PrimitiveValue::to_multi_float32`].
420 ///
421 /// Returns an error if the value is not primitive.
422 ///
423 /// [`PrimitiveValue::to_multi_float32`]: ../enum.PrimitiveValue.html#to_multi_float32
424 pub fn to_multi_float32(&self) -> Result<Vec<f32>, ConvertValueError> {
425 self.value().to_multi_float32()
426 }
427
428 /// Retrieve and convert the value of the data element
429 /// into a double-precision floating point number.
430 ///
431 /// If the value is a primitive, it will be converted into
432 /// a number as described in [`PrimitiveValue::to_float64`].
433 ///
434 /// Returns an error if the value is not primitive.
435 ///
436 /// [`PrimitiveValue::to_float64`]: ../enum.PrimitiveValue.html#to_float64
437 pub fn to_float64(&self) -> Result<f64, ConvertValueError> {
438 self.value().to_float64()
439 }
440
441 /// Retrieve and convert the value of the data element
442 /// into a sequence of double-precision floating point numbers.
443 ///
444 /// If the value is a primitive, it will be converted into
445 /// a vector of numbers as described in [`PrimitiveValue::to_multi_float64`].
446 ///
447 /// Returns an error if the value is not primitive.
448 ///
449 /// [`PrimitiveValue::to_multi_float64`]: ../enum.PrimitiveValue.html#to_multi_float64
450 pub fn to_multi_float64(&self) -> Result<Vec<f64>, ConvertValueError> {
451 self.value().to_multi_float64()
452 }
453
454 /// Retrieve and convert the primitive value into a date.
455 ///
456 /// If the value is a primitive, it will be converted into
457 /// a `DicomDate` as described in [`PrimitiveValue::to_date`].
458 ///
459 /// Returns an error if the value is not primitive.
460 ///
461 pub fn to_date(&self) -> Result<DicomDate, ConvertValueError> {
462 self.value().to_date()
463 }
464
465 /// Retrieve and convert the primitive value into a sequence of dates.
466 ///
467 /// If the value is a primitive, it will be converted into
468 /// a vector of `DicomDate` as described in [`PrimitiveValue::to_multi_date`].
469 ///
470 /// Returns an error if the value is not primitive.
471 ///
472 pub fn to_multi_date(&self) -> Result<Vec<DicomDate>, ConvertValueError> {
473 self.value().to_multi_date()
474 }
475
476 /// Retrieve and convert the primitive value into a time.
477 ///
478 /// If the value is a primitive, it will be converted into
479 /// a `DicomTime` as described in [`PrimitiveValue::to_time`].
480 ///
481 /// Returns an error if the value is not primitive.
482 ///
483 pub fn to_time(&self) -> Result<DicomTime, ConvertValueError> {
484 self.value().to_time()
485 }
486
487 /// Retrieve and convert the primitive value into a sequence of times.
488 ///
489 /// If the value is a primitive, it will be converted into
490 /// a vector of `DicomTime` as described in [`PrimitiveValue::to_multi_time`].
491 ///
492 /// Returns an error if the value is not primitive.
493 ///
494 pub fn to_multi_time(&self) -> Result<Vec<DicomTime>, ConvertValueError> {
495 self.value().to_multi_time()
496 }
497
498 /// Retrieve and convert the primitive value into a date-time.
499 ///
500 /// If the value is a primitive, it will be converted into
501 /// a `DicomDateTime` as described in [`PrimitiveValue::to_datetime`].
502 ///
503 /// Returns an error if the value is not primitive.
504 ///
505 pub fn to_datetime(&self) -> Result<DicomDateTime, ConvertValueError> {
506 self.value().to_datetime()
507 }
508
509 /// Retrieve and convert the primitive value into a sequence of date-times.
510 ///
511 /// If the value is a primitive, it will be converted into
512 /// a vector of `DicomDateTime` as described in [`PrimitiveValue::to_multi_datetime`].
513 ///
514 /// Returns an error if the value is not primitive.
515 ///
516 pub fn to_multi_datetime(&self) -> Result<Vec<DicomDateTime>, ConvertValueError> {
517 self.value().to_multi_datetime()
518 }
519
520 /// Retrieve the items stored in a sequence value.
521 ///
522 /// Returns `None` if the underlying value is not a data set sequence.
523 pub fn items(&self) -> Option<&[I]> {
524 self.value().items()
525 }
526
527 /// Gets a mutable reference to the items of a sequence value.
528 ///
529 /// The header's recorded length is automatically reset to undefined,
530 /// in order to prevent inconsistencies.
531 ///
532 /// Returns `None` if the underlying value is not a data set sequence.
533 pub fn items_mut(&mut self) -> Option<&mut C<I>> {
534 self.header.len = Length::UNDEFINED;
535 self.value.items_mut()
536 }
537
538 /// Retrieve the fragments stored in a pixel data sequence value.
539 ///
540 /// Returns `None` if the value is not a pixel data sequence.
541 pub fn fragments(&self) -> Option<&[P]> {
542 self.value().fragments()
543 }
544
545 /// Obtain a mutable reference to the fragments
546 /// stored in a pixel data sequence value.
547 ///
548 /// The header's recorded length is automatically reset to undefined,
549 /// in order to prevent inconsistencies.
550 ///
551 /// Returns `None` if the value is not a pixel data sequence.
552 pub fn fragments_mut(&mut self) -> Option<&mut C<P>> {
553 self.header.len = Length::UNDEFINED;
554 self.value.fragments_mut()
555 }
556
557 /// Obtain a reference to the encapsulated pixel data's basic offset table.
558 ///
559 /// Returns `None` if the underlying value is not a pixel data sequence.
560 pub fn offset_table(&self) -> Option<&[u32]> {
561 self.value().offset_table()
562 }
563}
564
565impl<'v, I, P> DataElementRef<'v, I, P>
566where
567 I: HasLength,
568{
569 /// Create a data element from the given parts. This method will not check
570 /// whether the value representation is compatible with the value. Caution
571 /// is advised.
572 pub fn new(tag: Tag, vr: VR, value: &'v Value<I, P>) -> Self {
573 DataElementRef {
574 header: DataElementHeader {
575 tag,
576 vr,
577 len: value.length(),
578 },
579 value,
580 }
581 }
582
583 /// Retrieves the element's value representation, which can be unknown.
584 pub fn vr(&self) -> VR {
585 self.header.vr()
586 }
587
588 /// Retrieves the DICOM value.
589 pub fn value(&self) -> &Value<I, P> {
590 self.value
591 }
592}
593
594/// Macro for implementing getters to single and multi-values,
595/// by delegating to `Value`.
596///
597/// Should be placed inside `DataElement`'s impl block.
598macro_rules! impl_primitive_getters {
599 ($name_single: ident, $name_multi: ident, $variant: ident, $ret: ty) => {
600 /// Get a single value of the requested type.
601 ///
602 /// If it contains multiple values,
603 /// only the first one is returned.
604 /// An error is returned if the variant is not compatible.
605 pub fn $name_single(&self) -> Result<$ret, CastValueError> {
606 self.value().$name_single()
607 }
608
609 /// Get a sequence of values of the requested type without copying.
610 ///
611 /// An error is returned if the variant is not compatible.
612 pub fn $name_multi(&self) -> Result<&[$ret], CastValueError> {
613 self.value().$name_multi()
614 }
615 };
616}
617
618impl<I, P> DataElement<I, P> {
619 /// Get a single string value.
620 ///
621 /// If it contains multiple strings,
622 /// only the first one is returned.
623 ///
624 /// An error is returned if the variant is not compatible.
625 ///
626 /// To enable conversions of other variants to a textual representation,
627 /// see [`to_str()`] instead.
628 ///
629 /// [`to_str()`]: #method.to_str
630 pub fn string(&self) -> Result<&str, CastValueError> {
631 self.value().string()
632 }
633
634 /// Get the inner sequence of string values
635 /// if the variant is either `Str` or `Strs`.
636 ///
637 /// An error is returned if the variant is not compatible.
638 ///
639 /// To enable conversions of other variants to a textual representation,
640 /// see [`to_str()`] instead.
641 ///
642 /// [`to_str()`]: #method.to_str
643 pub fn strings(&self) -> Result<&[String], CastValueError> {
644 self.value().strings()
645 }
646
647 impl_primitive_getters!(date, dates, Date, DicomDate);
648 impl_primitive_getters!(time, times, Time, DicomTime);
649 impl_primitive_getters!(datetime, datetimes, DateTime, DicomDateTime);
650 impl_primitive_getters!(uint8, uint8_slice, U8, u8);
651 impl_primitive_getters!(uint16, uint16_slice, U16, u16);
652 impl_primitive_getters!(int16, int16_slice, I16, i16);
653 impl_primitive_getters!(uint32, uint32_slice, U32, u32);
654 impl_primitive_getters!(int32, int32_slice, I32, i32);
655 impl_primitive_getters!(int64, int64_slice, I64, i64);
656 impl_primitive_getters!(uint64, uint64_slice, U64, u64);
657 impl_primitive_getters!(float32, float32_slice, F32, f32);
658 impl_primitive_getters!(float64, float64_slice, F64, f64);
659}
660
661/// A data structure for a data element header, containing
662/// a tag, value representation and specified length.
663#[derive(Debug, PartialEq, Clone, Copy)]
664pub struct DataElementHeader {
665 /// DICOM tag
666 pub tag: Tag,
667 /// Value Representation
668 pub vr: VR,
669 /// Element length
670 pub len: Length,
671}
672
673impl HasLength for DataElementHeader {
674 #[inline]
675 fn length(&self) -> Length {
676 self.len
677 }
678}
679
680impl Header for DataElementHeader {
681 #[inline]
682 fn tag(&self) -> Tag {
683 self.tag
684 }
685}
686
687impl DataElementHeader {
688 /// Create a new data element header with the given properties.
689 /// This is just a trivial constructor.
690 #[inline]
691 pub fn new<T: Into<Tag>>(tag: T, vr: VR, len: Length) -> DataElementHeader {
692 DataElementHeader {
693 tag: tag.into(),
694 vr,
695 len,
696 }
697 }
698
699 /// Retrieve the element's value representation, which can be unknown.
700 #[inline]
701 pub fn vr(&self) -> VR {
702 self.vr
703 }
704
705 /// Check whether the header suggests the value to be a sequence value:
706 /// if the value representation is SQ or the length is undefined.
707 #[inline]
708 pub fn is_non_primitive(&self) -> bool {
709 self.vr == VR::SQ || self.length().is_undefined()
710 }
711}
712
713impl From<SequenceItemHeader> for DataElementHeader {
714 fn from(value: SequenceItemHeader) -> DataElementHeader {
715 DataElementHeader {
716 tag: value.tag(),
717 vr: VR::UN,
718 len: value.length(),
719 }
720 }
721}
722
723/// Data type for describing a sequence item data element.
724/// If the element represents an item, it will also contain
725/// the specified length.
726#[derive(Debug, PartialEq, Clone, Copy)]
727pub enum SequenceItemHeader {
728 /// The cursor contains an item.
729 Item {
730 /// the length of the item in bytes (can be 0xFFFFFFFF if undefined)
731 len: Length,
732 },
733 /// The cursor read an item delimiter.
734 /// The element ends here and should not be read any further.
735 ItemDelimiter,
736 /// The cursor read a sequence delimiter.
737 /// The element ends here and should not be read any further.
738 SequenceDelimiter,
739}
740
741impl SequenceItemHeader {
742 /// Create a sequence item header using the element's raw properties.
743 /// An error can be raised if the given properties do not relate to a
744 /// sequence item, a sequence item delimiter or a sequence delimiter.
745 pub fn new<T: Into<Tag>>(tag: T, len: Length) -> Result<SequenceItemHeader> {
746 match tag.into() {
747 Tag(0xFFFE, 0xE000) => {
748 // item
749 Ok(SequenceItemHeader::Item { len })
750 }
751 Tag(0xFFFE, 0xE00D) => {
752 // item delimiter
753 // delimiters should not have a positive length
754 if len != Length(0) {
755 UnexpectedDelimiterLengthSnafu { len }.fail()
756 } else {
757 Ok(SequenceItemHeader::ItemDelimiter)
758 }
759 }
760 Tag(0xFFFE, 0xE0DD) => {
761 // sequence delimiter
762 Ok(SequenceItemHeader::SequenceDelimiter)
763 }
764 tag => UnexpectedTagSnafu { tag }.fail(),
765 }
766 }
767}
768
769impl HasLength for SequenceItemHeader {
770 #[inline]
771 fn length(&self) -> Length {
772 match *self {
773 SequenceItemHeader::Item { len } => len,
774 SequenceItemHeader::ItemDelimiter | SequenceItemHeader::SequenceDelimiter => Length(0),
775 }
776 }
777}
778impl Header for SequenceItemHeader {
779 #[inline]
780 fn tag(&self) -> Tag {
781 match *self {
782 SequenceItemHeader::Item { .. } => Tag(0xFFFE, 0xE000),
783 SequenceItemHeader::ItemDelimiter => Tag(0xFFFE, 0xE00D),
784 SequenceItemHeader::SequenceDelimiter => Tag(0xFFFE, 0xE0DD),
785 }
786 }
787}
788
789/// An enum type for a DICOM value representation.
790#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone, Ord, PartialOrd)]
791pub enum VR {
792 /// Application Entity
793 AE,
794 /// Age String
795 AS,
796 /// Attribute Tag
797 AT,
798 /// Code String
799 CS,
800 /// Date
801 DA,
802 /// Decimal String
803 DS,
804 /// Date Time
805 DT,
806 /// Floating Point Single
807 FL,
808 /// Floating Point Double
809 FD,
810 /// Integer String
811 IS,
812 /// Long String
813 LO,
814 /// Long Text
815 LT,
816 /// Other Byte
817 OB,
818 /// Other Double
819 OD,
820 /// Other Float
821 OF,
822 /// Other Long
823 OL,
824 /// Other Very Long
825 OV,
826 /// Other Word
827 OW,
828 /// Person Name
829 PN,
830 /// Short String
831 SH,
832 /// Signed Long
833 SL,
834 /// Sequence of Items
835 SQ,
836 /// Signed Short
837 SS,
838 /// Short Text
839 ST,
840 /// Signed Very Long
841 SV,
842 /// Time
843 TM,
844 /// Unlimited Characters
845 UC,
846 /// Unique Identifier (UID)
847 UI,
848 /// Unsigned Long
849 UL,
850 /// Unknown
851 UN,
852 /// Universal Resource Identifier or Universal Resource Locator (URI/URL)
853 UR,
854 /// Unsigned Short
855 US,
856 /// Unlimited Text
857 UT,
858 /// Unsigned Very Long
859 UV,
860}
861
862impl VR {
863 /// Obtain the value representation corresponding to the given two bytes.
864 /// Each byte should represent an alphabetic character in upper case.
865 pub fn from_binary(chars: [u8; 2]) -> Option<Self> {
866 from_utf8(chars.as_ref())
867 .ok()
868 .and_then(|s| VR::from_str(s).ok())
869 }
870
871 /// Retrieve a string representation of this VR.
872 pub fn to_string(self) -> &'static str {
873 use VR::*;
874 match self {
875 AE => "AE",
876 AS => "AS",
877 AT => "AT",
878 CS => "CS",
879 DA => "DA",
880 DS => "DS",
881 DT => "DT",
882 FL => "FL",
883 FD => "FD",
884 IS => "IS",
885 LO => "LO",
886 LT => "LT",
887 OB => "OB",
888 OD => "OD",
889 OF => "OF",
890 OL => "OL",
891 OV => "OV",
892 OW => "OW",
893 PN => "PN",
894 SH => "SH",
895 SL => "SL",
896 SQ => "SQ",
897 SS => "SS",
898 ST => "ST",
899 SV => "SV",
900 TM => "TM",
901 UC => "UC",
902 UI => "UI",
903 UL => "UL",
904 UN => "UN",
905 UR => "UR",
906 US => "US",
907 UT => "UT",
908 UV => "UV",
909 }
910 }
911
912 /// Retrieve a copy of this VR's byte representation.
913 /// The function returns two alphabetic characters in upper case.
914 pub fn to_bytes(self) -> [u8; 2] {
915 let bytes = self.to_string().as_bytes();
916 [bytes[0], bytes[1]]
917 }
918}
919
920/// Obtain the value representation corresponding to the given string.
921/// The string should hold exactly two UTF-8 encoded alphabetic characters
922/// in upper case, otherwise no match is made.
923impl FromStr for VR {
924 type Err = &'static str;
925
926 fn from_str(string: &str) -> std::result::Result<Self, Self::Err> {
927 use VR::*;
928 match string {
929 "AE" => Ok(AE),
930 "AS" => Ok(AS),
931 "AT" => Ok(AT),
932 "CS" => Ok(CS),
933 "DA" => Ok(DA),
934 "DS" => Ok(DS),
935 "DT" => Ok(DT),
936 "FL" => Ok(FL),
937 "FD" => Ok(FD),
938 "IS" => Ok(IS),
939 "LO" => Ok(LO),
940 "LT" => Ok(LT),
941 "OB" => Ok(OB),
942 "OD" => Ok(OD),
943 "OF" => Ok(OF),
944 "OL" => Ok(OL),
945 "OV" => Ok(OV),
946 "OW" => Ok(OW),
947 "PN" => Ok(PN),
948 "SH" => Ok(SH),
949 "SL" => Ok(SL),
950 "SQ" => Ok(SQ),
951 "SS" => Ok(SS),
952 "ST" => Ok(ST),
953 "SV" => Ok(SV),
954 "TM" => Ok(TM),
955 "UC" => Ok(UC),
956 "UI" => Ok(UI),
957 "UL" => Ok(UL),
958 "UN" => Ok(UN),
959 "UR" => Ok(UR),
960 "US" => Ok(US),
961 "UT" => Ok(UT),
962 "UV" => Ok(UV),
963 _ => Err("no such value representation"),
964 }
965 }
966}
967
968impl fmt::Display for VR {
969 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
970 f.write_str(VR::to_string(*self))
971 }
972}
973
974/// Idiomatic alias for a tag's group number.
975pub type GroupNumber = u16;
976/// Idiomatic alias for a tag's element number.
977pub type ElementNumber = u16;
978
979/// The data type for DICOM data element tags.
980///
981/// Tags are composed by a (group, element) pair of 16-bit unsigned integers.
982/// Aside from writing a struct expression,
983/// a `Tag` may also be built by converting a `(u16, u16)` or a `[u16; 2]`.
984///
985/// In its text form,
986/// DICOM tags are printed by [`Display`][display] in the form `(GGGG,EEEE)`,
987/// where the group and element parts are in uppercase hexadecimal.
988/// Moreover, its [`FromStr`] implementation
989/// support converting strings in the following text formats into DICOM tags:
990///
991/// - `(GGGG,EEEE)`
992/// - `GGGG,EEEE`
993/// - `GGGGEEEE`
994///
995/// [display]: std::fmt::Display
996///
997/// # Example
998///
999/// ```
1000/// # use dicom_core::Tag;
1001/// let tag: Tag = "(0010,1005)".parse()?;
1002/// assert_eq!(tag, Tag(0x0010, 0x1005));
1003/// # Ok::<_, dicom_core::header::ParseTagError>(())
1004/// ```
1005#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Copy)]
1006pub struct Tag(pub GroupNumber, pub ElementNumber);
1007
1008impl Tag {
1009 /// Getter for the tag's group value.
1010 #[inline]
1011 pub fn group(self) -> GroupNumber {
1012 self.0
1013 }
1014
1015 /// Getter for the tag's element value.
1016 #[inline]
1017 pub fn element(self) -> ElementNumber {
1018 self.1
1019 }
1020}
1021
1022impl fmt::Debug for Tag {
1023 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1024 write!(f, "Tag({:#06X?}, {:#06X?})", self.0, self.1)
1025 }
1026}
1027
1028impl fmt::Display for Tag {
1029 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1030 write!(f, "({:04X},{:04X})", self.0, self.1)
1031 }
1032}
1033
1034impl From<(u16, u16)> for Tag {
1035 #[inline]
1036 fn from(value: (u16, u16)) -> Tag {
1037 Tag(value.0, value.1)
1038 }
1039}
1040
1041impl From<[u16; 2]> for Tag {
1042 #[inline]
1043 fn from(value: [u16; 2]) -> Tag {
1044 Tag(value[0], value[1])
1045 }
1046}
1047
1048/// Could not parse DICOM tag
1049#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Snafu)]
1050pub enum ParseTagError {
1051 /// expected tag start '('
1052 Start,
1053 /// expected tag part separator ','
1054 Separator,
1055 /// expected tag end ')'
1056 End,
1057 /// unexpected length
1058 Length,
1059 /// Illegal character for hexadecimal number
1060 Number,
1061}
1062
1063/// This parser implementation for DICOM tags
1064/// accepts strictly one of the following formats:
1065/// - `ggggeeee`
1066/// - or `gggg,eeee`
1067/// - or `(gggg,eeee)`
1068///
1069/// where `gggg` and `eeee` are the characters representing
1070/// the group part an the element part in hexadecimal,
1071/// with four characters each.
1072/// Whitespace is not excluded automatically,
1073/// and may need to be removed before-parse
1074/// depending on the context.
1075/// Lowercase and uppercase characters are allowed.
1076impl FromStr for Tag {
1077 type Err = ParseTagError;
1078
1079 fn from_str(s: &str) -> Result<Self, Self::Err> {
1080 match s.len() {
1081 11 => {
1082 // (gggg,eeee)
1083 ensure!(s.starts_with('('), StartSnafu);
1084
1085 let (num_g, rest) = parse_tag_part(&s[1..])?;
1086
1087 ensure!(rest.starts_with(','), SeparatorSnafu);
1088
1089 let (num_e, rest) = parse_tag_part(&rest[1..])?;
1090
1091 ensure!(rest == ")", EndSnafu);
1092
1093 Ok(Tag(num_g, num_e))
1094 }
1095 9 => {
1096 // gggg,eeee
1097 let (num_g, rest) = parse_tag_part(s)?;
1098
1099 ensure!(rest.starts_with(','), SeparatorSnafu);
1100
1101 let (num_e, _) = parse_tag_part(&rest[1..])?;
1102
1103 Ok(Tag(num_g, num_e))
1104 }
1105 8 => {
1106 // ggggeeee
1107 let (g, e) = s.split_at(4);
1108 let (num_g, _) = parse_tag_part(g)?;
1109 let (num_e, _) = parse_tag_part(e)?;
1110
1111 Ok(Tag(num_g, num_e))
1112 }
1113 _ => Err(ParseTagError::Length),
1114 }
1115 }
1116}
1117
1118fn parse_tag_part(s: &str) -> Result<(u16, &str), ParseTagError> {
1119 ensure!(s.is_char_boundary(4), NumberSnafu);
1120
1121 let (num, rest) = s.split_at(4);
1122 ensure!(num.chars().all(|c| c.is_ascii_hexdigit()), NumberSnafu);
1123
1124 let num = u16::from_str_radix(num, 16).expect("failed to parse tag part");
1125 Ok((num, rest))
1126}
1127
1128/// A type for representing data set content length, in bytes.
1129/// An internal value of `0xFFFF_FFFF` represents an undefined
1130/// (unspecified) length, which would have to be determined
1131/// with a traversal based on the content's encoding.
1132///
1133/// This also means that numeric comparisons and arithmetic
1134/// do not function the same way as primitive number types:
1135///
1136/// Two length of undefined length are not equal.
1137///
1138/// ```
1139/// # use dicom_core::Length;
1140/// assert_ne!(Length::UNDEFINED, Length::UNDEFINED);
1141/// ```
1142///
1143/// Any addition or substraction with at least one undefined
1144/// length results in an undefined length.
1145///
1146/// ```
1147/// # use dicom_core::Length;
1148/// assert!((Length::defined(64) + Length::UNDEFINED).is_undefined());
1149/// assert!((Length::UNDEFINED + 8).is_undefined());
1150/// ```
1151///
1152/// Comparing between at least one undefined length is always `false`.
1153///
1154/// ```
1155/// # use dicom_core::Length;
1156/// assert!(Length::defined(16) < Length::defined(64));
1157/// assert!(!(Length::UNDEFINED < Length::defined(64)));
1158/// assert!(!(Length::UNDEFINED > Length::defined(64)));
1159///
1160/// assert!(!(Length::UNDEFINED < Length::UNDEFINED));
1161/// assert!(!(Length::UNDEFINED > Length::UNDEFINED));
1162/// assert!(!(Length::UNDEFINED <= Length::UNDEFINED));
1163/// assert!(!(Length::UNDEFINED >= Length::UNDEFINED));
1164/// ```
1165///
1166#[derive(Clone, Copy)]
1167pub struct Length(pub u32);
1168
1169const UNDEFINED_LEN: u32 = 0xFFFF_FFFF;
1170
1171impl Length {
1172 /// A length that is undefined.
1173 pub const UNDEFINED: Self = Length(UNDEFINED_LEN);
1174
1175 /// Create a new length value from its internal representation.
1176 /// This is equivalent to `Length(len)`.
1177 #[inline]
1178 pub fn new(len: u32) -> Self {
1179 Length(len)
1180 }
1181
1182 /// Create a new length value with the given number of bytes.
1183 ///
1184 /// # Panic
1185 ///
1186 /// This function will panic if `len` represents an undefined length.
1187 #[inline]
1188 pub fn defined(len: u32) -> Self {
1189 assert_ne!(len, UNDEFINED_LEN);
1190 Length(len)
1191 }
1192}
1193
1194impl From<u32> for Length {
1195 #[inline]
1196 fn from(o: u32) -> Self {
1197 Length(o)
1198 }
1199}
1200
1201impl PartialEq<Length> for Length {
1202 fn eq(&self, rhs: &Length) -> bool {
1203 match (self.0, rhs.0) {
1204 (UNDEFINED_LEN, _) | (_, UNDEFINED_LEN) => false,
1205 (l1, l2) => l1 == l2,
1206 }
1207 }
1208}
1209
1210impl PartialOrd<Length> for Length {
1211 fn partial_cmp(&self, rhs: &Length) -> Option<Ordering> {
1212 match (self.0, rhs.0) {
1213 (UNDEFINED_LEN, _) | (_, UNDEFINED_LEN) => None,
1214 (l1, l2) => Some(l1.cmp(&l2)),
1215 }
1216 }
1217}
1218
1219impl std::ops::Add<Length> for Length {
1220 type Output = Self;
1221
1222 fn add(self, rhs: Length) -> Self::Output {
1223 match (self.0, rhs.0) {
1224 (UNDEFINED_LEN, _) | (_, UNDEFINED_LEN) => Length::UNDEFINED,
1225 (l1, l2) => {
1226 let o = l1 + l2;
1227 debug_assert!(
1228 o != UNDEFINED_LEN,
1229 "integer overflow (0xFFFF_FFFF reserved for undefined length)"
1230 );
1231 Length(o)
1232 }
1233 }
1234 }
1235}
1236
1237impl std::ops::Add<i32> for Length {
1238 type Output = Self;
1239
1240 fn add(self, rhs: i32) -> Self::Output {
1241 match self.0 {
1242 UNDEFINED_LEN => Length::UNDEFINED,
1243 len => {
1244 let o = (len as i32 + rhs) as u32;
1245 debug_assert!(
1246 o != UNDEFINED_LEN,
1247 "integer overflow (0xFFFF_FFFF reserved for undefined length)"
1248 );
1249
1250 Length(o)
1251 }
1252 }
1253 }
1254}
1255
1256impl std::ops::Sub<Length> for Length {
1257 type Output = Self;
1258
1259 fn sub(self, rhs: Length) -> Self::Output {
1260 let mut o = self;
1261 o -= rhs;
1262 o
1263 }
1264}
1265
1266impl std::ops::SubAssign<Length> for Length {
1267 fn sub_assign(&mut self, rhs: Length) {
1268 match (self.0, rhs.0) {
1269 (UNDEFINED_LEN, _) | (_, UNDEFINED_LEN) => (), // no-op
1270 (_, l2) => {
1271 self.0 -= l2;
1272 debug_assert!(
1273 self.0 != UNDEFINED_LEN,
1274 "integer overflow (0xFFFF_FFFF reserved for undefined length)"
1275 );
1276 }
1277 }
1278 }
1279}
1280
1281impl std::ops::Sub<i32> for Length {
1282 type Output = Self;
1283
1284 fn sub(self, rhs: i32) -> Self::Output {
1285 let mut o = self;
1286 o -= rhs;
1287 o
1288 }
1289}
1290
1291impl std::ops::SubAssign<i32> for Length {
1292 fn sub_assign(&mut self, rhs: i32) {
1293 match self.0 {
1294 UNDEFINED_LEN => (), // no-op
1295 len => {
1296 self.0 = (len as i32 - rhs) as u32;
1297 debug_assert!(
1298 self.0 != UNDEFINED_LEN,
1299 "integer overflow (0xFFFF_FFFF reserved for undefined length)"
1300 );
1301 }
1302 }
1303 }
1304}
1305
1306impl Length {
1307 /// Check whether this length is undefined (unknown).
1308 #[inline]
1309 pub fn is_undefined(self) -> bool {
1310 self.0 == UNDEFINED_LEN
1311 }
1312
1313 /// Check whether this length is well defined (not undefined).
1314 #[inline]
1315 pub fn is_defined(self) -> bool {
1316 !self.is_undefined()
1317 }
1318
1319 /// Fetch the concrete length value, if available.
1320 /// Returns `None` if it represents an undefined length.
1321 #[inline]
1322 pub fn get(self) -> Option<u32> {
1323 match self.0 {
1324 UNDEFINED_LEN => None,
1325 v => Some(v),
1326 }
1327 }
1328
1329 /// Check whether the length is equally specified as another length.
1330 /// Unlike the implemented `PartialEq`, two undefined lengths are
1331 /// considered equivalent by this method.
1332 #[inline]
1333 pub fn inner_eq(self, other: Length) -> bool {
1334 self.0 == other.0
1335 }
1336}
1337
1338impl fmt::Debug for Length {
1339 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1340 match self.0 {
1341 UNDEFINED_LEN => f.write_str("Length(Undefined)"),
1342 l => f.debug_tuple("Length").field(&l).finish(),
1343 }
1344 }
1345}
1346
1347impl fmt::Display for Length {
1348 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1349 match self.0 {
1350 UNDEFINED_LEN => f.write_str("U/L"),
1351 l => write!(f, "{}", &l),
1352 }
1353 }
1354}
1355
1356#[cfg(test)]
1357mod tests {
1358 use super::*;
1359 use crate::{dicom_value, value::PixelFragmentSequence, DicomValue};
1360
1361 #[test]
1362 fn to_clean_string() {
1363 let p = dicom_value!(U16, [256, 0, 16]);
1364 let val = DicomValue::new(p);
1365 let element = DataElement::new(Tag(0x0028, 0x3002), VR::US, val);
1366 assert_eq!(element.to_str().unwrap(), "256\\0\\16",);
1367 }
1368
1369 #[test]
1370 fn tag_from_u16_pair() {
1371 let t = Tag::from((0x0010u16, 0x0020u16));
1372 assert_eq!(0x0010u16, t.group());
1373 assert_eq!(0x0020u16, t.element());
1374 }
1375
1376 #[test]
1377 fn tag_from_u16_array() {
1378 let t = Tag::from([0x0010u16, 0x0020u16]);
1379 assert_eq!(0x0010u16, t.group());
1380 assert_eq!(0x0020u16, t.element());
1381 }
1382
1383 /// Ensure good order between tags
1384 #[test]
1385 fn tag_ord() {
1386 assert_eq!(
1387 Tag(0x0010, 0x0020).cmp(&Tag(0x0010, 0x0020)),
1388 Ordering::Equal
1389 );
1390
1391 assert_eq!(
1392 Tag(0x0010, 0x0020).cmp(&Tag(0x0010, 0x0024)),
1393 Ordering::Less
1394 );
1395 assert_eq!(
1396 Tag(0x0010, 0x0020).cmp(&Tag(0x0020, 0x0010)),
1397 Ordering::Less
1398 );
1399 assert_eq!(
1400 Tag(0x0010, 0x0020).cmp(&Tag(0x0020, 0x0024)),
1401 Ordering::Less
1402 );
1403 assert_eq!(
1404 Tag(0x0010, 0x0000).cmp(&Tag(0x0320, 0x0010)),
1405 Ordering::Less
1406 );
1407
1408 assert_eq!(
1409 Tag(0x0010, 0x0020).cmp(&Tag(0x0010, 0x0010)),
1410 Ordering::Greater
1411 );
1412 assert_eq!(
1413 Tag(0x0012, 0x0020).cmp(&Tag(0x0010, 0x0024)),
1414 Ordering::Greater
1415 );
1416 assert_eq!(
1417 Tag(0x0012, 0x0020).cmp(&Tag(0x0010, 0x0010)),
1418 Ordering::Greater
1419 );
1420 assert_eq!(
1421 Tag(0x0012, 0x0020).cmp(&Tag(0x0012, 0x0010)),
1422 Ordering::Greater
1423 );
1424 }
1425
1426 #[test]
1427 fn get_date_value() {
1428 let data_element: DataElement<_, _> = DataElement::new(
1429 Tag(0x0010, 0x0030),
1430 VR::DA,
1431 Value::new(PrimitiveValue::from("19941012")),
1432 );
1433
1434 assert_eq!(
1435 data_element.to_date().unwrap(),
1436 DicomDate::from_ymd(1994, 10, 12).unwrap(),
1437 );
1438 }
1439
1440 #[test]
1441 fn create_data_element_from_primitive() {
1442 let data_element: DataElement<EmptyObject, [u8; 0]> = DataElement::new(
1443 Tag(0x0028, 0x3002),
1444 VR::US,
1445 crate::dicom_value!(U16, [256, 0, 16]),
1446 );
1447
1448 assert_eq!(data_element.uint16_slice().unwrap(), &[256, 0, 16]);
1449 }
1450
1451 #[test]
1452 fn parse_tag() {
1453 // without parens nor comma separator
1454 let tag: Tag = "00280004".parse().unwrap();
1455 assert_eq!(tag, Tag(0x0028, 0x0004));
1456 // lowercase
1457 let tag: Tag = "7fe00001".parse().unwrap();
1458 assert_eq!(tag, Tag(0x7FE0, 0x0001));
1459 // uppercase
1460 let tag: Tag = "7FE00001".parse().unwrap();
1461 assert_eq!(tag, Tag(0x7FE0, 0x0001));
1462
1463 // with parens, lowercase
1464 let tag: Tag = "(7fe0,0010)".parse().unwrap();
1465 assert_eq!(tag, Tag(0x7FE0, 0x0010));
1466 let tag: Tag = "(003a,001a)".parse().unwrap();
1467 assert_eq!(tag, Tag(0x003A, 0x001A));
1468
1469 // with parens, uppercase
1470 let tag: Tag = "(7FE0,0010)".parse().unwrap();
1471 assert_eq!(tag, Tag(0x7FE0, 0x0010));
1472 let tag: Tag = "(003A,001A)".parse().unwrap();
1473 assert_eq!(tag, Tag(0x003A, 0x001A));
1474
1475 // with parens, mixed case
1476 let tag: Tag = "(003a,001A)".parse().unwrap();
1477 assert_eq!(tag, Tag(0x003A, 0x001A));
1478
1479 // without parens
1480 let tag: Tag = "7fe0,0010".parse().unwrap();
1481 assert_eq!(tag, Tag(0x7FE0, 0x0010));
1482 let tag: Tag = "003a,001a".parse().unwrap();
1483 assert_eq!(tag, Tag(0x003A, 0x001A));
1484
1485 // error case: unsupported number forms
1486 let r: Result<Tag, _> = "+03a,0001".parse();
1487 assert_eq!(r, Err(ParseTagError::Number));
1488 // error case: bad start
1489 let r: Result<Tag, _> = "[baad,0123)".parse();
1490 assert_eq!(r, Err(ParseTagError::Start));
1491 // error case: bad end
1492 let r: Result<Tag, _> = "(baad,0123]".parse();
1493 assert_eq!(r, Err(ParseTagError::End));
1494 // error case: not enough characters
1495 let r: Result<Tag, _> = "(3a,1a)".parse();
1496 assert_eq!(r, Err(ParseTagError::Length));
1497 // error case: bad characters
1498 let r: Result<Tag, _> = "g00d,baad".parse();
1499 assert_eq!(r, Err(ParseTagError::Number));
1500 // error case: missing comma
1501 let r: Result<Tag, _> = "(baad&0123)".parse();
1502 assert_eq!(r, Err(ParseTagError::Separator));
1503 // error case: comma in the wrong place
1504 let r: Result<Tag, _> = "123,45678".parse();
1505 assert_eq!(r, Err(ParseTagError::Number));
1506 // error case: comma in the wrong place
1507 let r: Result<Tag, _> = "abcde,f01".parse();
1508 assert_eq!(r, Err(ParseTagError::Separator));
1509 // error case: comma instead of hex digit
1510 let r: Result<Tag, _> = "1234567,".parse();
1511 assert_eq!(r, Err(ParseTagError::Number));
1512 }
1513
1514 #[test]
1515 fn test_update_value() {
1516 // can update a string value
1517 let mut e: DataElement<EmptyObject, InMemFragment> =
1518 DataElement::new(Tag(0x0010, 0x0010), VR::PN, "Doe^John");
1519 assert_eq!(e.length(), Length(8));
1520 e.update_value(|e| {
1521 *e = "Smith^John".into();
1522 });
1523 assert_eq!(e.length(), Length(10));
1524
1525 // can update a pixel sequence
1526 let mut e: DataElement<EmptyObject, InMemFragment> = DataElement::new_with_len(
1527 Tag(0x7FE0, 0x0010),
1528 VR::OB,
1529 Length(0),
1530 PixelFragmentSequence::new_fragments(vec![]),
1531 );
1532 assert_eq!(e.length(), Length(0));
1533
1534 e.update_value(|v| {
1535 let fragments = v.fragments_mut().unwrap();
1536 fragments.push(vec![0x00; 256]);
1537 fragments.push(vec![0x55; 256]);
1538 fragments.push(vec![0xCC; 256]);
1539 });
1540
1541 assert!(e.length().is_undefined());
1542 assert_eq!(e.fragments().map(|f| f.len()), Some(3));
1543 }
1544}