1use std::ops::*;
60
61pub use sawp_flags_derive::BitFlags;
66
67pub trait Primitive:
69 Default
70 + BitOr<Self, Output = Self>
71 + BitAnd<Self, Output = Self>
72 + BitXor<Self, Output = Self>
73 + Not<Output = Self>
74 + PartialOrd<Self>
75 + std::fmt::Debug
76 + std::fmt::Binary
77 + Copy
78 + Clone
79{
80}
81
82impl Primitive for u8 {}
83impl Primitive for u16 {}
84impl Primitive for u32 {}
85impl Primitive for u64 {}
86impl Primitive for u128 {}
87
88pub trait Flag: Copy + Clone + std::fmt::Debug + std::fmt::Display + 'static {
90 type Primitive: Primitive;
92
93 const ITEMS: &'static [Self];
95
96 fn bits(self) -> Self::Primitive;
98
99 fn none() -> Flags<Self>;
101
102 fn all() -> Flags<Self>;
104}
105
106#[derive(Copy, Clone, PartialEq, Eq)]
108#[repr(transparent)]
109pub struct Flags<Enum, Primitive = <Enum as Flag>::Primitive> {
110 val: Primitive,
111 marker: std::marker::PhantomData<Enum>,
112}
113
114impl<Enum> std::fmt::Debug for Flags<Enum>
115where
116 Enum: Flag,
117{
118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 self.val.fmt(f)
120 }
121}
122
123impl<Enum> Default for Flags<Enum>
124where
125 Enum: Flag,
126{
127 fn default() -> Self {
128 Self {
129 val: <Enum as Flag>::Primitive::default(),
130 marker: std::marker::PhantomData,
131 }
132 }
133}
134
135impl<Enum> Flags<Enum>
136where
137 Enum: Flag,
138{
139 pub fn from_flag(flag: Enum) -> Self {
141 Self {
142 val: flag.bits(),
143 marker: std::marker::PhantomData,
144 }
145 }
146
147 pub fn from_bits(bits: <Enum as Flag>::Primitive) -> Self {
153 Self {
154 val: bits,
155 marker: std::marker::PhantomData,
156 }
157 }
158
159 pub fn bits(&self) -> <Enum as Flag>::Primitive {
161 self.val
162 }
163
164 pub fn bits_ref(&self) -> &<Enum as Flag>::Primitive {
166 &self.val
167 }
168
169 pub fn intersects<B: Into<Flags<Enum>>>(self, rhs: B) -> bool {
171 (self & rhs.into()).bits() != Enum::none().bits()
172 }
173
174 pub fn contains<B: Into<Flags<Enum>>>(self, rhs: B) -> bool {
176 let rhs = rhs.into();
177 (self & rhs).bits() == rhs.bits()
178 }
179
180 pub fn is_empty(&self) -> bool {
181 self.bits() == <Enum as Flag>::none().bits()
182 }
183
184 pub fn is_all(&self) -> bool {
185 self.bits() == <Enum as Flag>::all().bits()
186 }
187}
188
189impl<Enum: Flag> From<Enum> for Flags<Enum> {
190 fn from(flag: Enum) -> Self {
191 Self::from_flag(flag)
192 }
193}
194
195impl<Enum: Flag> PartialEq<Enum> for Flags<Enum> {
196 fn eq(&self, other: &Enum) -> bool {
197 self.bits() == other.bits()
198 }
199}
200
201impl<T, B> std::ops::BitOr<B> for Flags<T>
202where
203 T: Flag,
204 B: Into<Flags<T>>,
205{
206 type Output = Flags<T>;
207 fn bitor(self, other: B) -> Flags<T> {
208 Flags::from_bits(self.bits() | other.into().bits())
209 }
210}
211
212impl<T, B> std::ops::BitOrAssign<B> for Flags<T>
213where
214 T: Flag,
215 B: Into<Flags<T>>,
216{
217 fn bitor_assign(&mut self, rhs: B) {
218 *self = Flags::from_bits(self.bits() | rhs.into().bits())
219 }
220}
221
222impl<T, B> std::ops::BitAnd<B> for Flags<T>
223where
224 T: Flag,
225 B: Into<Flags<T>>,
226{
227 type Output = Flags<T>;
228 fn bitand(self, other: B) -> Flags<T> {
229 Flags::from_bits(self.bits() & other.into().bits())
230 }
231}
232
233impl<T, B> std::ops::BitAndAssign<B> for Flags<T>
234where
235 T: Flag,
236 B: Into<Flags<T>>,
237{
238 fn bitand_assign(&mut self, rhs: B) {
239 *self = Flags::from_bits(self.bits() & rhs.into().bits())
240 }
241}
242
243impl<T, B> std::ops::BitXor<B> for Flags<T>
244where
245 T: Flag,
246 B: Into<Flags<T>>,
247{
248 type Output = Flags<T>;
249 fn bitxor(self, other: B) -> Flags<T> {
250 Flags::from_bits(self.bits() ^ other.into().bits())
251 }
252}
253
254impl<T, B> std::ops::BitXorAssign<B> for Flags<T>
255where
256 T: Flag,
257 B: Into<Flags<T>>,
258{
259 fn bitxor_assign(&mut self, rhs: B) {
260 *self = Flags::from_bits(self.bits() ^ rhs.into().bits())
261 }
262}
263
264impl<T: Flag> std::ops::Not for Flags<T> {
265 type Output = Flags<T>;
266
267 fn not(self) -> Self::Output {
268 Flags::from_bits(!self.bits())
269 }
270}
271
272impl<T: Flag> std::fmt::Display for Flags<T> {
273 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
275 let none = self.bits() == T::none().bits();
276 let mut first = true;
277 for val in <T as Flag>::ITEMS
278 .iter()
279 .cloned()
280 .filter(move |&flag| self.contains(flag))
281 {
282 write!(f, "{}{:?}", if first { "" } else { " | " }, val)?;
283 first = false;
284
285 if none {
286 return Ok(());
287 }
288 }
289
290 if none {
291 write!(f, "NONE")?;
292 }
293
294 Ok(())
295 }
296}
297
298impl<T: Flag> std::fmt::Binary for Flags<T> {
299 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
300 std::fmt::Binary::fmt(&self.bits(), f)
301 }
302}
303
304pub mod example {
306 use super::*;
307
308 #[derive(Debug, Clone, Copy, PartialEq, Eq, BitFlags)]
310 #[repr(u8)]
311 pub enum Test {
312 A = 0b0001,
313 B = 0b0010,
314 C = 0b0100,
315 D = 0b1000,
316 E = Test::A as u8 | Test::B as u8 | Test::C as u8 | Test::D as u8,
318 }
319}
320
321#[cfg(test)]
322mod test {
323 use super::{example::*, *};
324
325 #[test]
326 fn test_enum_bits() {
327 let bits = 0b1010_1010;
328 let flags = Flags::<Test>::from_bits(bits);
329 assert_eq!(bits, flags.bits());
330 assert_eq!(&bits, flags.bits_ref());
331 }
332
333 #[test]
334 fn test_enum_or() {
335 let mut flags = Test::A | Test::B;
336 assert_eq!(0b0011, flags.bits());
337
338 flags |= Test::C;
339 assert_eq!(0b0111, flags.bits());
340
341 flags |= Test::C | Test::D;
342 assert_eq!(0b1111, flags.bits());
343 }
344
345 #[test]
346 fn test_enum_and() {
347 let mut flags = Test::E & Test::B;
348 assert_eq!(0b0010, flags.bits());
349
350 flags &= Test::B;
351 assert_eq!(0b0010, flags.bits());
352
353 flags &= Test::E & Test::B;
354 assert_eq!(0b0010, flags.bits());
355 }
356
357 #[test]
358 fn test_enum_xor() {
359 let mut flags = Test::A ^ Test::B;
360 assert_eq!(0b0011, flags.bits());
361
362 flags ^= Test::C;
363 assert_eq!(0b0111, flags.bits());
364
365 flags ^= Test::D ^ Test::B;
366 assert_eq!(0b1101, flags.bits());
367 }
368
369 #[test]
370 fn test_enum_not() {
371 let flags = !Test::A;
372 assert_eq!(0b1111_1110, flags.bits());
373 let flags = !(Test::A ^ Test::B);
374 assert_eq!(0b1111_1100, flags.bits());
375 }
376
377 #[test]
378 fn test_contains() {
379 let flags = Test::A | Test::C;
380 assert!(flags.contains(Test::A));
381 assert!(!flags.contains(Test::B));
382 assert!(!flags.contains(Test::E));
383 assert!(!flags.contains(Test::B | Test::D));
384 assert!(!flags.contains(Test::A | Test::B));
385 assert!(flags.contains(Test::A | Test::C));
386 }
387
388 #[test]
389 fn test_intersects() {
390 let flags = Test::A | Test::C;
391 assert!(flags.intersects(Test::A));
392 assert!(flags.intersects(Test::E));
393 assert!(flags.intersects(Test::A | Test::B));
394 assert!(flags.intersects(Test::A | Test::C));
395 assert!(flags.intersects(Test::A | Test::B | Test::C));
396 assert!(!flags.intersects(Test::B | Test::D));
397 }
398
399 #[test]
400 fn test_eq() {
401 let flags = Test::A;
402 assert_eq!(flags, Test::A);
403 assert_eq!(Test::A, flags);
404
405 let flags = Test::A | Test::C;
406 assert_ne!(flags, Test::A);
407 assert_ne!(flags, Test::C);
408 assert_ne!(Test::A, flags);
409 assert_eq!(flags, Test::A | Test::C);
410 assert_ne!(flags, Test::A | Test::C | Test::E);
411
412 let flags = Flags::<Test>::from_bits(0b1000_0001);
413 assert_ne!(flags, Test::A);
414 }
415
416 #[test]
417 fn test_enum_string() {
418 assert_eq!("NONE", Test::none().to_string());
419 assert_eq!("A", Test::A.to_string());
420 assert_eq!("A | B", (Test::A | Test::B).to_string());
421 assert_eq!("A | B | C | D | E", Test::E.to_string());
422 assert_eq!("A | B | C | D | E", Flags::from_flag(Test::E).to_string());
423 }
424
425 #[test]
426 fn test_enum_string_none() {
427 #[derive(Debug, Clone, Copy, PartialEq, Eq, BitFlags)]
428 #[repr(u8)]
429 pub enum Test {
430 Zero = 0b0000,
431 A = 0b0001,
432 B = 0b0010,
433 C = 0b0100,
434 D = 0b1000,
435 E = Test::A as u8 | Test::B as u8 | Test::C as u8 | Test::D as u8,
437 }
438 assert_eq!("Zero", Test::Zero.to_string());
439 assert_eq!("Zero", Test::none().to_string());
440 assert_eq!("Zero", Flags::from_flag(Test::Zero).to_string());
441 }
442
443 #[test]
444 fn test_enum_format() {
445 assert_eq!("A", format!("{:?}", Test::A));
446 assert_eq!("E", format!("{:?}", Test::E));
447 assert_eq!("0", format!("{:?}", Test::none()));
448
449 assert_eq!("0", format!("{:b}", Test::none()));
450 assert_eq!("1", format!("{:b}", Test::A));
451 assert_eq!("1111", format!("{:b}", Test::E));
452 }
453
454 #[test]
455 fn test_enum_from_str() {
456 use std::str::FromStr;
457 assert_eq!(Err(()), Test::from_str(""));
458 assert_eq!(Ok(Test::A), Test::from_str("a"));
459 assert_eq!(Ok(Test::A), Test::from_str("A"));
460 }
461
462 #[test]
463 fn test_all() {
464 assert_eq!(Test::E, Test::all());
465 assert!(!Flags::from_flag(Test::A).is_all());
466 assert!(Flags::from_flag(Test::E).is_all());
467 }
468
469 #[test]
470 fn test_none() {
471 assert_eq!(Flags::from_bits(0), Test::none());
472 assert!(Flags::<Test>::from_bits(0).is_empty());
473 assert!(!Flags::from_flag(Test::A).is_empty());
474 assert!(!Flags::from_flag(Test::E).is_empty());
475 }
476}