1use crate::mac::{Aid, MAX_AID};
6
7const TIM_BITMAP_LEN: usize = (MAX_AID as usize + 1) / 8;
8
9pub struct TrafficIndicationMap([u8; TIM_BITMAP_LEN]);
12
13impl TrafficIndicationMap {
14    pub fn new() -> Self {
15        Self([0; TIM_BITMAP_LEN])
16    }
17
18    pub fn set_traffic_buffered(&mut self, aid: Aid, buffered: bool) {
25        let octet = aid as usize / 8;
26        let bit_offset = aid as usize % 8;
27        self.0[octet] = (self.0[octet] & !(1 << bit_offset)) | ((buffered as u8) << bit_offset)
28    }
29
30    fn n1(&self) -> usize {
33        for (i, b) in self.0.iter().enumerate() {
35            if *b != 0 {
36                return i & !0b1;
38            }
39        }
40
41        0
44    }
45
46    fn n2(&self) -> usize {
49        for (i, b) in self.0.iter().enumerate().rev() {
51            if *b != 0 {
52                return i;
53            }
54        }
55
56        0
57    }
58
59    pub fn make_partial_virtual_bitmap(&self) -> (u8, &[u8]) {
61        let n1 = self.n1();
64        let n2 = self.n2();
65
66        ((n1 / 2) as u8, &self.0[n1..n2 + 1])
74    }
75}
76
77pub fn is_traffic_buffered(offset: u8, bitmap: &[u8], aid: Aid) -> bool {
78    let n1 = offset as usize * 2;
81    let octet = aid as usize / 8;
82
83    let carries_aid = n1 <= octet && octet < bitmap.len() + n1;
84    carries_aid && bitmap[octet - n1] & (1 << (aid as usize % 8)) != 0
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn zero_offset() {
93        let bitmap = &[0b0010010][..];
94
95        assert!(!is_traffic_buffered(0, bitmap, 0));
96        assert!(is_traffic_buffered(0, bitmap, 1));
97        assert!(!is_traffic_buffered(0, bitmap, 2));
98        assert!(!is_traffic_buffered(0, bitmap, 3));
99        assert!(is_traffic_buffered(0, bitmap, 4));
100        assert!(!is_traffic_buffered(0, bitmap, 5));
101        assert!(!is_traffic_buffered(0, bitmap, 6));
102        assert!(!is_traffic_buffered(0, bitmap, 7));
103        assert!(!is_traffic_buffered(0, bitmap, 100));
104    }
105
106    #[test]
107    fn with_offset() {
108        let bitmap = &[0b0010010][..];
109
110        assert!(!is_traffic_buffered(1, bitmap, 15));
112        assert!(!is_traffic_buffered(1, bitmap, 16));
113        assert!(is_traffic_buffered(1, bitmap, 17));
114        assert!(!is_traffic_buffered(1, bitmap, 18));
115        assert!(!is_traffic_buffered(1, bitmap, 19));
116        assert!(is_traffic_buffered(1, bitmap, 20));
117        assert!(!is_traffic_buffered(1, bitmap, 21));
118        assert!(!is_traffic_buffered(1, bitmap, 22));
119        assert!(!is_traffic_buffered(1, bitmap, 100));
120    }
121
122    #[test]
123    fn traffic_indication_map_set_traffic_buffered() {
124        let mut tim = TrafficIndicationMap::new();
125        tim.set_traffic_buffered(12, true);
126        let mut expected_bitmap = [0; TIM_BITMAP_LEN];
127        expected_bitmap[1] = 0b00010000;
128        assert_eq!(&tim.0[..], &expected_bitmap[..]);
129        assert_eq!(tim.n1(), 0);
130        assert_eq!(tim.n2(), 1);
131    }
132
133    #[test]
134    fn traffic_indication_map_set_traffic_buffered_multiple_octets() {
135        let mut tim = TrafficIndicationMap::new();
136        tim.set_traffic_buffered(12, true);
137        tim.set_traffic_buffered(35, true);
138        let mut expected_bitmap = [0; TIM_BITMAP_LEN];
139        expected_bitmap[1] = 0b00010000;
140        expected_bitmap[4] = 0b00001000;
141        assert_eq!(&tim.0[..], &expected_bitmap[..]);
142        assert_eq!(tim.n1(), 0);
143        assert_eq!(tim.n2(), 4);
144    }
145
146    #[test]
147    fn from_partial_virtual_bitmap() {
148        let mut tim = TrafficIndicationMap::new();
149        tim.set_traffic_buffered(12, true);
150        let (offset, bitmap) = tim.make_partial_virtual_bitmap();
151        assert_eq!(offset, 0);
152        assert_eq!(bitmap, &[0b00000000, 0b00010000]);
153        assert!(is_traffic_buffered(offset, bitmap, 12));
154    }
155
156    #[test]
157    fn from_partial_virtual_bitmap_bigger_offset() {
158        let mut tim = TrafficIndicationMap::new();
159        tim.set_traffic_buffered(49, true);
160        let (offset, bitmap) = tim.make_partial_virtual_bitmap();
161        assert_eq!(offset, 3);
162        assert_eq!(bitmap, &[0b00000010]);
163        assert!(is_traffic_buffered(offset, bitmap, 49));
164    }
165
166    #[test]
167    fn from_partial_virtual_bitmap_multiple_octets() {
168        let mut tim = TrafficIndicationMap::new();
169        tim.set_traffic_buffered(12, true);
170        tim.set_traffic_buffered(35, true);
171        let (offset, bitmap) = tim.make_partial_virtual_bitmap();
172        assert_eq!(offset, 0);
173        assert_eq!(bitmap, &[0b00000000, 0b00010000, 0b00000000, 0b00000000, 0b00001000]);
174        assert!(is_traffic_buffered(offset, bitmap, 12));
175        assert!(is_traffic_buffered(offset, bitmap, 35));
176    }
177
178    #[test]
179    fn from_partial_virtual_bitmap_no_traffic() {
180        let tim = TrafficIndicationMap::new();
181        let (offset, bitmap) = tim.make_partial_virtual_bitmap();
182        assert_eq!(offset, 0);
183        assert_eq!(bitmap, &[0b00000000]);
184    }
185}