1#![forbid(clippy::exit, clippy::expect_used, clippy::panic, clippy::unwrap_used)]
3#![deny(clippy::unimplemented, clippy::unreachable)]
4#![warn(clippy::dbg_macro, clippy::todo, clippy::try_err)]
5#![warn(clippy::cargo, clippy::nursery, clippy::pedantic, missing_docs)]
6#![no_std]
7
8use core::marker::PhantomData;
9
10pub trait Flag {
12 fn get_offset(&self) -> u8;
16}
17
18pub trait ConstField<T: Flag>: Sized {
20 #[cfg(feature = "serde")]
22 type Inner: for<'de> serde::Deserialize<'de>;
23 #[cfg(not(feature = "serde"))]
25 type Inner;
26
27 fn new() -> Self;
29 fn new_with(value: Self::Inner) -> Self;
31
32 fn get_inner(&self) -> Self::Inner;
34
35 fn contains(&self, flag: impl Into<T>) -> bool;
37 fn contains_all(&self, flags: &[impl Into<T> + Clone]) -> bool {
39 flags.iter().all(|flag| self.contains(flag.clone()))
40 }
41 fn contains_any(&self, flags: &[impl Into<T> + Clone]) -> bool {
43 flags.iter().any(|flag| self.contains(flag.clone()))
44 }
45}
46
47pub trait Field<T: Flag>: ConstField<T> {
49 #[must_use]
51 fn insert(self, flag: impl Into<T>) -> Self;
52 #[must_use]
54 fn insert_all(mut self, flags: &[impl Into<T> + Clone]) -> Self {
55 for flag in flags {
56 self = self.insert(flag.clone());
57 }
58
59 self
60 }
61
62 #[must_use]
64 fn remove(self, flag: impl Into<T>) -> Self;
65 #[must_use]
67 fn remove_all(mut self, flags: &[impl Into<T> + Clone]) -> Self {
68 for flag in flags {
69 self = self.remove(flag.clone());
70 }
71
72 self
73 }
74
75 #[must_use]
77 fn not(self) -> Self;
78}
79
80#[macro_export]
82macro_rules! flags {
83 ($visibility:vis $name:ident {$($flag:ident = $offset:literal,)*}) => {
84 #[repr(u8)]
85 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
86 #[allow(missing_docs)]
87 $visibility enum $name {
88 $($flag = $offset,)*
89 }
90
91 impl Flag for $name {
92 fn get_offset(&self) -> u8 {
93 *self as u8
94 }
95 }
96 };
97}
98
99macro_rules! bitfield {
100 (const $id:ident($n:ty); $doc:literal$(, $mark:literal)?) => {
101 #[doc = $doc]
102 $(#[doc = $mark])?
103 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
104 pub struct $id<T: Flag>($n, PhantomData<T>);
105
106 impl<T: Flag> ConstField<T> for $id<T> {
107 type Inner = $n;
108
109 fn new() -> Self {
110 Self::new_with(0)
111 }
112 fn new_with(value: Self::Inner) -> Self {
113 Self(value, PhantomData)
114 }
115 fn get_inner(&self) -> Self::Inner {
116 self.0
117 }
118 fn contains(&self, flag: impl Into<T>) -> bool {
119 self.0 & (1 << flag.into().get_offset()) != 0
120 }
121 }
122
123 impl<T: Flag> Default for $id<T> {
124 fn default() -> Self {
125 Self::new()
126 }
127 }
128
129 #[cfg(feature = "serde")]
130 impl<T: Flag> serde::Serialize for $id<T> {
131 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
132 where
133 S: serde::Serializer,
134 {
135 self.0.serialize(serializer)
136 }
137 }
138 #[cfg(feature = "serde")]
139 impl<'de, T: Flag> serde::Deserialize<'de> for $id<T> {
140 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
141 where
142 D: serde::Deserializer<'de>,
143 {
144 let inner = <Self as ConstField<T>>::Inner::deserialize(deserializer)?;
145
146 Ok(Self::new_with(inner))
147 }
148 }
149 };
150 ($id:ident($n:ty); $doc:literal$(, $mark:literal)?) => {
151 bitfield!(const $id($n); $doc$(, $mark)?);
152
153 impl<T: Flag> Field<T> for $id<T> {
154 fn insert(mut self, flag: impl Into<T>) -> Self {
155 self.0 |= 1 << flag.into().get_offset();
156 self
157 }
158 fn remove(mut self, flag: impl Into<T>) -> Self {
159 self.0 &= !(1 << flag.into().get_offset());
160 self
161 }
162 fn not(mut self) -> Self {
163 self.0 = !self.0;
164 self
165 }
166 }
167 };
168 ($n:ty => const $imm:ident, $mut:ident; $doc:literal) => {
169 bitfield!(const $imm($n); $doc, "\nThis is the immutable form and can be converted with `From::from` or `Into::into`.");
170 bitfield!($mut($n); $doc, "\nThis is the mutable form and can be converted with `From::from` or `Into::into`.");
171
172 impl<T: Flag> From<$imm<T>> for $mut<T> {
173 fn from(value: $imm<T>) -> Self {
174 Self::new_with(value.get_inner())
175 }
176 }
177 impl<T: Flag> From<$mut<T>> for $imm<T> {
178 fn from(value: $mut<T>) -> Self {
179 Self::new_with(value.get_inner())
180 }
181 }
182 };
183}
184
185bitfield!(u8 => const ConstBitField8, BitField8; "A bit field containing a `u8`");
186bitfield!(u16 => const ConstBitField16, BitField16; "A bit field containing a `u16`");
187bitfield!(u32 => const ConstBitField32, BitField32; "A bit field containing a `u32`");
188bitfield!(u64 => const ConstBitField64, BitField64; "A bit field containing a `u64`");
189bitfield!(u128 => const ConstBitField128, BitField128; "A bit field containing a `u128`");
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194
195 flags!(Byte {
196 Zero = 0,
197 One = 1,
198 Two = 2,
199 Three = 3,
200 Four = 4,
201 Five = 5,
202 Six = 6,
203 Seven = 7,
204 });
205
206 #[test]
207 fn new_empty() {
208 let field = BitField8::<Byte>::new();
209
210 assert_eq!(0, field.get_inner());
211 }
212 #[test]
213 fn new_filled() {
214 let field = BitField8::<Byte>::new_with(0b0010_0110);
215
216 assert_ne!(0, field.get_inner());
217 }
218 #[test]
219 fn contains() {
220 let field = BitField8::<Byte>::new_with(0b0010_0110);
221
222 assert!(field.contains_all(&[Byte::One, Byte::Two, Byte::Five]));
223 assert!(!field.contains_any(&[
224 Byte::Zero,
225 Byte::Three,
226 Byte::Four,
227 Byte::Six,
228 Byte::Seven,
229 ]));
230 }
231 #[test]
232 fn insert() {
233 let mut field = BitField8::<Byte>::new_with(0b0000_0111);
234
235 assert!(field.contains_all(&[Byte::Zero, Byte::One, Byte::Two]));
236
237 field = field.insert_all(&[Byte::Five, Byte::Seven]);
238
239 assert!(!field.contains_any(&[Byte::Three, Byte::Four, Byte::Six]));
240 assert!(field.contains_all(&[Byte::Zero, Byte::One, Byte::Two, Byte::Five, Byte::Seven]));
241 }
242 #[test]
243 fn remove() {
244 let mut field = BitField8::<Byte>::new_with(0b0000_0111);
245
246 assert!(field.contains_all(&[Byte::Zero, Byte::One, Byte::Two]));
247
248 field = field.remove_all(&[Byte::Zero, Byte::Two]);
249
250 assert!(field.contains(Byte::One));
251 }
252 #[test]
253 fn not() {
254 let mut field = BitField8::<Byte>::new_with(0b0000_1111);
255
256 assert!(field.contains_all(&[Byte::Zero, Byte::One, Byte::Two, Byte::Three]));
257
258 field = field.not();
259
260 assert!(field.contains_all(&[Byte::Four, Byte::Five, Byte::Six, Byte::Seven]));
261 }
262}