openthread/ot/types/
channel_mask.rsuse crate::prelude_internal::*;
use core::fmt::{Debug, Formatter};
#[repr(transparent)]
#[derive(Default, Clone, Copy, Eq, PartialEq)]
pub struct ChannelMask(u32);
pub const MAX_NUM_CHANNELS: u8 = 32;
impl ChannelMask {
pub fn try_from<'a, T, I>(iter: I) -> Result<Self, ot::ChannelOutOfRange>
where
T: 'a + TryInto<ChannelIndex> + Copy,
I: IntoIterator<Item = &'a T>,
{
let mut ret = Self::default();
for &channel in iter {
ret.try_insert(channel.try_into().map_err(|_| ot::ChannelOutOfRange)?)?;
}
Ok(ret)
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.0.count_ones() as usize
}
pub fn contains(&self, index: ChannelIndex) -> bool {
if index < MAX_NUM_CHANNELS {
self.0 & (1u32 << index) != 0
} else {
false
}
}
pub fn try_insert(&mut self, index: ChannelIndex) -> Result<(), ot::ChannelOutOfRange> {
if index >= MAX_NUM_CHANNELS {
Err(ot::ChannelOutOfRange)
} else {
let mask = 1u32 << index;
self.0 |= mask;
Ok(())
}
}
pub fn try_remove(&mut self, index: ChannelIndex) -> Result<bool, ot::ChannelOutOfRange> {
if index >= MAX_NUM_CHANNELS {
Err(ot::ChannelOutOfRange)
} else {
let mask = 1u32 << index;
let removed = self.0 & mask != 0;
self.0 &= !mask;
Ok(removed)
}
}
}
impl Debug for ChannelMask {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.collect::<Vec<_>>())
}
}
impl From<u32> for ChannelMask {
fn from(mask: u32) -> Self {
Self(mask)
}
}
impl From<ChannelMask> for u32 {
fn from(mask: ChannelMask) -> Self {
mask.0
}
}
impl Iterator for ChannelMask {
type Item = ChannelIndex;
fn next(&mut self) -> Option<Self::Item> {
let channel: ChannelIndex = self.0.trailing_zeros().try_into().unwrap();
match self.try_remove(channel) {
Ok(true) => Some(channel),
Ok(false) => {
unreachable!(
"Bug in ChannelMask. Next Channel: {}, Full Mask: {:#08x}",
channel, self.0
)
}
Err(ot::ChannelOutOfRange) => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_channel_mask_iter() {
let mut mask = ChannelMask::default();
assert_eq!(mask.count(), 0);
mask.try_insert(9).unwrap();
mask.try_insert(13).unwrap();
mask.try_insert(14).unwrap();
assert!(mask.contains(9));
assert!(mask.contains(13));
assert!(mask.contains(14));
assert!(!mask.contains(21));
assert_eq!(mask.collect::<Vec<_>>(), vec![9, 13, 14]);
assert_eq!(mask.len(), 3);
assert_eq!(mask.try_remove(13), Ok(true));
assert_eq!(mask.collect::<Vec<_>>(), vec![9, 14]);
assert_eq!(mask.try_remove(13), Ok(false));
assert_eq!(mask.collect::<Vec<_>>(), vec![9, 14]);
assert_eq!(ChannelMask::from(0).collect::<Vec<_>>(), vec![]);
assert_eq!(ChannelMask::from(0x0000FFFF).collect::<Vec<_>>(), (0..16).collect::<Vec<_>>());
assert_eq!(ChannelMask::from(0xFFFF0000).collect::<Vec<_>>(), (16..32).collect::<Vec<_>>());
assert_eq!(ChannelMask::from(0xFFFFFFFF).collect::<Vec<_>>(), (0..32).collect::<Vec<_>>());
assert!(ChannelMask::from(0xFFFFFFFF).contains(MAX_NUM_CHANNELS - 1));
assert!(!ChannelMask::from(0xFFFFFFFF).contains(MAX_NUM_CHANNELS));
assert!(!ChannelMask::from(0xFFFFFFFF).contains(255));
assert_eq!(ChannelMask::from(0xFFFFFFFF).len(), 32);
assert_eq!(ChannelMask::from(0x0000FFFF).len(), 16);
assert_eq!(ChannelMask::from(0xFFFF0000).len(), 16);
assert_eq!(ChannelMask::from(0).len(), 0);
}
}