51952137b7b657d123d9394413388f6340f65642
[pspp] / rust / src / endian.rs
1 #[derive(Copy, Clone, Debug)]
2 /// The endianness for integer and floating-point numbers in SPSS system files.
3 ///
4 /// SPSS system files can declare IBM 370 and DEC VAX floating-point
5 /// representations, but no file that uses either of these has ever been found
6 /// in the wild, so this code does not handle them.
7 pub enum Endian {
8     /// Big-endian: MSB at lowest address.
9     Big,
10
11     /// Little-endian: LSB at lowest address.
12     Little,
13 }
14
15 impl Endian {
16     pub fn identify_u32(expected_value: u32, bytes: [u8; 4]) -> Option<Self> {
17         let as_big: u32 = Endian::Big.parse(bytes);
18         let as_little: u32 = Endian::Little.parse(bytes);
19         match (as_big == expected_value, as_little == expected_value) {
20             (true, false) => Some(Endian::Big),
21             (false, true) => Some(Endian::Little),
22             _ => None
23         }
24     }
25
26     pub fn identify_f64(expected_value: f64, bytes: [u8; 8]) -> Option<Self> {
27         let as_big: f64 = Endian::Big.parse(bytes);
28         let as_little: f64 = Endian::Little.parse(bytes);
29         match (as_big == expected_value, as_little == expected_value) {
30             (true, false) => Some(Endian::Big),
31             (false, true) => Some(Endian::Little),
32             _ => None
33         }
34     }
35 }
36
37 /// Parses an `N`-byte slice in one of the supported formats into native format
38 /// as type `T`.
39 pub trait Parse<T, const N: usize> {
40     /// Given 'bytes', returns `T`.
41     fn parse(self, bytes: [u8; N]) -> T;
42 }
43 impl Parse<u64, 8> for Endian {
44     fn parse(self, bytes: [u8; 8]) -> u64 {
45         match self {
46             Endian::Big => u64::from_be_bytes(bytes),
47             Endian::Little => u64::from_le_bytes(bytes),
48         }
49     }
50 }
51 impl Parse<u32, 4> for Endian {
52     fn parse(self, bytes: [u8; 4]) -> u32 {
53         match self {
54             Endian::Big => u32::from_be_bytes(bytes),
55             Endian::Little => u32::from_le_bytes(bytes),
56         }
57     }
58 }
59 impl Parse<u16, 2> for Endian {
60     fn parse(self, bytes: [u8; 2]) -> u16 {
61         match self {
62             Endian::Big => u16::from_be_bytes(bytes),
63             Endian::Little => u16::from_le_bytes(bytes),
64         }
65     }
66 }
67 impl Parse<u8, 1> for Endian {
68     fn parse(self, bytes: [u8; 1]) -> u8 {
69         match self {
70             Endian::Big => u8::from_be_bytes(bytes),
71             Endian::Little => u8::from_le_bytes(bytes),
72         }
73     }
74 }
75 impl Parse<i64, 8> for Endian {
76     fn parse(self, bytes: [u8; 8]) -> i64 {
77         match self {
78             Endian::Big => i64::from_be_bytes(bytes),
79             Endian::Little => i64::from_le_bytes(bytes),
80         }
81     }
82 }
83 impl Parse<i32, 4> for Endian {
84     fn parse(self, bytes: [u8; 4]) -> i32 {
85         match self {
86             Endian::Big => i32::from_be_bytes(bytes),
87             Endian::Little => i32::from_le_bytes(bytes),
88         }
89     }
90 }
91 impl Parse<i16, 2> for Endian {
92     fn parse(self, bytes: [u8; 2]) -> i16 {
93         match self {
94             Endian::Big => i16::from_be_bytes(bytes),
95             Endian::Little => i16::from_le_bytes(bytes),
96         }
97     }
98 }
99 impl Parse<i8, 1> for Endian {
100     fn parse(self, bytes: [u8; 1]) -> i8 {
101         match self {
102             Endian::Big => i8::from_be_bytes(bytes),
103             Endian::Little => i8::from_le_bytes(bytes),
104         }
105     }
106 }
107 impl Parse<f64, 8> for Endian {
108     fn parse(self, bytes: [u8; 8]) -> f64 {
109         match self {
110             Endian::Big => f64::from_be_bytes(bytes),
111             Endian::Little => f64::from_le_bytes(bytes),
112         }
113     }
114 }
115