use core::fmt;
pub(crate) const UID_LEN: usize = 16;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceUid([u8; UID_LEN]);
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UidParseError {
input: String,
}
impl fmt::Display for UidParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "invalid uid {:?}", self.input)
}
}
impl std::error::Error for UidParseError {}
impl DeviceUid {
pub const ZERO: Self = Self([0; UID_LEN]);
pub const fn from_array(raw: [u8; UID_LEN]) -> Self {
Self(raw)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, UidParseError> {
if b.is_empty() {
return Ok(Self::ZERO);
}
match b
.get(..UID_LEN)
.and_then(|s| <[u8; UID_LEN]>::try_from(s).ok())
{
Some(raw) => Ok(Self(raw)),
None => Err(UidParseError {
input: format!("{b:02x?}"),
}),
}
}
pub fn is_zero(&self) -> bool {
self.0 == [0; UID_LEN]
}
pub const fn as_bytes(&self) -> &[u8; UID_LEN] {
&self.0
}
}
impl fmt::Display for DeviceUid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, word) in self.0.chunks_exact(4).enumerate() {
if i > 0 {
f.write_str(".")?;
}
for b in word.iter().rev() {
write!(f, "{b:02x}")?;
}
}
Ok(())
}
}
impl std::str::FromStr for DeviceUid {
type Err = UidParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let err = || UidParseError {
input: s.to_owned(),
};
let mut raw = [0u8; UID_LEN];
let mut parts = s.split('.');
for word in raw.chunks_exact_mut(4) {
let part = parts.next().ok_or_else(err)?;
let v = u32::from_str_radix(part, 16).map_err(|_| err())?;
word.copy_from_slice(&v.to_le_bytes());
}
Ok(Self(raw))
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct BayUid {
pub device: DeviceUid,
pub port: u16,
}
impl BayUid {
pub const fn new(device: DeviceUid, port: u16) -> Self {
Self { device, port }
}
}
impl fmt::Display for BayUid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.device, self.port)
}
}