1use std::{marker::PhantomData, str::FromStr};
4
5use crate::DicomJson;
6use dicom_core::{
7 value::{InMemFragment, Value, C},
8 DataDictionary, DataElement, PrimitiveValue, Tag, VR,
9};
10use dicom_object::InMemDicomObject;
11use serde::de::{Deserialize, DeserializeOwned, Error as _, Visitor};
12
13use self::value::{BulkDataUri, DicomJsonPerson, NumberOrText};
14
15mod value;
16
17pub fn from_str<'a, T>(string: &'a str) -> Result<T, serde_json::Error>
19where
20 DicomJson<T>: Deserialize<'a>,
21{
22 serde_json::from_str::<DicomJson<T>>(string).map(DicomJson::into_inner)
23}
24
25pub fn from_slice<'a, T>(slice: &'a [u8]) -> Result<T, serde_json::Error>
27where
28 DicomJson<T>: Deserialize<'a>,
29{
30 serde_json::from_slice::<DicomJson<T>>(slice).map(DicomJson::into_inner)
31}
32
33pub fn from_reader<R, T>(reader: R) -> Result<T, serde_json::Error>
35where
36 R: std::io::Read,
37 DicomJson<T>: DeserializeOwned,
38{
39 serde_json::from_reader::<_, DicomJson<T>>(reader).map(DicomJson::into_inner)
40}
41
42pub fn from_value<T>(value: serde_json::Value) -> Result<T, serde_json::Error>
44where
45 DicomJson<T>: DeserializeOwned,
46{
47 serde_json::from_value::<DicomJson<T>>(value).map(DicomJson::into_inner)
48}
49
50#[derive(Debug)]
51struct InMemDicomObjectVisitor<D>(PhantomData<D>);
52
53impl<D> Default for InMemDicomObjectVisitor<D> {
54 fn default() -> Self {
55 Self(PhantomData)
56 }
57}
58
59impl<'de, D> Visitor<'de> for InMemDicomObjectVisitor<D>
60where
61 D: Default + DataDictionary + Clone,
62{
63 type Value = InMemDicomObject<D>;
64
65 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
66 formatter.write_str("a DICOM data set map")
67 }
68
69 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
70 where
71 A: serde::de::MapAccess<'de>,
72 {
73 let mut obj = InMemDicomObject::<D>::new_empty_with_dict(D::default());
74 while let Some(e) = map.next_entry::<DicomJson<Tag>, JsonDataElement<D>>()? {
75 let (
76 DicomJson(tag),
77 JsonDataElement {
78 vr,
79 value,
80 bulk_data_uri,
81 },
82 ) = e;
83 if bulk_data_uri.is_some() {
84 tracing::warn!(
85 "bulk data URI is not supported for InMemDicomObject; skipping {}",
86 tag
87 );
88 } else {
89 obj.put(DataElement::new(tag, vr, value));
90 }
91 }
92 Ok(obj)
93 }
94}
95
96impl<'de, I> Deserialize<'de> for DicomJson<InMemDicomObject<I>>
97where
98 I: Default + Clone + DataDictionary,
99{
100 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
101 where
102 D: serde::Deserializer<'de>,
103 {
104 deserializer
105 .deserialize_map(InMemDicomObjectVisitor::default())
106 .map(DicomJson::from)
107 }
108}
109
110#[derive(Debug)]
111struct JsonDataElement<D> {
112 vr: VR,
113 value: Value<InMemDicomObject<D>, InMemFragment>,
114 bulk_data_uri: Option<BulkDataUri>,
118}
119
120#[derive(Debug)]
121struct DataElementVisitor<D>(PhantomData<D>);
122
123impl<D> Default for DataElementVisitor<D> {
124 fn default() -> Self {
125 Self(PhantomData)
126 }
127}
128
129impl<'de, D> Visitor<'de> for DataElementVisitor<D>
130where
131 D: Default + Clone + DataDictionary,
132{
133 type Value = JsonDataElement<D>;
134
135 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
136 formatter.write_str("a data element object")
137 }
138
139 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
140 where
141 A: serde::de::MapAccess<'de>,
142 {
143 let mut values: Option<_> = None;
144 let mut vr = None;
145 let mut value: Option<serde_json::Value> = None;
146 let mut inline_binary = None;
147 let mut bulk_data_uri = None;
148
149 while let Some(key) = map.next_key::<String>()? {
150 match &*key {
151 "vr" => {
152 if vr.is_some() {
153 return Err(A::Error::custom("\"vr\" should only be set once"));
154 }
155
156 let val: String = map.next_value()?;
157 vr = Some(VR::from_str(&val).unwrap_or(VR::UN));
158 }
159 "Value" => {
160 if inline_binary.is_some() {
161 return Err(A::Error::custom(
162 "\"Value\" conflicts with \"InlineBinary\"",
163 ));
164 }
165
166 if bulk_data_uri.is_some() {
167 return Err(A::Error::custom("\"Value\" conflicts with \"BulkDataURI\""));
168 }
169
170 value = Some(map.next_value()?);
171 }
172 "InlineBinary" => {
173 if values.is_some() {
174 return Err(A::Error::custom(
175 "\"InlineBinary\" conflicts with \"Value\"",
176 ));
177 }
178
179 if bulk_data_uri.is_some() {
180 return Err(A::Error::custom(
181 "\"InlineBinary\" conflicts with \"BulkDataURI\"",
182 ));
183 }
184 let val: String = map.next_value()?;
186 inline_binary = Some(val);
187 }
188 "BulkDataURI" => {
189 if values.is_some() {
190 return Err(A::Error::custom("\"BulkDataURI\" conflicts with \"Value\""));
191 }
192
193 if inline_binary.is_some() {
194 return Err(A::Error::custom(
195 "\"BulkDataURI\" conflicts with \"InlineBinary\"",
196 ));
197 }
198
199 let val: BulkDataUri = map.next_value()?;
201 bulk_data_uri = Some(val);
202 }
203 _ => {
204 return Err(A::Error::custom("Unrecognized data element field"));
205 }
206 }
207 }
208
209 let Some(vr) = vr else {
211 return Err(A::Error::custom("missing VR field"));
212 };
213
214 if let Some(value) = value {
215 match vr {
218 VR::SQ => {
220 let items: Vec<DicomJson<InMemDicomObject<D>>> =
221 serde_json::from_value(value).map_err(A::Error::custom)?;
222 let items: Vec<_> = items.into_iter().map(DicomJson::into_inner).collect();
223 values = Some(Value::Sequence(items.into()));
224 }
225 VR::AE
227 | VR::AS
228 | VR::CS
229 | VR::DA
230 | VR::DT
231 | VR::LO
232 | VR::LT
233 | VR::SH
234 | VR::ST
235 | VR::UT
236 | VR::UR
237 | VR::TM
238 | VR::UC
239 | VR::UI => {
240 let items: Vec<Option<String>> =
241 serde_json::from_value(value).map_err(A::Error::custom)?;
242 let items: Vec<String> =
243 items.into_iter().map(|v| v.unwrap_or_default()).collect();
244 values = Some(PrimitiveValue::Strs(items.into()).into());
245 }
246
247 VR::SS => {
249 let items: Vec<i16> =
250 serde_json::from_value(value).map_err(A::Error::custom)?;
251 values = Some(PrimitiveValue::I16(items.into()).into());
252 }
253 VR::US | VR::OW => {
255 let items: Vec<u16> =
256 serde_json::from_value(value).map_err(A::Error::custom)?;
257 values = Some(PrimitiveValue::U16(items.into()).into());
258 }
259 VR::SL => {
261 let items: Vec<i32> =
262 serde_json::from_value(value).map_err(A::Error::custom)?;
263 values = Some(PrimitiveValue::I32(items.into()).into());
264 }
265 VR::OB => {
266 let items: Vec<u8> = serde_json::from_value(value).map_err(A::Error::custom)?;
267 values = Some(PrimitiveValue::U8(items.into()).into());
268 }
269 VR::FL | VR::OF => {
272 let items: Vec<NumberOrText<f32>> =
273 serde_json::from_value(value).map_err(A::Error::custom)?;
274 let items: C<f32> = items
275 .into_iter()
276 .map(|v| v.to_num())
277 .collect::<Result<C<f32>, _>>()
278 .map_err(A::Error::custom)?;
279 values = Some(PrimitiveValue::F32(items).into());
280 }
281 VR::FD | VR::OD => {
282 let items: Vec<NumberOrText<f64>> =
283 serde_json::from_value(value).map_err(A::Error::custom)?;
284 let items: C<f64> = items
285 .into_iter()
286 .map(|v| v.to_num())
287 .collect::<Result<C<f64>, _>>()
288 .map_err(A::Error::custom)?;
289 values = Some(PrimitiveValue::F64(items).into());
290 }
291 VR::SV => {
292 let items: Vec<NumberOrText<i64>> =
293 serde_json::from_value(value).map_err(A::Error::custom)?;
294 let items: C<i64> = items
295 .into_iter()
296 .map(|v| v.to_num())
297 .collect::<Result<C<i64>, _>>()
298 .map_err(A::Error::custom)?;
299 values = Some(PrimitiveValue::I64(items).into());
300 }
301 VR::UL | VR::OL => {
302 let items: Vec<NumberOrText<u32>> =
303 serde_json::from_value(value).map_err(A::Error::custom)?;
304 let items: C<u32> = items
305 .into_iter()
306 .map(|v| v.to_num())
307 .collect::<Result<C<u32>, _>>()
308 .map_err(A::Error::custom)?;
309 values = Some(PrimitiveValue::U32(items).into());
310 }
311 VR::UV | VR::OV => {
312 let items: Vec<NumberOrText<u64>> =
313 serde_json::from_value(value).map_err(A::Error::custom)?;
314 let items: C<u64> = items
315 .into_iter()
316 .map(|v| v.to_num())
317 .collect::<Result<C<u64>, _>>()
318 .map_err(A::Error::custom)?;
319 values = Some(PrimitiveValue::U64(items).into());
320 }
321 VR::DS => {
324 let items: Vec<NumberOrText<f64>> =
325 serde_json::from_value(value).map_err(A::Error::custom)?;
326 let items: C<String> = items.into_iter().map(|v| v.to_string()).collect();
327 values = Some(PrimitiveValue::Strs(items).into());
328 }
329 VR::IS => {
330 let items: Vec<NumberOrText<f64>> =
331 serde_json::from_value(value).map_err(A::Error::custom)?;
332 let items: C<String> = items.into_iter().map(|v| v.to_string()).collect();
333 values = Some(PrimitiveValue::Strs(items).into());
334 }
335 VR::PN => {
337 let items: Vec<DicomJsonPerson> =
338 serde_json::from_value(value).map_err(A::Error::custom)?;
339 let items: C<String> = items.into_iter().map(|v| v.to_string()).collect();
340 values = Some(PrimitiveValue::Strs(items).into());
341 }
342 VR::AT => {
344 let items: Vec<DicomJson<Tag>> =
345 serde_json::from_value(value).map_err(A::Error::custom)?;
346 let items: C<Tag> = items.into_iter().map(DicomJson::into_inner).collect();
347 values = Some(PrimitiveValue::Tags(items).into());
348 }
349 VR::UN => return Err(A::Error::custom("can't parse JSON Value in UN")),
351 }
352 }
353
354 let value = match (values, inline_binary) {
355 (None, None) => PrimitiveValue::Empty.into(),
356 (None, Some(inline_binary)) => {
357 use base64::Engine;
359 let data = base64::engine::general_purpose::STANDARD
360 .decode(inline_binary)
361 .map_err(|_| A::Error::custom("inline binary data is not valid base64"))?;
362 PrimitiveValue::from(data).into()
363 }
364 (Some(values), None) => values,
365 _ => unreachable!(),
366 };
367
368 Ok(JsonDataElement {
369 vr,
370 value,
371 bulk_data_uri,
372 })
373 }
374}
375
376impl<'de, I> Deserialize<'de> for JsonDataElement<I>
377where
378 I: Default + Clone + DataDictionary,
379{
380 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
381 where
382 D: serde::Deserializer<'de>,
383 {
384 deserializer.deserialize_struct(
385 "DataElement",
386 &["vr", "Value", "InlineData", "BulkDataURI"],
387 DataElementVisitor(PhantomData),
388 )
389 }
390}
391
392#[derive(Debug)]
393struct TagVisitor;
394
395impl Visitor<'_> for TagVisitor {
396 type Value = Tag;
397
398 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
399 formatter.write_str("a DICOM tag string in the form \"GGGGEEEE\"")
400 }
401
402 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
403 where
404 E: serde::de::Error,
405 {
406 v.parse().map_err(E::custom)
407 }
408}
409
410impl<'de> Deserialize<'de> for DicomJson<Tag> {
411 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
412 where
413 D: serde::Deserializer<'de>,
414 {
415 deserializer.deserialize_str(TagVisitor).map(DicomJson)
416 }
417}
418
419#[cfg(test)]
420mod tests {
421 use super::from_str;
422 use dicom_core::{dicom_value, DataElement, Tag, VR};
423 use dicom_object::InMemDicomObject;
424 use num_traits::Float;
425
426 fn assert_float_slice_eq<T: Float>(actual: &[T], expected: &[T]) {
429 assert_eq!(actual.len(), expected.len());
430 assert!(actual
431 .iter()
432 .zip(actual.iter())
433 .all(|(&a, &b)| (a == b) || (a.is_nan() && b.is_nan())));
434 }
435
436 #[test]
437 fn can_parse_tags() {
438 let serialized = "\"00080010\"";
439 let tag: Tag = from_str(serialized).unwrap();
440 assert_eq!(tag, Tag(0x0008, 0x0010));
441
442 let serialized = "\"00200013\"";
443 let tag: Tag = from_str(serialized).unwrap();
444 assert_eq!(tag, Tag(0x0020, 0x0013));
445 }
446
447 #[test]
448 fn can_parse_simple_data_sets() {
449 let serialized = serde_json::json!({
450 "00080005": {
451 "Value": [ "ISO_IR 192" ],
452 "vr": "CS"
453 },
454 "00080020": {
455 "vr": "DA",
456 "Value": [ "20130409" ]
457 },
458 "00080061": {
459 "vr": "CS",
460 "Value": [
461 "CT",
462 "PET"
463 ]
464 },
465 "00080090": {
466 "vr": "PN",
467 "Value": [
468 {
469 "Alphabetic": "^Bob^^Dr."
470 }
471 ]
472 },
473 "00091002": {
474 "vr": "UN",
475 "InlineBinary": "z0x9c8v7"
476 },
477 "00101010": {
478 "vr": "AS",
479 "Value": [ "30Y" ]
480 }
481 });
482
483 let obj: InMemDicomObject = super::from_value(serialized).unwrap();
484
485 let tag = Tag(0x0008, 0x0005);
486 assert_eq!(
487 obj.get(tag),
488 Some(&DataElement::new(tag, VR::CS, "ISO_IR 192")),
489 )
490 }
491
492 #[test]
493 fn can_parse_null_values() {
494 let serialized = serde_json::json!({
495 "00080008": {
496 "Value": [
497 "DERIVED",
498 "PRIMARY",
499 "POST_PROCESSED",
500 "RT",
501 null,
502 null,
503 null,
504 null,
505 "100000"
506 ],
507 "vr": "CS"
508 }
509 });
510
511 let obj: InMemDicomObject = super::from_value(serialized).unwrap();
512
513 let tag = Tag(0x0008, 0x0008);
514 assert_eq!(
515 obj.get(tag),
516 Some(&DataElement::new(
517 tag,
518 VR::CS,
519 dicom_value!(
520 Strs,
521 [
522 "DERIVED",
523 "PRIMARY",
524 "POST_PROCESSED",
525 "RT",
526 "",
527 "",
528 "",
529 "",
530 "100000",
531 ]
532 )
533 )),
534 )
535 }
536
537 #[test]
538 fn can_resolve_bulk_data() {
539 let serialized = serde_json::json!({
540 "7FE00010": {
541 "vr": "OW",
542 "BulkDataURI": "http://localhost:8042/dicom-web/studies/1.2.276.0.89.300.10035584652.20181014.93645/series/1.2.392.200036.9125.3.1696751121028.64888163108.42362060/instances/1.2.392.200036.9125.9.0.454007928.539582480.1883970570/bulk/7fe00010"
543 }
544 });
545
546 assert!(super::from_value::<InMemDicomObject>(serialized).is_ok());
547 }
548
549 #[test]
550 fn can_resolve_nan_and_inf_float() {
551 let serialized = serde_json::json!({
552 "0018605A": {
553 "vr": "FL",
554 "Value": [
555 5492.8545,
556 5462.5205,
557 "NaN",
558 "-inf",
559 "inf"
560 ]
561 }
562 });
563
564 let obj: InMemDicomObject = super::from_value(serialized).unwrap();
565 let tag = Tag(0x0018, 0x605A);
566 let element = obj.get(tag).unwrap();
567
568 let actual_values = element.float32_slice().unwrap();
570 let expected_values = &[
571 5492.8545,
572 5462.5205,
573 f32::NAN,
574 f32::NEG_INFINITY,
575 f32::INFINITY,
576 ];
577
578 assert_float_slice_eq(actual_values, expected_values);
579
580 let actual_values_multifloat_64 = element.to_multi_float64().unwrap();
582 let expected_values_multifloat_64 = &[
583 5492.8544921875,
584 5462.5205078125,
585 f64::NAN,
586 f64::NEG_INFINITY,
587 f64::INFINITY,
588 ];
589
590 assert_float_slice_eq(&actual_values_multifloat_64, expected_values_multifloat_64);
591 }
592}