1use crate::Endian;
2use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt};
3use std::{
4 fmt::Debug,
5 io::{Error, Read, Write},
6 ops::{Deref, DerefMut},
7};
8
9#[repr(C)]
11#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
12pub struct Ecc(
13 u64,
15);
16
17impl Debug for Ecc {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 write!(f, "Ecc(\"{}\")", self.to_string())
20 }
21}
22
23impl Default for Ecc {
24 fn default() -> Self {
25 Self::INVALID
26 }
27}
28
29impl Ecc {
30 pub const SIZE: usize = std::mem::size_of::<Self>();
32 pub const INVALID: Ecc = Self(0);
34 pub const HFF_MAGIC: Ecc = Self::new("HFF-2023");
36
37 pub const fn new(name: &str) -> Self {
42 let bytes = name.as_bytes();
43 let count = bytes.len();
44
45 if count == 0 || count > 8 {
46 panic!("Invalid ECC string.");
47 }
48
49 union BytesU64 {
52 value: u64,
53 bytes: [u8; 8],
54 }
55
56 let mut converter = BytesU64 { value: 0 };
57 unsafe {
58 converter.bytes[0] = bytes[0];
59 converter.bytes[1] = if count > 1 { bytes[1] } else { 0 };
60 converter.bytes[2] = if count > 2 { bytes[2] } else { 0 };
61 converter.bytes[3] = if count > 3 { bytes[3] } else { 0 };
62 converter.bytes[4] = if count > 4 { bytes[4] } else { 0 };
63 converter.bytes[5] = if count > 5 { bytes[5] } else { 0 };
64 converter.bytes[6] = if count > 6 { bytes[6] } else { 0 };
65 converter.bytes[7] = if count > 7 { bytes[7] } else { 0 };
66 }
67
68 Self(unsafe { converter.value })
69 }
70
71 pub fn is_valid(&self) -> bool {
73 *self != Self::INVALID
74 }
75
76 pub fn endian(&self, rhs: Self) -> Option<Endian> {
81 if rhs.swap_bytes() == rhs {
82 panic!("Does not work for symetric ID's.")
83 }
84 if self.0 == rhs.0 {
85 Some(crate::NATIVE_ENDIAN)
86 } else if self.0 == rhs.0.swap_bytes() {
87 Some(crate::OPPOSING_ENDIAN)
88 } else {
89 None
90 }
91 }
92
93 pub const fn swap_bytes(&self) -> Self {
95 Self(self.0.swap_bytes())
96 }
97
98 pub const fn as_slice(&self) -> &[u8] {
100 unsafe { std::slice::from_raw_parts((&self.0 as *const u64) as *const u8, 8) }
101 }
102
103 pub fn as_slice_mut(&mut self) -> &mut [u8] {
105 unsafe { std::slice::from_raw_parts_mut((&mut self.0 as *mut u64) as *mut u8, 8) }
106 }
107
108 pub fn read<E: ByteOrder>(reader: &mut dyn Read) -> Result<Self, Error> {
110 Ok(Self(reader.read_u64::<E>()?))
111 }
112
113 pub fn write<E: ByteOrder>(self, writer: &mut dyn Write) -> Result<(), Error> {
115 writer.write_u64::<E>(self.0)?;
116 Ok(())
117 }
118}
119
120impl Deref for Ecc {
121 type Target = u64;
122
123 fn deref(&self) -> &Self::Target {
124 &self.0
125 }
126}
127
128impl DerefMut for Ecc {
129 fn deref_mut(&mut self) -> &mut Self::Target {
130 &mut self.0
131 }
132}
133
134impl TryFrom<String> for Ecc {
135 type Error = crate::Error;
136
137 fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
138 let bytes = value.as_bytes();
139 let count = bytes.len();
140
141 if count > 0 && count < 9 {
142 Ok(Ecc::new(value.as_str()))
143 } else {
144 Err(crate::Error::InvalidEcc(value))
145 }
146 }
147}
148
149impl From<&str> for Ecc {
150 fn from(value: &str) -> Self {
151 Ecc::new(value)
152 }
153}
154
155impl From<u64> for Ecc {
156 fn from(value: u64) -> Self {
157 Self(value)
158 }
159}
160
161impl From<[u8; 8]> for Ecc {
162 fn from(value: [u8; 8]) -> Self {
163 unsafe { Self(*(value.as_ptr() as *const u64)) }
164 }
165}
166
167impl ToString for Ecc {
168 fn to_string(&self) -> String {
169 let mut name = String::with_capacity(8);
170 let code = self.as_slice();
171 if self.is_valid() {
172 for i in 0..8 {
173 if code[i].is_ascii() {
174 if code[i] == 0 {
175 break;
176 } else {
177 name.push(code[i] as char);
178 }
179 } else {
180 name = format!("{}", self.0);
181 break;
182 }
183 }
184 } else {
185 name = "INVALID".into();
186 }
187 name
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194
195 #[test]
196 fn test_layout() {
197 assert_eq!(std::mem::size_of::<Ecc>(), 8);
199 }
200
201 #[test]
202 fn test_construction() {
203 for i in 1..=8 {
204 let id = (0..i).into_iter().map(|_| 'x').collect::<String>();
206 let code = Ecc::new(&id);
207 assert_eq!(code.to_string(), id);
208
209 let bytes = code.as_slice();
211 for j in i..8 {
212 assert_eq!(bytes[j], 0);
213 }
214 }
215 }
216
217 #[test]
218 fn test_serialization_le() {
219 let mut buffer = vec![];
220 let ecc = Ecc::new("test");
221 assert!(ecc.write::<crate::LE>(&mut buffer).is_ok());
222
223 let result = Ecc::read::<crate::LE>(&mut buffer.as_slice()).unwrap();
224 assert_eq!(ecc, result);
225 assert_eq!(result.to_string(), "test");
226 }
227
228 #[test]
229 fn test_serialization_be() {
230 let mut buffer = vec![];
231 let ecc = Ecc::new("test");
232 assert!(ecc.write::<crate::BE>(&mut buffer).is_ok());
233
234 let result = Ecc::read::<crate::BE>(&mut buffer.as_slice()).unwrap();
235 assert_eq!(ecc, result);
236 assert_eq!(result.to_string(), "test");
237 }
238
239 #[test]
240 fn test_endianness() {
241 assert_eq!(
242 Ecc::HFF_MAGIC.endian(Ecc::HFF_MAGIC),
243 Some(crate::NATIVE_ENDIAN)
244 );
245 assert_eq!(
246 Ecc::from(Ecc::HFF_MAGIC.0.swap_bytes()).endian(Ecc::HFF_MAGIC),
247 Some(crate::OPPOSING_ENDIAN)
248 );
249 }
250}