1use crate::tags::ENTRIES;
4use dicom_core::dictionary::{DataDictionary, DataDictionaryEntryRef, TagRange::*, VirtualVr};
5use dicom_core::header::Tag;
6use dicom_core::VR;
7use once_cell::sync::Lazy;
8use std::collections::{HashMap, HashSet};
9use std::fmt;
10use std::fmt::{Display, Formatter};
11
12static DICT: Lazy<StandardDataDictionaryRegistry> = Lazy::new(init_dictionary);
13
14#[inline]
21pub fn registry() -> &'static StandardDataDictionaryRegistry {
22 &DICT
23}
24
25#[derive(Debug)]
30pub struct StandardDataDictionaryRegistry {
31 by_name: HashMap<&'static str, &'static DataDictionaryEntryRef<'static>>,
33 by_tag: HashMap<Tag, &'static DataDictionaryEntryRef<'static>>,
35 repeating_ggxx: HashSet<Tag>,
37 repeating_eexx: HashSet<Tag>,
39}
40
41impl StandardDataDictionaryRegistry {
42 fn new() -> StandardDataDictionaryRegistry {
43 StandardDataDictionaryRegistry {
44 by_name: HashMap::with_capacity(5000),
45 by_tag: HashMap::with_capacity(5000),
46 repeating_ggxx: HashSet::with_capacity(75),
47 repeating_eexx: HashSet::new(),
48 }
49 }
50
51 fn index(&mut self, entry: &'static DataDictionaryEntryRef<'static>) -> &mut Self {
53 self.by_name.insert(entry.alias, entry);
54 self.by_tag.insert(entry.tag.inner(), entry);
55 match entry.tag {
56 Group100(tag) => {
57 self.repeating_ggxx.insert(tag);
58 }
59 Element100(tag) => {
60 self.repeating_eexx.insert(tag);
61 }
62 _ => {}
63 }
64 self
65 }
66}
67
68static GROUP_LENGTH_ENTRY: DataDictionaryEntryRef<'static> = DataDictionaryEntryRef {
70 tag: GroupLength,
71 alias: "GenericGroupLength",
72 vr: VirtualVr::Exact(VR::UL),
73};
74
75static PRIVATE_CREATOR_ENTRY: DataDictionaryEntryRef<'static> = DataDictionaryEntryRef {
77 tag: PrivateCreator,
78 alias: "PrivateCreator",
79 vr: VirtualVr::Exact(VR::LO),
80};
81
82#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
91pub struct StandardDataDictionary;
92
93impl StandardDataDictionary {
94 fn indexed_tag(tag: Tag) -> Option<&'static DataDictionaryEntryRef<'static>> {
95 let r = registry();
96
97 r.by_tag
98 .get(&tag)
99 .or_else(|| {
100 let group_trimmed = Tag(tag.0 & 0xFF00, tag.1);
102 if r.repeating_ggxx.contains(&group_trimmed) {
103 return r.by_tag.get(&group_trimmed);
104 }
105 let elem_trimmed = Tag(tag.0, tag.1 & 0xFF00);
107 if r.repeating_eexx.contains(&elem_trimmed) {
108 return r.by_tag.get(&elem_trimmed);
109 }
110
111 None
112 })
113 .cloned()
114 .or_else(|| {
115 if tag.0 & 1 == 1 && (0x0010..=0x00FF).contains(&tag.1) {
117 return Some(&PRIVATE_CREATOR_ENTRY);
118 }
119 if tag.element() == 0x0000 {
121 return Some(&GROUP_LENGTH_ENTRY);
122 }
123
124 None
125 })
126 }
127}
128
129impl DataDictionary for StandardDataDictionary {
130 type Entry = DataDictionaryEntryRef<'static>;
131
132 fn by_name(&self, name: &str) -> Option<&Self::Entry> {
133 registry().by_name.get(name).cloned()
134 }
135
136 fn by_tag(&self, tag: Tag) -> Option<&Self::Entry> {
137 StandardDataDictionary::indexed_tag(tag)
138 }
139}
140
141impl<'a> DataDictionary for &'a StandardDataDictionary {
142 type Entry = DataDictionaryEntryRef<'static>;
143
144 fn by_name(&self, name: &str) -> Option<&'static DataDictionaryEntryRef<'static>> {
145 registry().by_name.get(name).cloned()
146 }
147
148 fn by_tag(&self, tag: Tag) -> Option<&'static DataDictionaryEntryRef<'static>> {
149 StandardDataDictionary::indexed_tag(tag)
150 }
151}
152
153impl Display for StandardDataDictionary {
154 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
155 f.write_str("Standard DICOM Data Dictionary")
156 }
157}
158
159fn init_dictionary() -> StandardDataDictionaryRegistry {
160 let mut d = StandardDataDictionaryRegistry::new();
161 for entry in ENTRIES {
162 d.index(entry);
163 }
164 d.by_name.insert("GenericGroupLength", &GROUP_LENGTH_ENTRY);
167 d
168}
169
170#[cfg(test)]
171mod tests {
172 use crate::tags;
173
174 use super::StandardDataDictionary;
175 use dicom_core::dictionary::{DataDictionary, DataDictionaryEntryRef, TagRange::*, VirtualVr};
176 use dicom_core::header::{Tag, VR};
177 use dicom_core::ops::AttributeSelector;
178
179 #[test]
182 fn smoke_test() {
183 let dict = StandardDataDictionary::default();
184
185 assert_eq!(
186 dict.by_name("PatientName"),
187 Some(&DataDictionaryEntryRef {
188 tag: Single(Tag(0x0010, 0x0010)),
189 alias: "PatientName",
190 vr: VR::PN.into(),
191 })
192 );
193
194 assert_eq!(
195 dict.by_name("Modality"),
196 Some(&DataDictionaryEntryRef {
197 tag: Single(Tag(0x0008, 0x0060)),
198 alias: "Modality",
199 vr: VR::CS.into(),
200 })
201 );
202
203 let pixel_data = dict
204 .by_tag(Tag(0x7FE0, 0x0010))
205 .expect("Pixel Data attribute should exist");
206 eprintln!("{:X?}", pixel_data.tag);
207 assert_eq!(pixel_data.tag, Single(Tag(0x7FE0, 0x0010)));
208 assert_eq!(pixel_data.alias, "PixelData");
209 assert!(pixel_data.vr == VirtualVr::Px);
210
211 let overlay_data = dict
212 .by_tag(Tag(0x6000, 0x3000))
213 .expect("Overlay Data attribute should exist");
214 assert_eq!(overlay_data.tag, Group100(Tag(0x6000, 0x3000)));
215 assert_eq!(overlay_data.alias, "OverlayData");
216 assert!(overlay_data.vr == VirtualVr::Ox);
217
218 let overlay_data = dict
220 .by_tag(Tag(0x60EE, 0x3000))
221 .expect("Repeated Overlay Data attribute should exist");
222 assert_eq!(overlay_data.tag, Group100(Tag(0x6000, 0x3000)));
223 assert_eq!(overlay_data.alias, "OverlayData");
224 assert!(overlay_data.vr == VirtualVr::Ox);
225 }
226
227 #[test]
228 fn can_parse_tags() {
229 let dict = StandardDataDictionary;
230
231 assert_eq!(dict.parse_tag("(7FE0,0010)"), Some(crate::tags::PIXEL_DATA));
232 assert_eq!(dict.parse_tag("0010,21C0"), Some(Tag(0x0010, 0x21C0)));
233 assert_eq!(
234 dict.parse_tag("OperatorsName"),
235 Some(crate::tags::OPERATORS_NAME)
236 );
237
238 assert_eq!(dict.parse_tag(""), None);
240 assert_eq!(dict.parse_tag("1111,2222,3333"), None);
241 assert_eq!(dict.parse_tag("OperatorNickname"), None);
242 }
243
244 #[test]
245 fn can_query_by_expression() {
246 let dict = StandardDataDictionary;
247
248 assert_eq!(
249 dict.by_expr("(0010,0010)"),
250 Some(&DataDictionaryEntryRef {
251 tag: Single(crate::tags::PATIENT_NAME),
252 alias: "PatientName",
253 vr: VR::PN.into(),
254 })
255 );
256
257 assert_eq!(
258 dict.by_expr("0008,0060"),
259 Some(&DataDictionaryEntryRef {
260 tag: Single(crate::tags::MODALITY),
261 alias: "Modality",
262 vr: VR::CS.into(),
263 })
264 );
265
266 assert_eq!(
267 dict.by_expr("OperatorsName"),
268 Some(&DataDictionaryEntryRef {
269 tag: Single(crate::tags::OPERATORS_NAME),
270 alias: "OperatorsName",
271 vr: VR::PN.into(),
272 })
273 );
274
275 assert_eq!(dict.parse_tag("0080 0010"), None);
277 assert_eq!(dict.parse_tag("(0000.0600)"), None);
278 assert_eq!(dict.parse_tag("OPERATORSNAME"), None);
279 }
280
281 #[test]
282 fn has_group_length_tags() {
283 use crate::tags::*;
284 assert_eq!(COMMAND_GROUP_LENGTH, Tag(0x0000, 0x0000));
285 assert_eq!(FILE_META_INFORMATION_GROUP_LENGTH, Tag(0x0002, 0x0000));
286
287 let dict = StandardDataDictionary::default();
288
289 assert_eq!(
290 dict.by_tag(FILE_META_INFORMATION_GROUP_LENGTH),
291 Some(&DataDictionaryEntryRef {
292 tag: Single(FILE_META_INFORMATION_GROUP_LENGTH),
293 alias: "FileMetaInformationGroupLength",
294 vr: VR::UL.into(),
295 }),
296 );
297
298 assert_eq!(
299 dict.by_tag(COMMAND_GROUP_LENGTH),
300 Some(&DataDictionaryEntryRef {
301 tag: Single(COMMAND_GROUP_LENGTH),
302 alias: "CommandGroupLength",
303 vr: VR::UL.into(),
304 }),
305 );
306
307 assert_eq!(
310 dict.by_tag(Tag(0x7FE0, 0x0000)),
311 Some(&DataDictionaryEntryRef {
312 tag: GroupLength,
313 alias: "GenericGroupLength",
314 vr: VR::UL.into(),
315 }),
316 );
317
318 assert_eq!(
319 dict.by_name("GenericGroupLength"),
320 Some(&DataDictionaryEntryRef {
321 tag: GroupLength,
322 alias: "GenericGroupLength",
323 vr: VR::UL.into(),
324 }),
325 );
326 }
327
328 #[test]
329 fn has_private_creator() {
330 let dict = StandardDataDictionary::default();
331
332 let private_creator = DataDictionaryEntryRef {
333 tag: PrivateCreator,
334 alias: "PrivateCreator",
335 vr: VR::LO.into(),
336 };
337
338 assert_eq!(dict.by_tag(Tag(0x0009, 0x0010)), Some(&private_creator));
339 assert_eq!(dict.by_tag(Tag(0x0009, 0x0011)), Some(&private_creator));
340 assert_eq!(dict.by_tag(Tag(0x000B, 0x0010)), Some(&private_creator));
341 assert_eq!(dict.by_tag(Tag(0x00ED, 0x00FF)), Some(&private_creator));
342 }
343
344 #[test]
345 fn can_parse_selectors() {
346 let dict = StandardDataDictionary;
347 let selector: AttributeSelector = dict.parse_selector("(0002,0010)").unwrap();
350 assert_eq!(selector, AttributeSelector::from(tags::TRANSFER_SYNTAX_UID));
351
352 let selector: AttributeSelector = dict.parse_selector("00101010").unwrap();
355 assert_eq!(selector, AttributeSelector::from(tags::PATIENT_AGE));
356
357 let selector: AttributeSelector = dict.parse_selector("0040A168[0].CodeValue").unwrap();
360 assert_eq!(
361 selector,
362 AttributeSelector::from((tags::CONCEPT_CODE_SEQUENCE, 0, tags::CODE_VALUE)),
363 );
364 let selector: AttributeSelector =
367 dict.parse_selector("0040,A730[1].ContentSequence").unwrap();
368 assert_eq!(
369 selector,
370 AttributeSelector::from((tags::CONTENT_SEQUENCE, 1, tags::CONTENT_SEQUENCE,)),
371 );
372
373 let selector: AttributeSelector = dict
376 .parse_selector("SequenceOfUltrasoundRegions.RegionSpatialFormat")
377 .unwrap();
378 assert_eq!(
379 selector,
380 AttributeSelector::from((
381 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
382 0,
383 tags::REGION_SPATIAL_FORMAT
384 )),
385 );
386 }
387
388 #[test]
390 fn print_and_parse_selectors() {
391 let selectors = [
392 AttributeSelector::from((tags::CONTENT_SEQUENCE, 1, tags::CONTENT_SEQUENCE)),
393 AttributeSelector::new([
394 (tags::CONTENT_SEQUENCE, 1).into(),
395 (tags::CONTENT_SEQUENCE, 3).into(),
396 (tags::CONTENT_SEQUENCE, 5).into(),
397 (tags::CONCEPT_NAME_CODE_SEQUENCE, 0).into(),
398 tags::CODE_VALUE.into(),
399 ])
400 .unwrap(),
401 ];
402
403 for selector in selectors {
404 let selector2: AttributeSelector = StandardDataDictionary
405 .parse_selector(&selector.to_string())
406 .unwrap();
407 assert_eq!(selector, selector2);
408 }
409 }
410}