use std::{collections::HashSet, convert::TryFrom, fmt::Display, ops::Deref};
use deku::{DekuRead, DekuWrite};
use serde::{Deserialize, Serialize};
use crate::ies::{Field, IeId};
#[derive(Debug, Clone, PartialEq, Eq, Hash, DekuRead, DekuWrite, Serialize, Deserialize)]
#[deku(ctx = "len: usize")]
pub struct SupportedRates {
#[deku(count = "len")]
bytes: Vec<u8>,
}
impl SupportedRates {
pub const NAME: &'static str = "Supported Rates";
pub const ID: u8 = 1;
pub const ID_EXT: Option<u8> = None;
pub(crate) const IE_ID: IeId = IeId::new(Self::ID, Self::ID_EXT);
pub fn rates(&self) -> HashSet<DataRate> {
self.bytes
.iter()
.filter_map(|byte| DataRate::try_from(*byte).ok())
.collect()
}
pub fn basic_rates(&self) -> Vec<f64> {
self.bytes
.iter()
.filter_map(|byte| DataRate::try_from(*byte).ok())
.filter_map(|rate| {
if rate.is_basic() {
Some(rate.value())
} else {
None
}
})
.collect()
}
pub fn all_rates(&self) -> Vec<f64> {
self.bytes
.iter()
.filter_map(|byte| DataRate::try_from(*byte).ok())
.map(|rate| rate.value())
.collect()
}
pub fn summary(&self) -> String {
let rates = self
.bytes
.iter()
.filter_map(|byte| DataRate::try_from(*byte).ok())
.map(|rate| {
if rate.is_basic() {
format!(
"{}*",
rate.value()
.to_string()
.trim_end_matches('0')
.trim_end_matches('.')
)
} else {
rate.value()
.to_string()
.trim_end_matches('0')
.trim_end_matches('.')
.to_string()
}
})
.collect::<Vec<String>>();
rates.join(", ")
}
pub fn fields(&self) -> Vec<Field> {
self.bytes
.iter()
.filter_map(|byte| {
let rate = DataRate::try_from(*byte).ok()?;
Some((rate, byte))
})
.map(|(rate, byte)| {
Field::builder()
.title("Supported Rate")
.value(
format!("{:.1}", rate.value())
.trim_end_matches('0')
.trim_end_matches('.'),
)
.units("Mbps".to_string() + if rate.is_basic() { " (Basic)" } else { "" })
.byte(*byte)
.build()
})
.collect()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, DekuRead, DekuWrite, Serialize, Deserialize)]
#[deku(ctx = "len: usize")]
pub struct ExtendedSupportedRates {
#[deku(ctx = "len")]
supported_rates: SupportedRates,
}
impl ExtendedSupportedRates {
pub const NAME: &'static str = "Extended Supported Rates";
pub const ID: u8 = 50;
pub const ID_EXT: Option<u8> = None;
pub(crate) const IE_ID: IeId = IeId::new(Self::ID, Self::ID_EXT);
}
impl Deref for ExtendedSupportedRates {
type Target = SupportedRates;
fn deref(&self) -> &Self::Target {
&self.supported_rates
}
}
impl AsRef<SupportedRates> for ExtendedSupportedRates {
fn as_ref(&self) -> &SupportedRates {
&self.supported_rates
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum DataRate {
OneMbps(bool),
TwoMbps(bool),
FivePointFiveMbps(bool),
SixMbps(bool),
NineMbps(bool),
ElevenMbps(bool),
TwelveMbps(bool),
EighteenMbps(bool),
TwentyTwoMbps(bool),
TwentyFourMbps(bool),
ThirtyThreeMbps(bool),
ThirtySixMbps(bool),
FortyEightMbps(bool),
FiftyFourMbps(bool),
}
impl DataRate {
pub fn is_basic(&self) -> bool {
match self {
DataRate::OneMbps(is_basic) => *is_basic,
DataRate::TwoMbps(is_basic) => *is_basic,
DataRate::FivePointFiveMbps(is_basic) => *is_basic,
DataRate::SixMbps(is_basic) => *is_basic,
DataRate::NineMbps(is_basic) => *is_basic,
DataRate::ElevenMbps(is_basic) => *is_basic,
DataRate::TwelveMbps(is_basic) => *is_basic,
DataRate::EighteenMbps(is_basic) => *is_basic,
DataRate::TwentyTwoMbps(is_basic) => *is_basic,
DataRate::TwentyFourMbps(is_basic) => *is_basic,
DataRate::ThirtyThreeMbps(is_basic) => *is_basic,
DataRate::ThirtySixMbps(is_basic) => *is_basic,
DataRate::FortyEightMbps(is_basic) => *is_basic,
DataRate::FiftyFourMbps(is_basic) => *is_basic,
}
}
pub fn value(&self) -> f64 {
match self {
DataRate::OneMbps(_) => 1.0,
DataRate::TwoMbps(_) => 2.0,
DataRate::FivePointFiveMbps(_) => 5.5,
DataRate::SixMbps(_) => 6.0,
DataRate::NineMbps(_) => 9.0,
DataRate::ElevenMbps(_) => 11.0,
DataRate::TwelveMbps(_) => 12.0,
DataRate::EighteenMbps(_) => 18.0,
DataRate::TwentyTwoMbps(_) => 22.0,
DataRate::TwentyFourMbps(_) => 24.0,
DataRate::ThirtyThreeMbps(_) => 33.0,
DataRate::ThirtySixMbps(_) => 36.0,
DataRate::FortyEightMbps(_) => 48.0,
DataRate::FiftyFourMbps(_) => 54.0,
}
}
}
impl Display for DataRate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_basic() {
write!(f, "{:.1}*", self.value())
} else {
write!(f, "{:.1}", self.value())
}
}
}
impl TryFrom<u8> for DataRate {
type Error = &'static str;
fn try_from(rate_byte: u8) -> Result<Self, Self::Error> {
let is_basic = (rate_byte & 0b10000000) > 0;
let encoded_rate = rate_byte & 0b01111111;
match encoded_rate {
2 => Ok(DataRate::OneMbps(is_basic)),
4 => Ok(DataRate::TwoMbps(is_basic)),
11 => Ok(DataRate::FivePointFiveMbps(is_basic)),
12 => Ok(DataRate::SixMbps(is_basic)),
18 => Ok(DataRate::NineMbps(is_basic)),
22 => Ok(DataRate::ElevenMbps(is_basic)),
24 => Ok(DataRate::TwelveMbps(is_basic)),
36 => Ok(DataRate::EighteenMbps(is_basic)),
44 => Ok(DataRate::TwentyTwoMbps(is_basic)),
48 => Ok(DataRate::TwentyFourMbps(is_basic)),
66 => Ok(DataRate::ThirtyThreeMbps(is_basic)),
72 => Ok(DataRate::ThirtySixMbps(is_basic)),
96 => Ok(DataRate::FortyEightMbps(is_basic)),
108 => Ok(DataRate::FiftyFourMbps(is_basic)),
_ => Err("Invalid data rate"),
}
}
}