dicom_core/
lib.rs

1#![crate_type = "lib"]
2#![deny(trivial_numeric_casts, unsafe_code, unstable_features)]
3#![warn(
4    missing_debug_implementations,
5    unused_qualifications,
6    unused_import_braces
7)]
8#![allow(clippy::derive_partial_eq_without_eq)]
9
10//! This is the core library of DICOM-rs containing various concepts,
11//! data structures and traits specific to DICOM content.
12//!
13//! The current structure of this crate is as follows:
14//!
15//! - [`header`] comprises various data types for DICOM element header,
16//!   including common definitions for DICOM tags and value representations.
17//! - [`dictionary`] describes common behavior of DICOM data dictionaries,
18//!   which translate attribute names and/or tags to a dictionary entry
19//!   containing relevant information about the attribute.
20//! - [`ops`] provides constructs for defining
21//!   operations on DICOM attributes,
22//!   to be applied on types resembling DICOM objects or data sets.
23//! - [`value`] holds definitions for values in standard DICOM elements,
24//!   with the awareness of multiplicity, representation,
25//!   and the possible presence of sequences.
26//!
27
28pub mod dictionary;
29pub mod header;
30pub mod ops;
31pub mod prelude;
32pub mod value;
33
34pub use dictionary::DataDictionary;
35pub use header::{DataElement, DataElementHeader, Length, Tag, VR};
36pub use value::{PrimitiveValue, Value as DicomValue};
37
38// re-export crates that are part of the public API
39pub use chrono;
40pub use smallvec;
41
42/// Helper macro for constructing a DICOM primitive value,
43/// of an arbitrary variant and multiplicity.
44///
45/// The base syntax is a value type identifier,
46/// which is one of the variants of [`PrimitiveValue`],
47/// followed by either an expression resolving to one standard Rust value,
48/// or an explicitly laid out array of Rust values.
49/// The type variant may be omitted in some cases.
50///
51/// Passing a single expression for multiple values is not supported.
52/// Please use standard `From` conversions instead.
53///
54/// ```none
55/// dicom_value!() // empty value
56/// dicom_value!(«Type», «expression») // one value
57/// dicom_value!(«Type», [«expression1», «expression2», ...]) // multiple values
58/// dicom_value!(«expression») // a single value, inferred variant
59/// ```
60///
61/// # Examples:
62///
63/// Strings are automatically converted to retain ownership.
64///
65/// ```
66/// use dicom_core::value::PrimitiveValue;
67/// use dicom_core::{DicomValue, dicom_value};
68///
69/// let value = dicom_value!(Str, "Smith^John");
70/// assert_eq!(
71///     value,
72///     PrimitiveValue::Str("Smith^John".to_owned()),
73/// );
74/// ```
75///
76/// A DICOM value may also have multiple elements:
77///
78/// ```
79/// # use dicom_core::value::PrimitiveValue;
80/// # use dicom_core::dicom_value;
81/// let value = dicom_value!(Strs, [
82///     "Smith^John",
83///     "Simões^João",
84/// ]);
85/// assert_eq!(
86///     value,
87///     PrimitiveValue::Strs([
88///         "Smith^John".to_string(),
89///         "Simões^João".to_string(),
90///     ][..].into()),
91/// );
92/// let value = dicom_value!(U16, [5, 6, 7]);
93/// assert_eq!(
94///     value,
95///     PrimitiveValue::U16([5, 6, 7][..].into()),
96/// );
97/// ```
98///
99/// The output is a [`PrimitiveValue`],
100/// which can be converted to a `DicomValue` as long as its type parameters
101/// are specified or inferable.
102///
103/// ```
104/// # use dicom_core::header::EmptyObject;
105/// # use dicom_core::value::PrimitiveValue;
106/// # use dicom_core::{DicomValue, dicom_value};
107/// # let value = dicom_value!(U16, [5, 6, 7]);
108/// // conversion to a DicomValue only requires its type parameters
109/// // to be specified or inferable.
110/// assert_eq!(
111///     DicomValue::from(value),
112///     DicomValue::<EmptyObject, ()>::Primitive(
113///         PrimitiveValue::U16([5, 6, 7][..].into())),
114/// );
115/// ```
116///
117/// [`PrimitiveValue`]: ./enum.PrimitiveValue.html
118#[macro_export]
119macro_rules! dicom_value {
120    // Empty value
121    () => { $crate::value::PrimitiveValue::Empty };
122    // Multiple strings
123    (Strs, [ $($elem: expr),+ , ]) => {
124        $crate::value::PrimitiveValue :: Strs ($crate::smallvec::smallvec![$($elem.to_owned(),)*])
125    };
126    (Strs, [ $($elem: expr),+ ]) => {
127        $crate::value::PrimitiveValue :: Strs ($crate::smallvec::smallvec![$($elem.to_owned(),)*])
128    };
129    ($typ: ident, [ $($elem: expr),+ , ]) => {
130        $crate::value::PrimitiveValue :: $typ ($crate::smallvec::smallvec![$($elem,)*])
131    };
132    ($typ: ident, [ $($elem: expr),+ ]) => {
133        $crate::value::PrimitiveValue :: $typ ($crate::smallvec::smallvec![$($elem,)*])
134    };
135    (Str, $elem: expr) => {
136        $crate::value::PrimitiveValue :: Str (String::from($elem))
137    };
138    ($typ: ident, $elem: expr) => {
139        $crate::value::PrimitiveValue :: $typ ($crate::value::C::from_elem($elem, 1))
140    };
141    ($elem: expr) => {
142        $crate::value::PrimitiveValue::from($elem)
143    };
144}
145
146#[cfg(test)]
147mod tests {
148    use crate::value::PrimitiveValue;
149    use smallvec::smallvec;
150
151    #[test]
152    fn macro_dicom_value() {
153        // single string with variant
154        assert_eq!(
155            dicom_value!(Str, "PALETTE COLOR "),
156            PrimitiveValue::Str("PALETTE COLOR ".to_owned()),
157        );
158
159        // single string without variant
160        assert_eq!(
161            dicom_value!("PALETTE COLOR "),
162            PrimitiveValue::Str("PALETTE COLOR ".to_owned()),
163        );
164
165        // multiple string literals with variant, no trailing comma
166        assert_eq!(
167            dicom_value!(Strs, ["BASE", "LIGHT", "DARK"]),
168            PrimitiveValue::Strs(smallvec![
169                "BASE".to_owned(),
170                "LIGHT".to_owned(),
171                "DARK".to_owned(),
172            ]),
173        );
174
175        // multiple strings and string slices with variant, no trailing comma
176        assert_eq!(
177            dicom_value!(
178                Strs,
179                [
180                    "DERIVED",
181                    "PRIMARY".to_string(), // accepts both &str and String
182                    "WHOLE BODY",
183                    "EMISSION"
184                ]
185            ),
186            PrimitiveValue::Strs(smallvec![
187                "DERIVED".to_string(),
188                "PRIMARY".to_string(),
189                "WHOLE BODY".to_string(),
190                "EMISSION".to_string(),
191            ]),
192        );
193
194        // multiple string literals with variant, with trailing comma
195        assert_eq!(
196            dicom_value!(Strs, ["DERIVED", "PRIMARY", "WHOLE BODY", "EMISSION",]),
197            PrimitiveValue::Strs(smallvec![
198                "DERIVED".to_string(),
199                "PRIMARY".to_string(),
200                "WHOLE BODY".to_string(),
201                "EMISSION".to_string(),
202            ]),
203        );
204
205        // single number with variant
206        assert_eq!(dicom_value!(U16, 55), PrimitiveValue::U16(smallvec![55]),);
207
208        // single number without variant
209        assert_eq!(dicom_value!(55_u32), PrimitiveValue::U32(smallvec![55]),);
210
211        // multiple numbers without variant, no trailing comma
212        assert_eq!(
213            dicom_value!(I32, [11, 22, 33]),
214            PrimitiveValue::I32(smallvec![11, 22, 33]),
215        );
216
217        // empty value
218        assert_eq!(dicom_value!(), PrimitiveValue::Empty,);
219    }
220}