use crate::result::{Error, Result};
use crate::util::check_ascii;
pub const OID_LEN: usize = 2;
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct OemId(u16);
impl OemId {
pub const fn new() -> Self {
Self(0)
}
pub const fn bits(&self) -> u16 {
self.0
}
pub const fn bytes(&self) -> [u8; OID_LEN] {
self.0.to_be_bytes()
}
pub const fn try_from_bits(val: u16) -> Result<Self> {
match check_ascii(&val.to_be_bytes(), OID_LEN) {
Ok(_) => Ok(Self(val)),
Err(err) => Err(err),
}
}
pub const fn try_from_bytes(val: &[u8]) -> Result<Self> {
match check_ascii(val, OID_LEN) {
Ok(_) => Ok(Self(u16::from_be_bytes([val[0], val[1]]))),
Err(err) => Err(err),
}
}
}
impl Default for OemId {
fn default() -> Self {
Self::new()
}
}
impl From<OemId> for u16 {
fn from(val: OemId) -> Self {
val.bits()
}
}
impl From<OemId> for [u8; OID_LEN] {
fn from(val: OemId) -> Self {
val.bytes()
}
}
impl TryFrom<u16> for OemId {
type Error = Error;
fn try_from(val: u16) -> Result<Self> {
Self::try_from_bits(val)
}
}
impl TryFrom<&[u8]> for OemId {
type Error = Error;
fn try_from(val: &[u8]) -> Result<Self> {
Self::try_from_bytes(val)
}
}
impl<const N: usize> TryFrom<[u8; N]> for OemId {
type Error = Error;
fn try_from(val: [u8; N]) -> Result<Self> {
Self::try_from_bytes(val.as_ref())
}
}
impl<const N: usize> TryFrom<&[u8; N]> for OemId {
type Error = Error;
fn try_from(val: &[u8; N]) -> Result<Self> {
Self::try_from_bytes(val.as_ref())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid() {
(0..u16::MAX)
.filter(|c| check_ascii(&c.to_be_bytes(), OID_LEN).is_ok())
.for_each(|oid| {
let raw_oid = oid.to_be_bytes();
let exp_oid = OemId(oid);
assert_eq!(OemId::try_from_bits(oid), Ok(exp_oid));
assert_eq!(OemId::try_from_bytes(raw_oid.as_ref()), Ok(exp_oid));
assert_eq!(OemId::try_from(raw_oid.as_ref()), Ok(exp_oid));
assert_eq!(OemId::try_from(&raw_oid), Ok(exp_oid));
assert_eq!(OemId::try_from(raw_oid), Ok(exp_oid));
assert_eq!(u16::from(exp_oid), oid);
assert_eq!(<[u8; OID_LEN]>::from(exp_oid), raw_oid);
assert_eq!(exp_oid.bits(), oid);
assert_eq!(exp_oid.bytes(), raw_oid);
});
}
#[test]
fn test_invalid() {
(0..u16::MAX)
.filter(|c| check_ascii(&c.to_be_bytes(), OID_LEN).is_err())
.for_each(|oid| {
let raw_oid = oid.to_be_bytes();
let err = check_ascii(raw_oid.as_ref(), OID_LEN).map(|_| OemId::new());
assert!(err.is_err());
assert_eq!(OemId::try_from_bits(oid), err);
assert_eq!(OemId::try_from_bytes(raw_oid.as_ref()), err);
assert_eq!(OemId::try_from(raw_oid.as_ref()), err);
assert_eq!(OemId::try_from(&raw_oid), err);
assert_eq!(OemId::try_from(raw_oid), err);
});
}
}