1 /// The endianness for integer and floating-point numbers in SPSS system files.
3 /// SPSS system files can declare IBM 370 and DEC VAX floating-point
4 /// representations, but no file that uses either of these has ever been found
5 /// in the wild, so this code does not handle them.
6 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
8 /// Big-endian: MSB at lowest address.
11 /// Little-endian: LSB at lowest address.
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),
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),
37 pub trait ToBytes<T, const N: usize> {
38 fn to_bytes(self, value: T) -> [u8; N];
40 impl ToBytes<i64, 8> for Endian {
41 fn to_bytes(self, value: i64) -> [u8; 8] {
43 Endian::Big => i64::to_be_bytes(value),
44 Endian::Little => i64::to_le_bytes(value),
48 impl ToBytes<u32, 4> for Endian {
49 fn to_bytes(self, value: u32) -> [u8; 4] {
51 Endian::Big => u32::to_be_bytes(value),
52 Endian::Little => u32::to_le_bytes(value),
56 impl ToBytes<i32, 4> for Endian {
57 fn to_bytes(self, value: i32) -> [u8; 4] {
59 Endian::Big => i32::to_be_bytes(value),
60 Endian::Little => i32::to_le_bytes(value),
64 impl ToBytes<u16, 2> for Endian {
65 fn to_bytes(self, value: u16) -> [u8; 2] {
67 Endian::Big => u16::to_be_bytes(value),
68 Endian::Little => u16::to_le_bytes(value),
72 impl ToBytes<u8, 1> for Endian {
73 fn to_bytes(self, value: u8) -> [u8; 1] {
77 impl ToBytes<f64, 8> for Endian {
78 fn to_bytes(self, value: f64) -> [u8; 8] {
80 Endian::Big => f64::to_be_bytes(value),
81 Endian::Little => f64::to_le_bytes(value),
86 /// Parses an `N`-byte slice in one of the supported formats into native format
88 pub trait Parse<T, const N: usize> {
89 /// Given 'bytes', returns `T`.
90 fn parse(self, bytes: [u8; N]) -> T;
92 impl Parse<u64, 8> for Endian {
93 fn parse(self, bytes: [u8; 8]) -> u64 {
95 Endian::Big => u64::from_be_bytes(bytes),
96 Endian::Little => u64::from_le_bytes(bytes),
100 impl Parse<u32, 4> for Endian {
101 fn parse(self, bytes: [u8; 4]) -> u32 {
103 Endian::Big => u32::from_be_bytes(bytes),
104 Endian::Little => u32::from_le_bytes(bytes),
108 impl Parse<u16, 2> for Endian {
109 fn parse(self, bytes: [u8; 2]) -> u16 {
111 Endian::Big => u16::from_be_bytes(bytes),
112 Endian::Little => u16::from_le_bytes(bytes),
116 impl Parse<u8, 1> for Endian {
117 fn parse(self, bytes: [u8; 1]) -> u8 {
119 Endian::Big => u8::from_be_bytes(bytes),
120 Endian::Little => u8::from_le_bytes(bytes),
124 impl Parse<i64, 8> for Endian {
125 fn parse(self, bytes: [u8; 8]) -> i64 {
127 Endian::Big => i64::from_be_bytes(bytes),
128 Endian::Little => i64::from_le_bytes(bytes),
132 impl Parse<i32, 4> for Endian {
133 fn parse(self, bytes: [u8; 4]) -> i32 {
135 Endian::Big => i32::from_be_bytes(bytes),
136 Endian::Little => i32::from_le_bytes(bytes),
140 impl Parse<i16, 2> for Endian {
141 fn parse(self, bytes: [u8; 2]) -> i16 {
143 Endian::Big => i16::from_be_bytes(bytes),
144 Endian::Little => i16::from_le_bytes(bytes),
148 impl Parse<i8, 1> for Endian {
149 fn parse(self, bytes: [u8; 1]) -> i8 {
151 Endian::Big => i8::from_be_bytes(bytes),
152 Endian::Little => i8::from_le_bytes(bytes),
156 impl Parse<f64, 8> for Endian {
157 fn parse(self, bytes: [u8; 8]) -> f64 {
159 Endian::Big => f64::from_be_bytes(bytes),
160 Endian::Little => f64::from_le_bytes(bytes),