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}