1use core::fmt;
7
8pub(crate) const UID_LEN: usize = 16;
10
11#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct DeviceUid([u8; UID_LEN]);
16
17#[derive(Clone, Debug, PartialEq, Eq)]
19pub struct UidParseError {
20 input: String,
21}
22
23impl fmt::Display for UidParseError {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 write!(f, "invalid uid {:?}", self.input)
26 }
27}
28
29impl std::error::Error for UidParseError {}
30
31impl DeviceUid {
32 pub const ZERO: Self = Self([0; UID_LEN]);
34
35 pub const fn from_array(raw: [u8; UID_LEN]) -> Self {
37 Self(raw)
38 }
39
40 pub fn from_bytes(b: &[u8]) -> Result<Self, UidParseError> {
45 if b.is_empty() {
46 return Ok(Self::ZERO);
47 }
48 match b
49 .get(..UID_LEN)
50 .and_then(|s| <[u8; UID_LEN]>::try_from(s).ok())
51 {
52 Some(raw) => Ok(Self(raw)),
53 None => Err(UidParseError {
54 input: format!("{b:02x?}"),
55 }),
56 }
57 }
58
59 pub fn is_zero(&self) -> bool {
61 self.0 == [0; UID_LEN]
62 }
63
64 pub const fn as_bytes(&self) -> &[u8; UID_LEN] {
66 &self.0
67 }
68}
69
70impl fmt::Display for DeviceUid {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 for (i, word) in self.0.chunks_exact(4).enumerate() {
75 if i > 0 {
76 f.write_str(".")?;
77 }
78 for b in word.iter().rev() {
79 write!(f, "{b:02x}")?;
80 }
81 }
82 Ok(())
83 }
84}
85
86impl std::str::FromStr for DeviceUid {
87 type Err = UidParseError;
88
89 fn from_str(s: &str) -> Result<Self, Self::Err> {
92 let err = || UidParseError {
93 input: s.to_owned(),
94 };
95 let mut raw = [0u8; UID_LEN];
96 let mut parts = s.split('.');
97 for word in raw.chunks_exact_mut(4) {
98 let part = parts.next().ok_or_else(err)?;
99 let v = u32::from_str_radix(part, 16).map_err(|_| err())?;
100 word.copy_from_slice(&v.to_le_bytes());
101 }
102 Ok(Self(raw))
103 }
104}
105
106#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
108pub struct BayUid {
109 pub device: DeviceUid,
111 pub port: u16,
113}
114
115impl BayUid {
116 pub const fn new(device: DeviceUid, port: u16) -> Self {
118 Self { device, port }
119 }
120}
121
122impl fmt::Display for BayUid {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 write!(f, "{}:{}", self.device, self.port)
125 }
126}