1use serde::{
2 Deserialize,
3 Serialize,
4};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub struct RegistryKey([u8; Self::SIZE]);
11impl RegistryKey {
12 pub const DEFAULT_VALUE: Self = Self([u8::MAX; Self::SIZE]);
14 pub const MAX_WRITABLE: Self = Self([u8::MAX, u8::MAX, u8::MAX - 1]);
16 pub const SIZE: usize = 3;
18 pub const ZERO: Self = Self([0; Self::SIZE]);
20
21 pub fn as_u32(self) -> u32 {
23 u32::from_be_bytes([0, self.0[0], self.0[1], self.0[2]])
24 }
25
26 pub fn next(self) -> Self {
29 if self == Self::DEFAULT_VALUE {
30 panic!("Max/default value has no next key");
31 }
32 let next_raw = self.as_u32() + 1u32;
33 if next_raw == Self::DEFAULT_VALUE.as_u32() {
34 Self::ZERO
35 } else {
36 Self::try_from(next_raw)
37 .expect("The procedure above always produces a valid key")
38 }
39 }
40}
41
42impl TryFrom<u32> for RegistryKey {
43 type Error = &'static str;
44
45 fn try_from(value: u32) -> Result<Self, Self::Error> {
46 let v = value.to_be_bytes();
47 if v[0] != 0 {
48 return Err("RegistryKey must be less than 2^24");
49 }
50
51 let mut bytes = [0u8; 3];
52 bytes.copy_from_slice(&v[1..]);
53 Ok(Self(bytes))
54 }
55}
56
57impl TryFrom<&[u8]> for RegistryKey {
58 type Error = &'static str;
59
60 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
61 if value.len() != Self::SIZE {
62 return Err("RegistryKey must be 3 bytes long");
63 }
64
65 let mut bytes = [0u8; 3];
66 bytes.copy_from_slice(value);
67 Ok(Self(bytes))
68 }
69}
70
71impl AsRef<[u8]> for RegistryKey {
72 fn as_ref(&self) -> &[u8] {
73 &self.0
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::RegistryKey;
80
81 #[test]
82 fn key_next() {
83 assert_eq!(RegistryKey::ZERO.next(), RegistryKey([0, 0, 1]));
84 assert_eq!(RegistryKey::ZERO.next().next(), RegistryKey([0, 0, 2]));
85 assert_eq!(RegistryKey([0, 0, 255]).next(), RegistryKey([0, 1, 0]));
86 assert_eq!(RegistryKey([0, 1, 255]).next(), RegistryKey([0, 2, 0]));
87 assert_eq!(RegistryKey([0, 255, 255]).next(), RegistryKey([1, 0, 0]));
88 assert_eq!(RegistryKey::MAX_WRITABLE.next(), RegistryKey::ZERO);
89 }
90}