use crate::result::{Error, Result};
mod rate_unit;
mod time_value;
pub use rate_unit::*;
pub use time_value::*;
const UNIT_MASK: u8 = 0x3;
const VALUE_MASK: u8 = 0x78;
const VALUE_SHIFT: usize = 3;
const SPEED_MASK: u8 = 0x7f;
const DEFAULT_SPEED: u8 = 0x32;
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct TransferSpeed(u8);
impl TransferSpeed {
pub const fn new() -> Self {
Self(DEFAULT_SPEED)
}
pub const fn bits(&self) -> u8 {
self.0
}
pub const fn from_parts(rate_unit: TransferRateUnit, time_value: TransferTimeValue) -> Self {
Self((time_value.into_raw() << VALUE_SHIFT) | rate_unit.into_raw())
}
pub const fn try_from_bits(val: u8) -> Result<Self> {
match (
TransferRateUnit::from_raw(val & UNIT_MASK),
TransferTimeValue::from_raw((val & VALUE_MASK) >> VALUE_SHIFT),
) {
(Ok(_), Ok(_)) => Ok(Self(val & SPEED_MASK)),
(Err(err), _) => Err(err),
(_, Err(err)) => Err(err),
}
}
pub const fn rate_unit(&self) -> TransferRateUnit {
match self.try_rate_unit() {
Ok(val) => val,
Err(_) => TransferRateUnit::new(),
}
}
pub const fn try_rate_unit(&self) -> Result<TransferRateUnit> {
TransferRateUnit::from_raw(self.0 & UNIT_MASK)
}
pub const fn time_value(&self) -> TransferTimeValue {
match self.try_time_value() {
Ok(val) => val,
Err(_) => TransferTimeValue::new(),
}
}
pub const fn try_time_value(&self) -> Result<TransferTimeValue> {
TransferTimeValue::from_raw((self.0 & VALUE_MASK) >> VALUE_SHIFT)
}
pub const fn rate_kbits(&self) -> u32 {
(self.time_value().value_int() * self.rate_unit().kbits()) / 10
}
}
impl Default for TransferSpeed {
fn default() -> Self {
Self::new()
}
}
impl From<TransferSpeed> for u8 {
fn from(val: TransferSpeed) -> Self {
val.bits()
}
}
impl TryFrom<u8> for TransferSpeed {
type Error = Error;
fn try_from(val: u8) -> Result<Self> {
Self::try_from_bits(val)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid() {
let taac = TransferSpeed::new();
assert_eq!(taac.try_rate_unit(), Ok(TransferRateUnit::new()));
assert_eq!(taac.rate_unit(), TransferRateUnit::new());
assert_eq!(taac.try_time_value(), Ok(TransferTimeValue::new()));
assert_eq!(taac.time_value(), TransferTimeValue::new());
(0..=u8::MAX)
.filter(|b| {
TransferRateUnit::from_raw(b & UNIT_MASK).is_ok()
&& TransferTimeValue::from_raw((b & VALUE_MASK) >> VALUE_SHIFT).is_ok()
})
.for_each(|raw| {
let exp_taac = TransferSpeed(raw & SPEED_MASK);
let exp_unit = TransferRateUnit::from_raw(raw & UNIT_MASK).unwrap();
let exp_value =
TransferTimeValue::from_raw((raw & VALUE_MASK) >> VALUE_SHIFT).unwrap();
let exp_kbits = (exp_value.value_int() * exp_unit.kbits()) / 10;
assert_eq!(TransferSpeed::try_from_bits(raw), Ok(exp_taac));
assert_eq!(TransferSpeed::try_from(raw), Ok(exp_taac));
assert_eq!(exp_taac.bits(), raw & SPEED_MASK);
assert_eq!(u8::from(exp_taac), raw & SPEED_MASK);
assert_eq!(exp_taac.rate_unit(), exp_unit);
assert_eq!(exp_taac.time_value(), exp_value);
assert_eq!(exp_taac.rate_kbits(), exp_kbits);
});
}
#[test]
fn test_invalid() {
(0..=u8::MAX)
.filter(|b| TransferRateUnit::from_raw(b & UNIT_MASK).is_err())
.for_each(|raw| {
let exp_err = Error::InvalidVariant((raw & UNIT_MASK) as usize);
assert_eq!(TransferSpeed::try_from_bits(raw), Err(exp_err));
assert_eq!(TransferSpeed::try_from(raw), Err(exp_err));
});
(0..=u8::MAX)
.filter(|b| {
TransferRateUnit::from_raw(b & UNIT_MASK).is_ok()
&& TransferTimeValue::from_raw((b & VALUE_MASK) >> VALUE_SHIFT).is_err()
})
.for_each(|raw| {
let exp_err = Error::InvalidVariant(((raw & VALUE_MASK) >> VALUE_SHIFT) as usize);
assert_eq!(TransferSpeed::try_from_bits(raw), Err(exp_err));
assert_eq!(TransferSpeed::try_from(raw), Err(exp_err));
});
}
}