hff_core/identifier/
mod.rs

1use crate::{Ecc, Error, Result};
2use std::ops::{Deref, DerefMut};
3use uuid::Uuid;
4
5/// Identifier type as specified in the hff header.
6/// This has no impact on behavior at all, it is only a
7/// hint to the end user about how to use/view the ID's.
8#[repr(u32)]
9#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
10pub enum IdType {
11    /// A simple u128.
12    Id = 0,
13    /// Dual eight character codes.
14    Ecc2 = 1,
15    /// A UUID.
16    Uuid = 2,
17    /// An array of u8.
18    Au8 = 3,
19    /// An eight character code and a u64.
20    EccU64 = 4,
21    /// Two u64's.
22    U64s = 5,
23}
24
25impl Deref for IdType {
26    type Target = u32;
27
28    fn deref(&self) -> &Self::Target {
29        match self {
30            Self::Id => &0,
31            Self::Ecc2 => &1,
32            Self::Uuid => &2,
33            Self::Au8 => &3,
34            Self::EccU64 => &4,
35            Self::U64s => &5,
36        }
37    }
38}
39
40impl From<u32> for IdType {
41    fn from(value: u32) -> Self {
42        match value {
43            0 => Self::Id,
44            1 => Self::Ecc2,
45            2 => Self::Uuid,
46            3 => Self::Au8,
47            4 => Self::EccU64,
48            5 => Self::U64s,
49            _ => panic!("Invalid identifier type in header."),
50        }
51    }
52}
53
54/// An identifier for the tables and chunks.
55#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
56pub struct Identifier(u128);
57
58impl Identifier {
59    /// An invalid identifier.
60    pub const INVALID: Self = Self(0);
61
62    /// Create a new instance.
63    pub fn new(id: u128) -> Self {
64        Self(id)
65    }
66
67    /// Create a string from the identifier formatted to the given type.
68    pub fn to_string(&self, id_type: IdType) -> String {
69        match id_type {
70            IdType::Id => format!("{:X}", self.0),
71            IdType::Ecc2 => {
72                let (p, s): (Ecc, Ecc) = (*self).into();
73                format!("{}:{}", p.to_string(), s.to_string())
74            }
75            IdType::Uuid => {
76                let id: Uuid = (*self).into();
77                format!("{}", id.to_string())
78            }
79            IdType::Au8 => {
80                let chars: [u8; 16] = (*self).into();
81                format!("{:?}", chars)
82            }
83            IdType::EccU64 => {
84                let (ecc, value): (Ecc, u64) = (*self).into();
85                format!("{}:{:X}", ecc.to_string(), value)
86            }
87            IdType::U64s => {
88                let (l, r): (u64, u64) = (*self).into();
89                format!("{:X}:{:X}", l, r)
90            }
91        }
92    }
93
94    // Conversions back to specific identifier types.
95
96    /// Convert to a pair of u64's.
97    pub fn as_u64s(self) -> (u64, u64) {
98        ((self.0 >> 64) as u64, self.0 as u64)
99    }
100
101    /// Convert to dual ecc's.
102    pub fn as_ecc2(self) -> (Ecc, Ecc) {
103        let (l, r) = self.as_u64s();
104        (l.into(), r.into())
105    }
106
107    /// Convert to an Uuid.
108    pub fn as_uuid(self) -> Uuid {
109        Uuid::from_u128(self.0)
110    }
111
112    /// Convert to an array of u8.
113    pub fn as_au8(self) -> [u8; 16] {
114        #[cfg(target_endian = "little")]
115        {
116            self.0.to_le_bytes()
117        }
118
119        #[cfg(target_endian = "big")]
120        {
121            self.0.to_be_bytes()
122        }
123    }
124
125    /// Convert to an Ecc and u64.
126    pub fn as_eccu64(self) -> (Ecc, u64) {
127        let (ecc, value) = self.as_u64s();
128        (Ecc::from(ecc), value)
129    }
130}
131
132impl Deref for Identifier {
133    type Target = u128;
134
135    fn deref(&self) -> &Self::Target {
136        &self.0
137    }
138}
139
140impl DerefMut for Identifier {
141    fn deref_mut(&mut self) -> &mut Self::Target {
142        &mut self.0
143    }
144}
145
146impl Into<u128> for Identifier {
147    fn into(self) -> u128 {
148        self.0
149    }
150}
151
152impl Into<(Ecc, Ecc)> for Identifier {
153    fn into(self) -> (Ecc, Ecc) {
154        self.as_ecc2()
155    }
156}
157
158impl Into<Uuid> for Identifier {
159    fn into(self) -> Uuid {
160        self.as_uuid()
161    }
162}
163
164impl Into<[u8; 16]> for Identifier {
165    fn into(self) -> [u8; 16] {
166        self.as_au8()
167    }
168}
169
170impl Into<(Ecc, u64)> for Identifier {
171    fn into(self) -> (Ecc, u64) {
172        self.as_eccu64()
173    }
174}
175
176impl Into<(u64, u64)> for Identifier {
177    fn into(self) -> (u64, u64) {
178        self.as_u64s()
179    }
180}
181
182// Several infallible conversions first.
183
184// For IdType::Id
185impl From<u128> for Identifier {
186    fn from(value: u128) -> Self {
187        Self(value)
188    }
189}
190
191// For IdType::Ecc2
192impl From<(Ecc, Ecc)> for Identifier {
193    fn from(value: (Ecc, Ecc)) -> Self {
194        let primary: u64 = *value.0;
195        let secondary: u64 = *value.1;
196        let value = (primary as u128) << 64 | (secondary as u128);
197        Self(value)
198    }
199}
200
201// For IdType::Uuid
202impl From<Uuid> for Identifier {
203    fn from(value: Uuid) -> Self {
204        Self(value.as_u128())
205    }
206}
207
208// For IdType::Scc
209impl From<[u8; 16]> for Identifier {
210    fn from(value: [u8; 16]) -> Self {
211        #[cfg(target_endian = "little")]
212        let value = u128::from_le_bytes(value);
213        #[cfg(target_endian = "big")]
214        let value = u128::from_be_bytes(value);
215
216        Self(value)
217    }
218}
219
220// For IdType::EccU64
221impl From<(Ecc, u64)> for Identifier {
222    fn from(value: (Ecc, u64)) -> Self {
223        let ecc: u64 = *value.0;
224        let value = (ecc as u128) << 64 | (value.1 as u128);
225        Self(value)
226    }
227}
228
229// For IdType::U64s
230impl From<(u64, u64)> for Identifier {
231    fn from(value: (u64, u64)) -> Self {
232        let value = (value.0 as u128) << 64 | (value.1 as u128);
233        Self(value)
234    }
235}
236
237impl TryFrom<(&str, &str)> for Identifier {
238    type Error = Error;
239
240    fn try_from(value: (&str, &str)) -> Result<Self> {
241        let primary: Ecc = value.0.try_into()?;
242        let secondary: Ecc = value.1.try_into()?;
243        Ok((primary, secondary).try_into()?)
244    }
245}
246
247impl TryFrom<(&str, u64)> for Identifier {
248    type Error = Error;
249
250    fn try_from(value: (&str, u64)) -> Result<Self> {
251        let ecc: Ecc = value.0.try_into()?;
252        Ok((ecc, value.1).try_into()?)
253    }
254}
255
256#[cfg(test)]
257mod tests {
258    use super::*;
259
260    #[test]
261    fn test_ecc2() {
262        let identifier: Identifier = (123, 456).try_into().unwrap();
263        let (_123, _456) = identifier.as_u64s();
264        assert_eq!(_123, 123);
265        assert_eq!(_456, 456);
266    }
267}