openthread/ot/types/
channel_mask.rs1use crate::prelude_internal::*;
6
7use core::fmt::{Debug, Formatter};
8
9#[repr(transparent)]
11#[derive(Default, Clone, Copy, Eq, PartialEq)]
12pub struct ChannelMask(u32);
13
14pub const MAX_NUM_CHANNELS: u8 = 32;
16
17impl ChannelMask {
18 pub fn try_from<'a, T, I>(iter: I) -> Result<Self, ot::ChannelOutOfRange>
20 where
21 T: 'a + TryInto<ChannelIndex> + Copy,
22 I: IntoIterator<Item = &'a T>,
23 {
24 let mut ret = Self::default();
25 for &channel in iter {
26 ret.try_insert(channel.try_into().map_err(|_| ot::ChannelOutOfRange)?)?;
27 }
28 Ok(ret)
29 }
30
31 #[allow(clippy::len_without_is_empty)]
33 pub fn len(&self) -> usize {
34 self.0.count_ones() as usize
35 }
36
37 pub fn contains(&self, index: ChannelIndex) -> bool {
39 if index < MAX_NUM_CHANNELS {
40 self.0 & (1u32 << index) != 0
41 } else {
42 false
43 }
44 }
45
46 pub fn try_insert(&mut self, index: ChannelIndex) -> Result<(), ot::ChannelOutOfRange> {
51 if index >= MAX_NUM_CHANNELS {
52 Err(ot::ChannelOutOfRange)
53 } else {
54 let mask = 1u32 << index;
55 self.0 |= mask;
56 Ok(())
57 }
58 }
59
60 pub fn try_remove(&mut self, index: ChannelIndex) -> Result<bool, ot::ChannelOutOfRange> {
67 if index >= MAX_NUM_CHANNELS {
68 Err(ot::ChannelOutOfRange)
69 } else {
70 let mask = 1u32 << index;
71 let removed = self.0 & mask != 0;
72 self.0 &= !mask;
73 Ok(removed)
74 }
75 }
76}
77
78impl Debug for ChannelMask {
79 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
80 write!(f, "{:?}", self.collect::<Vec<_>>())
81 }
82}
83
84impl From<u32> for ChannelMask {
85 fn from(mask: u32) -> Self {
86 Self(mask)
87 }
88}
89
90impl From<ChannelMask> for u32 {
91 fn from(mask: ChannelMask) -> Self {
92 mask.0
93 }
94}
95
96impl Iterator for ChannelMask {
97 type Item = ChannelIndex;
98 fn next(&mut self) -> Option<Self::Item> {
99 let channel: ChannelIndex = self.0.trailing_zeros().try_into().unwrap();
100 match self.try_remove(channel) {
101 Ok(true) => Some(channel),
102 Ok(false) => {
103 unreachable!(
104 "Bug in ChannelMask. Next Channel: {}, Full Mask: {:#08x}",
105 channel, self.0
106 )
107 }
108 Err(ot::ChannelOutOfRange) => None,
109 }
110 }
111
112 fn size_hint(&self) -> (usize, Option<usize>) {
113 let len = self.len();
114 (len, Some(len))
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn test_channel_mask_iter() {
124 let mut mask = ChannelMask::default();
125
126 assert_eq!(mask.count(), 0);
127
128 mask.try_insert(9).unwrap();
129 mask.try_insert(13).unwrap();
130 mask.try_insert(14).unwrap();
131
132 assert!(mask.contains(9));
133 assert!(mask.contains(13));
134 assert!(mask.contains(14));
135 assert!(!mask.contains(21));
136
137 assert_eq!(mask.collect::<Vec<_>>(), vec![9, 13, 14]);
138 assert_eq!(mask.len(), 3);
139
140 assert_eq!(mask.try_remove(13), Ok(true));
141
142 assert_eq!(mask.collect::<Vec<_>>(), vec![9, 14]);
143
144 assert_eq!(mask.try_remove(13), Ok(false));
145
146 assert_eq!(mask.collect::<Vec<_>>(), vec![9, 14]);
147
148 assert_eq!(ChannelMask::from(0).collect::<Vec<_>>(), vec![]);
149 assert_eq!(ChannelMask::from(0x0000FFFF).collect::<Vec<_>>(), (0..16).collect::<Vec<_>>());
150 assert_eq!(ChannelMask::from(0xFFFF0000).collect::<Vec<_>>(), (16..32).collect::<Vec<_>>());
151 assert_eq!(ChannelMask::from(0xFFFFFFFF).collect::<Vec<_>>(), (0..32).collect::<Vec<_>>());
152
153 assert!(ChannelMask::from(0xFFFFFFFF).contains(MAX_NUM_CHANNELS - 1));
154 assert!(!ChannelMask::from(0xFFFFFFFF).contains(MAX_NUM_CHANNELS));
155 assert!(!ChannelMask::from(0xFFFFFFFF).contains(255));
156
157 assert_eq!(ChannelMask::from(0xFFFFFFFF).len(), 32);
158 assert_eq!(ChannelMask::from(0x0000FFFF).len(), 16);
159 assert_eq!(ChannelMask::from(0xFFFF0000).len(), 16);
160 assert_eq!(ChannelMask::from(0).len(), 0);
161 }
162}