use crate::mac::{Aid, MAX_AID};
const TIM_BITMAP_LEN: usize = (MAX_AID as usize + 1) / 8;
pub struct TrafficIndicationMap([u8; TIM_BITMAP_LEN]);
impl TrafficIndicationMap {
pub fn new() -> Self {
Self([0; TIM_BITMAP_LEN])
}
pub fn set_traffic_buffered(&mut self, aid: Aid, buffered: bool) {
let octet = aid as usize / 8;
let bit_offset = aid as usize % 8;
self.0[octet] = (self.0[octet] & !(1 << bit_offset)) | ((buffered as u8) << bit_offset)
}
fn n1(&self) -> usize {
for (i, b) in self.0.iter().enumerate() {
if *b != 0 {
return i & !0b1;
}
}
0
}
fn n2(&self) -> usize {
for (i, b) in self.0.iter().enumerate().rev() {
if *b != 0 {
return i;
}
}
0
}
pub fn make_partial_virtual_bitmap(&self) -> (u8, &[u8]) {
let n1 = self.n1();
let n2 = self.n2();
((n1 / 2) as u8, &self.0[n1..n2 + 1])
}
}
pub fn is_traffic_buffered(offset: u8, bitmap: &[u8], aid: Aid) -> bool {
let n1 = offset as usize * 2;
let octet = aid as usize / 8;
let carries_aid = n1 <= octet && octet < bitmap.len() + n1;
carries_aid && bitmap[octet - n1] & (1 << (aid as usize % 8)) != 0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zero_offset() {
let bitmap = &[0b0010010][..];
assert!(!is_traffic_buffered(0, bitmap, 0));
assert!(is_traffic_buffered(0, bitmap, 1));
assert!(!is_traffic_buffered(0, bitmap, 2));
assert!(!is_traffic_buffered(0, bitmap, 3));
assert!(is_traffic_buffered(0, bitmap, 4));
assert!(!is_traffic_buffered(0, bitmap, 5));
assert!(!is_traffic_buffered(0, bitmap, 6));
assert!(!is_traffic_buffered(0, bitmap, 7));
assert!(!is_traffic_buffered(0, bitmap, 100));
}
#[test]
fn with_offset() {
let bitmap = &[0b0010010][..];
assert!(!is_traffic_buffered(1, bitmap, 15));
assert!(!is_traffic_buffered(1, bitmap, 16));
assert!(is_traffic_buffered(1, bitmap, 17));
assert!(!is_traffic_buffered(1, bitmap, 18));
assert!(!is_traffic_buffered(1, bitmap, 19));
assert!(is_traffic_buffered(1, bitmap, 20));
assert!(!is_traffic_buffered(1, bitmap, 21));
assert!(!is_traffic_buffered(1, bitmap, 22));
assert!(!is_traffic_buffered(1, bitmap, 100));
}
#[test]
fn traffic_indication_map_set_traffic_buffered() {
let mut tim = TrafficIndicationMap::new();
tim.set_traffic_buffered(12, true);
let mut expected_bitmap = [0; TIM_BITMAP_LEN];
expected_bitmap[1] = 0b00010000;
assert_eq!(&tim.0[..], &expected_bitmap[..]);
assert_eq!(tim.n1(), 0);
assert_eq!(tim.n2(), 1);
}
#[test]
fn traffic_indication_map_set_traffic_buffered_multiple_octets() {
let mut tim = TrafficIndicationMap::new();
tim.set_traffic_buffered(12, true);
tim.set_traffic_buffered(35, true);
let mut expected_bitmap = [0; TIM_BITMAP_LEN];
expected_bitmap[1] = 0b00010000;
expected_bitmap[4] = 0b00001000;
assert_eq!(&tim.0[..], &expected_bitmap[..]);
assert_eq!(tim.n1(), 0);
assert_eq!(tim.n2(), 4);
}
#[test]
fn from_partial_virtual_bitmap() {
let mut tim = TrafficIndicationMap::new();
tim.set_traffic_buffered(12, true);
let (offset, bitmap) = tim.make_partial_virtual_bitmap();
assert_eq!(offset, 0);
assert_eq!(bitmap, &[0b00000000, 0b00010000]);
assert!(is_traffic_buffered(offset, bitmap, 12));
}
#[test]
fn from_partial_virtual_bitmap_bigger_offset() {
let mut tim = TrafficIndicationMap::new();
tim.set_traffic_buffered(49, true);
let (offset, bitmap) = tim.make_partial_virtual_bitmap();
assert_eq!(offset, 3);
assert_eq!(bitmap, &[0b00000010]);
assert!(is_traffic_buffered(offset, bitmap, 49));
}
#[test]
fn from_partial_virtual_bitmap_multiple_octets() {
let mut tim = TrafficIndicationMap::new();
tim.set_traffic_buffered(12, true);
tim.set_traffic_buffered(35, true);
let (offset, bitmap) = tim.make_partial_virtual_bitmap();
assert_eq!(offset, 0);
assert_eq!(bitmap, &[0b00000000, 0b00010000, 0b00000000, 0b00000000, 0b00001000]);
assert!(is_traffic_buffered(offset, bitmap, 12));
assert!(is_traffic_buffered(offset, bitmap, 35));
}
#[test]
fn from_partial_virtual_bitmap_no_traffic() {
let tim = TrafficIndicationMap::new();
let (offset, bitmap) = tim.make_partial_virtual_bitmap();
assert_eq!(offset, 0);
assert_eq!(bitmap, &[0b00000000]);
}
}