dicom_json/ser/
value.rs

1//! DICOM value serialization
2
3use dicom_core::PrimitiveValue;
4use serde::ser::SerializeSeq;
5use serde::Serialize;
6
7use crate::{INFINITY, NAN, NEG_INFINITY};
8
9/// Wrapper type for [primitive values][1]
10/// which should always be encoded as strings.
11///
12/// Should be used for the value representations
13/// AE, AS, AT, CS, DA, DT, LO, LT, SH, ST, TM, UC, UI, UR, and UT.
14/// Can also be used for the value representations
15/// DS, IS, SV, and UV.
16///
17/// [1]: dicom_core::PrimitiveValue
18#[derive(Debug, Clone)]
19pub struct AsStrings<'a>(&'a PrimitiveValue);
20
21impl<'a> From<&'a PrimitiveValue> for AsStrings<'a> {
22    fn from(value: &'a PrimitiveValue) -> Self {
23        AsStrings(value)
24    }
25}
26
27impl Serialize for AsStrings<'_> {
28    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
29    where
30        S: serde::Serializer,
31    {
32        let strings = self.0.to_multi_str();
33        serializer.collect_seq(&*strings)
34    }
35}
36
37/// Wrapper type for [primitive values][1]
38/// which should preferably be encoded as numbers,
39/// unless the value is already a string,
40/// or if serialization would result in precision loss.
41///
42/// Should be used for the value representations
43/// DS, FL, FD, IS, SL, SS, SV, UL, US, and UV.
44///
45/// [1]: dicom_core::PrimitiveValue
46#[derive(Debug, Clone)]
47pub struct AsNumbers<'a>(&'a PrimitiveValue);
48
49impl<'a> From<&'a PrimitiveValue> for AsNumbers<'a> {
50    fn from(value: &'a PrimitiveValue) -> Self {
51        AsNumbers(value)
52    }
53}
54
55impl Serialize for AsNumbers<'_> {
56    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
57    where
58        S: serde::Serializer,
59    {
60        match self.0 {
61            // empty
62            PrimitiveValue::Empty => serializer.serialize_seq(Some(0))?.end(),
63            // not numeric nor stringly
64            PrimitiveValue::Date(_) => panic!("wrong impl: cannot encode Date as numbers"),
65            PrimitiveValue::DateTime(_) => panic!("wrong impl: cannot encode DateTime as numbers"),
66            PrimitiveValue::Time(_) => panic!("wrong impl: cannot encode Time as numbers"),
67            PrimitiveValue::Tags(_) => panic!("wrong impl: cannot encode Tags as numbers"),
68            // strings
69            PrimitiveValue::Strs(strings) => serializer.collect_seq(strings),
70            PrimitiveValue::Str(string) => serializer.collect_seq([string]),
71            // no risk of precision loss
72            PrimitiveValue::U8(numbers) => serializer.collect_seq(numbers),
73            PrimitiveValue::I16(numbers) => serializer.collect_seq(numbers),
74            PrimitiveValue::U16(numbers) => serializer.collect_seq(numbers),
75            PrimitiveValue::I32(numbers) => serializer.collect_seq(numbers),
76            PrimitiveValue::U32(numbers) => serializer.collect_seq(numbers),
77            // possible precision loss
78            PrimitiveValue::I64(numbers) => {
79                let mut ser = serializer.serialize_seq(None)?;
80                for number in numbers {
81                    let narrowed: Option<i32> = num_traits::NumCast::from(*number);
82                    if let Some(narrowed) = narrowed {
83                        ser.serialize_element(&narrowed)?;
84                    } else {
85                        ser.serialize_element(&number.to_string())?;
86                    }
87                }
88                ser.end()
89            }
90            PrimitiveValue::U64(numbers) => {
91                let mut ser = serializer.serialize_seq(None)?;
92                for number in numbers {
93                    let narrowed: Option<i32> = num_traits::NumCast::from(*number);
94                    if let Some(narrowed) = narrowed {
95                        ser.serialize_element(&narrowed)?;
96                    } else {
97                        ser.serialize_element(&number.to_string())?;
98                    }
99                }
100                ser.end()
101            }
102            // floating point
103            PrimitiveValue::F32(numbers) => {
104                let mut ser = serializer.serialize_seq(None)?;
105                for number in numbers {
106                    if number.is_finite() {
107                        ser.serialize_element(&number)?;
108                    } else if number.is_nan() {
109                        ser.serialize_element(NAN)?;
110                    } else if number.is_infinite() && number.is_sign_positive() {
111                        ser.serialize_element(INFINITY)?;
112                    } else if number.is_infinite() && number.is_sign_negative() {
113                        ser.serialize_element(NEG_INFINITY)?;
114                    } else {
115                        ser.serialize_element(&Option::<()>::None)?;
116                    }
117                }
118                ser.end()
119            }
120            PrimitiveValue::F64(numbers) => {
121                let mut ser = serializer.serialize_seq(None)?;
122                for number in numbers {
123                    if number.is_finite() {
124                        ser.serialize_element(&number)?;
125                    } else if number.is_nan() {
126                        ser.serialize_element(NAN)?;
127                    } else if number.is_infinite() && number.is_sign_positive() {
128                        ser.serialize_element(INFINITY)?;
129                    } else if number.is_infinite() && number.is_sign_negative() {
130                        ser.serialize_element(NEG_INFINITY)?;
131                    } else {
132                        ser.serialize_element(&Option::<()>::None)?;
133                    }
134                }
135                ser.end()
136            }
137        }
138    }
139}
140
141/// Wrapper type for primitive binary values
142/// which should be encoded as base64 inline strings.
143///
144/// Should be used for the value representations
145/// OB, OW, OL, OF, OD, OV, and UN.
146#[derive(Debug, Clone)]
147pub struct InlineBinary<'a>(&'a PrimitiveValue);
148
149impl<'a> From<&'a PrimitiveValue> for InlineBinary<'a> {
150    fn from(value: &'a PrimitiveValue) -> Self {
151        InlineBinary(value)
152    }
153}
154
155impl Serialize for InlineBinary<'_> {
156    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
157    where
158        S: serde::Serializer,
159    {
160        let value = self.0.to_bytes();
161        use base64::Engine;
162        let str = base64::engine::general_purpose::STANDARD.encode(value);
163        serializer.serialize_str(&str)
164    }
165}
166
167/// Wrapper type for [primitive values][1]
168/// which should always be encoded as person names.
169///
170/// Should only used for the value representation PN.
171///
172/// [1]: dicom_core::PrimitiveValue
173#[derive(Debug, Clone)]
174pub struct AsPersonNames<'a>(&'a PrimitiveValue);
175
176impl<'a> From<&'a PrimitiveValue> for AsPersonNames<'a> {
177    fn from(value: &'a PrimitiveValue) -> Self {
178        AsPersonNames(value)
179    }
180}
181
182impl Serialize for AsPersonNames<'_> {
183    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
184    where
185        S: serde::Serializer,
186    {
187        let strings = self.0.to_multi_str();
188        serializer.collect_seq(strings.iter().map(|p| PersonNameDef::from(p.as_str())))
189    }
190}
191
192/// Wrapper type for a string
193/// to be interpreted as a person's name.
194///
195/// Should only used for the value representation PN.
196#[derive(Debug, Clone, Serialize)]
197pub struct PersonNameDef<'a> {
198    #[serde(rename = "Alphabetic")]
199    alphabetic: &'a str,
200}
201
202impl<'a> From<&'a str> for PersonNameDef<'a> {
203    fn from(value: &'a str) -> Self {
204        PersonNameDef { alphabetic: value }
205    }
206}
207
208#[cfg(test)]
209mod tests {
210    use dicom_core::dicom_value;
211    use dicom_core::value::DicomDate;
212    use pretty_assertions::assert_eq;
213    use serde_json::json;
214    use serde_json::Value;
215
216    use super::*;
217
218    #[test]
219    fn serialize_primitive_value_as_strings() {
220        let v = PrimitiveValue::from("Test Hospital");
221        let json = serde_json::to_value(AsStrings(&v)).unwrap();
222        assert_eq!(
223            json,
224            Value::Array(vec![Value::String("Test Hospital".to_string())]),
225        );
226
227        let v = PrimitiveValue::Empty;
228        let json = serde_json::to_value(AsStrings(&v)).unwrap();
229        assert_eq!(json, json!([]));
230
231        let v = dicom_value!(U16, [20, 40, 60]);
232        let json = serde_json::to_value(AsStrings(&v)).unwrap();
233        assert_eq!(
234            json,
235            Value::Array(vec![
236                Value::from("20"),
237                Value::from("40"),
238                Value::from("60"),
239            ]),
240        );
241
242        let v = dicom_value!(Date, [DicomDate::from_ymd(2023, 6, 13).unwrap()]);
243        let json = serde_json::to_value(AsStrings(&v)).unwrap();
244        assert_eq!(json, Value::Array(vec![Value::from("20230613")]));
245    }
246
247    #[test]
248    fn serialize_primitive_value_as_numbers() {
249        let v = PrimitiveValue::from(23.5_f64);
250        let json = serde_json::to_value(AsNumbers(&v)).unwrap();
251        assert_eq!(json, json!([23.5]),);
252
253        let v = PrimitiveValue::from([f64::NAN, f64::INFINITY, f64::NEG_INFINITY]);
254        let json = serde_json::to_value(AsNumbers(&v)).unwrap();
255        assert_eq!(json, json!(["NaN", "inf", "-inf"]),);
256
257        let v = PrimitiveValue::from([f32::NAN, f32::INFINITY, f32::NEG_INFINITY]);
258        let json = serde_json::to_value(AsNumbers(&v)).unwrap();
259        assert_eq!(json, json!(["NaN", "inf", "-inf"]),);
260
261        let v = PrimitiveValue::Empty;
262        let json = serde_json::to_value(AsNumbers(&v)).unwrap();
263        assert_eq!(json, json!([]));
264
265        let v = PrimitiveValue::from("5");
266        let json = serde_json::to_value(AsNumbers(&v)).unwrap();
267        assert_eq!(json, json!(["5"]),);
268
269        let v = dicom_value!(U16, [20, 40, 60]);
270        let json = serde_json::to_value(AsNumbers(&v)).unwrap();
271        assert_eq!(json, json!([20, 40, 60]));
272
273        // too large for a 32-bit integer
274        let v = dicom_value!(U64, [876543245678]);
275        let json = serde_json::to_value(AsNumbers(&v)).unwrap();
276        assert_eq!(json, json!(["876543245678"]),);
277    }
278}