ittech/data/
channel.rs

1use super::*;
2use std::borrow::Borrow;
3use std::convert::TryInto;
4use std::fmt::{self, Debug};
5use std::iter::FromIterator;
6use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
7
8
9/// Channel number
10#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
11pub struct Channel(RangedU8<0, 63>);
12
13impl Channel {
14    /// Create a channel identifier with the given number
15    ///
16    /// Accepted range is 1..=64, this function panics for values out of the range.
17    pub fn new(number: u8) -> Channel {
18        assert!((1..=64).contains(&number), "channel number is out of range");
19        Channel::from_u8_index(number - 1)
20    }
21
22    /// Returns 0 based channel index (0..=63), as opposed to channel number (1..=64)
23    pub fn as_usize(self) -> usize {
24        self.0.as_u8().into()
25    }
26
27    /// Creates channel from channel index (0..=63), as opposed to channel number (1..=64)
28    pub(crate) fn from_u8_index(raw: u8) -> Channel {
29        Channel(raw.try_into().expect("channel index out of range"))
30    }
31}
32
33impl Debug for Channel {
34    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35        write!(f, "ch{:02}", self.0.as_u8() + 1)
36    }
37}
38
39
40/// Active channels in a particular pattern or module.
41#[derive(Clone, Copy, PartialEq)]
42pub struct ActiveChannels(u64);
43
44impl ActiveChannels {
45    pub const fn all() -> ActiveChannels {
46        ActiveChannels(u64::MAX)
47    }
48
49    pub const fn empty() -> ActiveChannels {
50        ActiveChannels(0)
51    }
52
53    pub fn new<C: Borrow<Channel>>(iter: impl IntoIterator<Item=C>) -> ActiveChannels {
54        iter.into_iter()
55            .map(|c| *c.borrow())
56            .collect()
57    }
58
59    pub fn iter(self) -> impl Iterator<Item=Channel> {
60        (0..=63)
61            .filter(move |chan| (self.0 & (1u64 << chan)) != 0)
62            .map(Channel::from_u8_index)
63    }
64
65    pub const fn count(self) -> usize {
66        // NOTE 0..64 will always fit into an usize but we can't use .into() because const context
67        #[allow(clippy::as_conversions)]
68        { self.0.count_ones() as usize }
69    }
70}
71
72impl BitAnd<ActiveChannels> for ActiveChannels {
73    type Output = ActiveChannels;
74    fn bitand(self, rhs: ActiveChannels) -> Self::Output {
75        ActiveChannels(self.0 & rhs.0)
76    }
77}
78
79impl BitAndAssign for ActiveChannels {
80    fn bitand_assign(&mut self, rhs: ActiveChannels) {
81        *self = *self & rhs;
82    }
83}
84
85impl BitOr<ActiveChannels> for ActiveChannels {
86    type Output = ActiveChannels;
87    fn bitor(self, rhs: ActiveChannels) -> Self::Output {
88        ActiveChannels(self.0 | rhs.0)
89    }
90}
91
92impl BitOrAssign for ActiveChannels {
93    fn bitor_assign(&mut self, rhs: ActiveChannels) {
94        *self = *self | rhs;
95    }
96}
97
98impl FromIterator<Channel> for ActiveChannels {
99    fn from_iter<I: IntoIterator<Item=Channel>>(iter: I) -> ActiveChannels {
100        ActiveChannels(
101            iter.into_iter()
102                .map(|chan| 1u64 << chan.as_usize())
103                .fold(0u64, u64::bitor)
104        )
105    }
106}
107
108impl Debug for ActiveChannels {
109    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110        f.debug_list()
111            .entries(self.iter())
112            .finish()
113    }
114}