dicom_encoding/encode/
basic.rs

1//! This module provides implementations for basic encoders: little endian and big endian.
2//!
3
4use super::BasicEncode;
5use byteordered::{ByteOrdered, Endianness};
6use std::io::Write;
7
8type Result<T> = std::io::Result<T>;
9
10/// A basic encoder of primitive elements in little endian.
11#[derive(Debug, Default, Clone, PartialEq)]
12pub struct LittleEndianBasicEncoder;
13
14impl BasicEncode for LittleEndianBasicEncoder {
15    fn endianness(&self) -> Endianness {
16        Endianness::Little
17    }
18
19    fn encode_us<S>(&self, to: S, value: u16) -> Result<()>
20    where
21        S: Write,
22    {
23        ByteOrdered::le(to).write_u16(value)?;
24        Ok(())
25    }
26
27    fn encode_ul<S>(&self, to: S, value: u32) -> Result<()>
28    where
29        S: Write,
30    {
31        ByteOrdered::le(to).write_u32(value)?;
32        Ok(())
33    }
34
35    fn encode_uv<S>(&self, to: S, value: u64) -> Result<()>
36    where
37        S: Write,
38    {
39        ByteOrdered::le(to).write_u64(value)?;
40        Ok(())
41    }
42
43    fn encode_ss<S>(&self, to: S, value: i16) -> Result<()>
44    where
45        S: Write,
46    {
47        ByteOrdered::le(to).write_i16(value)?;
48        Ok(())
49    }
50
51    fn encode_sl<S>(&self, to: S, value: i32) -> Result<()>
52    where
53        S: Write,
54    {
55        ByteOrdered::le(to).write_i32(value)?;
56        Ok(())
57    }
58
59    fn encode_sv<S>(&self, to: S, value: i64) -> Result<()>
60    where
61        S: Write,
62    {
63        ByteOrdered::le(to).write_i64(value)?;
64        Ok(())
65    }
66
67    fn encode_fl<S>(&self, to: S, value: f32) -> Result<()>
68    where
69        S: Write,
70    {
71        ByteOrdered::le(to).write_f32(value)?;
72        Ok(())
73    }
74
75    fn encode_fd<S>(&self, to: S, value: f64) -> Result<()>
76    where
77        S: Write,
78    {
79        ByteOrdered::le(to).write_f64(value)?;
80        Ok(())
81    }
82}
83
84/// A basic encoder of DICOM primitive elements in big endian.
85#[derive(Debug, Default, Clone, PartialEq)]
86pub struct BigEndianBasicEncoder;
87
88impl BasicEncode for BigEndianBasicEncoder {
89    fn endianness(&self) -> Endianness {
90        Endianness::Big
91    }
92
93    fn encode_us<S>(&self, to: S, value: u16) -> Result<()>
94    where
95        S: Write,
96    {
97        ByteOrdered::be(to).write_u16(value)?;
98        Ok(())
99    }
100
101    fn encode_ul<S>(&self, to: S, value: u32) -> Result<()>
102    where
103        S: Write,
104    {
105        ByteOrdered::be(to).write_u32(value)?;
106        Ok(())
107    }
108
109    fn encode_uv<S>(&self, to: S, value: u64) -> Result<()>
110    where
111        S: Write,
112    {
113        ByteOrdered::be(to).write_u64(value)?;
114        Ok(())
115    }
116
117    fn encode_ss<S>(&self, to: S, value: i16) -> Result<()>
118    where
119        S: Write,
120    {
121        ByteOrdered::be(to).write_i16(value)?;
122        Ok(())
123    }
124
125    fn encode_sl<S>(&self, to: S, value: i32) -> Result<()>
126    where
127        S: Write,
128    {
129        ByteOrdered::be(to).write_i32(value)?;
130        Ok(())
131    }
132
133    fn encode_sv<S>(&self, to: S, value: i64) -> Result<()>
134    where
135        S: Write,
136    {
137        ByteOrdered::be(to).write_i64(value)?;
138        Ok(())
139    }
140
141    fn encode_fl<S>(&self, to: S, value: f32) -> Result<()>
142    where
143        S: Write,
144    {
145        ByteOrdered::be(to).write_f32(value)?;
146        Ok(())
147    }
148
149    fn encode_fd<S>(&self, to: S, value: f64) -> Result<()>
150    where
151        S: Write,
152    {
153        ByteOrdered::be(to).write_f64(value)?;
154        Ok(())
155    }
156}
157
158/// A basic encoder with support for both Little Endian an Big Endian
159/// encoding, decided at run-time. Since only two values are possible,
160/// this enum may become more practical and efficient than relying on trait objects.
161#[derive(Debug, Clone, PartialEq)]
162pub enum BasicEncoder {
163    /// Encode in Little Endian
164    LE(LittleEndianBasicEncoder),
165    /// Encode in Big Endian
166    BE(BigEndianBasicEncoder),
167}
168
169use self::BasicEncoder::{BE, LE};
170
171/// Handle multiple encoding tasks with the expected endianness. The parameter `$e`
172/// will either yield a `LittleEndianBasicEncoder` or a `BigEndianBasicEncoder`. When
173/// the specific basic encoder is still unknown in compile-time, this macro can be used
174/// to resolve the endianess only once.
175macro_rules! for_both {
176    ($endianness: expr, |$e: ident| $f: expr) => {
177        match *$endianness {
178            LE(ref $e) => $f,
179            BE(ref $e) => $f,
180        }
181    };
182}
183
184impl BasicEncode for BasicEncoder {
185    fn endianness(&self) -> Endianness {
186        match *self {
187            LE(_) => Endianness::Little,
188            BE(_) => Endianness::Big,
189        }
190    }
191
192    fn encode_us<S>(&self, to: S, value: u16) -> Result<()>
193    where
194        S: Write,
195    {
196        for_both!(self, |e| e.encode_us(to, value))
197    }
198
199    fn encode_ul<S>(&self, to: S, value: u32) -> Result<()>
200    where
201        S: Write,
202    {
203        for_both!(self, |e| e.encode_ul(to, value))
204    }
205
206    fn encode_uv<S>(&self, to: S, value: u64) -> Result<()>
207    where
208        S: Write,
209    {
210        for_both!(self, |e| e.encode_uv(to, value))
211    }
212
213    fn encode_ss<S>(&self, to: S, value: i16) -> Result<()>
214    where
215        S: Write,
216    {
217        for_both!(self, |e| e.encode_ss(to, value))
218    }
219
220    fn encode_sl<S>(&self, to: S, value: i32) -> Result<()>
221    where
222        S: Write,
223    {
224        for_both!(self, |e| e.encode_sl(to, value))
225    }
226
227    fn encode_sv<S>(&self, to: S, value: i64) -> Result<()>
228    where
229        S: Write,
230    {
231        for_both!(self, |e| e.encode_sv(to, value))
232    }
233
234    fn encode_fl<S>(&self, to: S, value: f32) -> Result<()>
235    where
236        S: Write,
237    {
238        for_both!(self, |e| e.encode_fl(to, value))
239    }
240
241    fn encode_fd<S>(&self, to: S, value: f64) -> Result<()>
242    where
243        S: Write,
244    {
245        for_both!(self, |e| e.encode_fd(to, value))
246    }
247}
248
249#[cfg(test)]
250mod tests {
251    use super::*;
252    use dicom_core::value::DicomDate;
253    use dicom_core::{PrimitiveValue, Tag};
254
255    fn test_one_primitive_be(value: PrimitiveValue, raw: &[u8]) {
256        let mut out = vec![];
257        BigEndianBasicEncoder
258            .encode_primitive(&mut out, &value)
259            .unwrap();
260        assert_eq!(&*out, raw);
261    }
262
263    fn test_one_primitive_le(value: PrimitiveValue, raw: &[u8]) {
264        let mut out = vec![];
265        LittleEndianBasicEncoder
266            .encode_primitive(&mut out, &value)
267            .unwrap();
268        assert_eq!(&*out, raw);
269    }
270
271    #[test]
272    fn test_basic_encode_le() {
273        test_one_primitive_le(PrimitiveValue::Empty, &[]);
274        test_one_primitive_le(
275            PrimitiveValue::I32(vec![0x01, 0x0200, 0x0300_FFCC].into()),
276            &[
277                0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xCC, 0xFF, 0x00, 0x03,
278            ],
279        );
280
281        test_one_primitive_le(
282            PrimitiveValue::Strs(
283                ["one", "more", "time"]
284                    .iter()
285                    .map(|s| s.to_string())
286                    .collect(),
287            ),
288            &*b"one\\more\\time",
289        );
290
291        test_one_primitive_le(
292            PrimitiveValue::Date(
293                vec![
294                    DicomDate::from_ymd(2016, 12, 01).unwrap(),
295                    DicomDate::from_ymd(2123, 9, 13).unwrap(),
296                ]
297                .into(),
298            ),
299            &*b"20161201\\21230913",
300        );
301
302        test_one_primitive_le(
303            PrimitiveValue::Tags(vec![Tag(0x0002, 0x0001), Tag(0xFA80, 0xBC12)].into()),
304            &[0x02, 0x00, 0x01, 0x00, 0x80, 0xFA, 0x12, 0xBC],
305        );
306    }
307
308    #[test]
309    fn test_basic_encode_be() {
310        test_one_primitive_be(PrimitiveValue::Empty, &[]);
311        test_one_primitive_be(
312            PrimitiveValue::I32(vec![0x01, 0x0200, 0x0300_FFCC].into()),
313            &[
314                0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0xFF, 0xCC,
315            ],
316        );
317
318        test_one_primitive_be(
319            PrimitiveValue::Strs(
320                ["one", "more", "time"]
321                    .iter()
322                    .map(|s| s.to_string())
323                    .collect(),
324            ),
325            &*b"one\\more\\time",
326        );
327
328        test_one_primitive_be(
329            PrimitiveValue::Date(
330                vec![
331                    DicomDate::from_ymd(2016, 12, 01).unwrap(),
332                    DicomDate::from_ym(2123, 9).unwrap(),
333                ]
334                .into(),
335            ),
336            &*b"20161201\\212309",
337        );
338
339        test_one_primitive_be(
340            PrimitiveValue::Tags(vec![Tag(0x0002, 0x0001), Tag(0xFA80, 0xBC12)].into()),
341            &[0x00, 0x02, 0x00, 0x01, 0xFA, 0x80, 0xBC, 0x12],
342        );
343    }
344}