1use core::any::type_name;
2use core::borrow::Borrow;
3use core::cmp::Ordering;
4use core::fmt;
5use core::hash::{Hash, Hasher};
6use core::iter::{FromIterator, IntoIterator};
7use core::marker::PhantomData;
8use core::ops::{
9 BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, Sub, SubAssign,
10};
11use core::str::FromStr;
12
13use crate::{BitFlag, BitFlagsIter, BitFlagsSpec, NameMatcher, util};
14
15#[repr(transparent)]
106pub struct BitFlags<T, U>(
107 T,
108 PhantomData<fn() -> *const U>,
112)
113where
114 U: ?Sized;
115
116#[cfg(feature = "serde")]
128struct BitFlagsVisitor<T, U>(PhantomData<T>, PhantomData<fn() -> *const U>)
129where
130 U: ?Sized;
131
132impl<T, U> BitFlags<T, U>
133where
134 U: ?Sized,
135{
136 #[inline]
140 #[must_use]
141 pub const fn empty() -> Self
142 where
143 T: util::IntOpsExt,
144 {
145 Self(T::ZERO, PhantomData)
146 }
147
148 #[doc(alias = "all")]
161 #[inline]
162 #[must_use]
163 pub const fn all_valid() -> Self
164 where
165 U: BitFlagsSpec<T>,
166 {
167 Self(U::VALID_BITS_MASK, PhantomData)
168 }
169
170 #[inline]
179 #[must_use]
180 pub const fn from_bits_retain(bits: T) -> Self {
181 Self(bits, PhantomData)
182 }
183
184 #[inline]
191 #[must_use]
192 pub const fn bits(&self) -> T
193 where
194 T: Copy,
195 {
196 self.0
197 }
198
199 #[inline]
205 #[must_use]
206 pub const fn bits_mut(&mut self) -> &mut T {
207 &mut self.0
208 }
209
210 #[inline]
219 #[must_use]
220 pub fn into_bits(self) -> T {
221 self.0
222 }
223
224 #[inline]
230 pub const fn iter(self) -> BitFlagsIter<T, U>
231 where
232 T: Copy + Not<Output = T> + BitAndAssign<T> + util::IntOpsExt,
233 {
234 BitFlagsIter::new(self)
235 }
236
237 #[inline]
257 pub fn try_from_str(
258 input: &str,
259 separator: &'static str,
260 name_matcher: NameMatcher,
261 ) -> Result<Self, BitFlagsParseError>
262 where
263 T: BitOrAssign<T> + util::IntOpsExt,
264 U: BitFlagsSpec<T>,
265 {
266 if input.trim().is_empty() {
267 return Ok(Self::empty());
268 }
269
270 let mut this = Self::empty();
271 let input = input.split(separator);
272 for input in input {
273 let input = input.trim();
274
275 let flag = BitFlag::from_name_opt(input, name_matcher);
276 if let Some(flag) = flag {
277 this |= flag;
278 continue;
279 }
280
281 if let Some(maybe_hex_flag) = input.strip_prefix("0x") {
282 if !maybe_hex_flag.starts_with('+') {
285 let bits = T::from_str_radix(maybe_hex_flag, 16);
286 if let Ok(bits) = bits {
287 this |= Self::from_bits_retain(bits);
288 continue;
289 }
290 }
291 }
292
293 #[cfg(feature = "alloc")]
294 let given = alloc::string::ToString::to_string(input);
295 #[cfg(not(feature = "alloc"))]
296 let given = ();
297 let expected = U::FLAG_NAMES;
298 return Err(BitFlagsParseError {
299 given,
300 separator,
301 expected,
302 });
303 }
304
305 Ok(this)
306 }
307}
308
309macro_rules! impl_bit_flags {
313 ($ty:ty) => {
314 impl<U> BitFlags<$ty, U>
315 where
316 U: ?Sized,
317 {
318 #[inline]
327 #[must_use]
328 pub const fn from_flag(flag: BitFlag<$ty, U>) -> Self {
329 Self::from_bit_retain(flag.bit())
330 }
331
332 #[inline]
344 #[must_use]
345 pub const fn from_bit_retain(bit: u8) -> Self {
346 #[expect(clippy::as_conversions, reason = "supported in const functions")]
347 let bit = bit as u32;
348 if bit < <$ty>::BITS {
349 Self::from_bits_retain(1 << bit)
350 } else {
351 Self::empty()
352 }
353 }
354
355 #[inline]
369 #[must_use]
370 pub const fn from_bit_truncate(bit: u8) -> Self
371 where
372 U: BitFlagsSpec<$ty>,
373 {
374 #[expect(clippy::as_conversions, reason = "supported in const functions")]
375 let bit = bit as u32;
376 if bit < <$ty>::BITS {
377 Self::from_bits_truncate(1 << bit)
378 } else {
379 Self::empty()
380 }
381 }
382
383 #[inline]
389 #[must_use]
390 pub const fn try_from_bit(bit: u8) -> Option<Self>
391 where
392 U: BitFlagsSpec<$ty>,
393 {
394 #[expect(clippy::as_conversions, reason = "supported in const functions")]
395 let bit = bit as u32;
396 if bit < <$ty>::BITS {
397 Self::try_from_bits(1 << bit)
398 } else {
399 None
400 }
401 }
402
403 #[doc(alias = "from_bits")]
411 #[inline]
412 #[must_use]
413 pub const fn try_from_bits(bits: $ty) -> Option<Self>
414 where
415 U: BitFlagsSpec<$ty>,
416 {
417 if bits & !U::VALID_BITS_MASK == 0 {
418 Some(Self(bits, PhantomData))
419 } else {
420 None
421 }
422 }
423
424 #[inline]
429 #[must_use]
430 pub const fn from_bits_truncate(bits: $ty) -> Self
431 where
432 U: BitFlagsSpec<$ty>,
433 {
434 Self(bits & U::VALID_BITS_MASK, PhantomData)
435 }
436
437 #[inline]
442 #[must_use]
443 pub const fn is_empty(&self) -> bool {
444 self.0 == 0
445 }
446
447 #[doc(alias = "is_all")]
458 #[inline]
459 #[must_use]
460 pub const fn is_valid(&self) -> bool
461 where
462 U: BitFlagsSpec<$ty>,
463 {
464 self.bits() & !U::VALID_BITS_MASK == 0
465 }
466
467 #[inline]
473 #[must_use]
474 pub const fn intersects(&self, other: Self) -> bool {
475 (self.0 & other.0) != 0
476 }
477
478 #[inline]
483 #[must_use]
484 pub const fn contains(&self, other: Self) -> bool {
485 (self.0 & other.0) == other.0
486 }
487
488 #[inline]
494 pub const fn insert(&mut self, other: Self) {
495 self.0 |= other.0;
496 }
497
498 #[inline]
502 pub const fn clear(&mut self) {
503 self.0 = 0;
504 }
505
506 #[inline]
512 pub const fn truncate(&mut self)
513 where
514 U: BitFlagsSpec<$ty>,
515 {
516 self.0 &= U::VALID_BITS_MASK
517 }
518
519 #[inline]
525 pub const fn remove(&mut self, other: Self) {
526 self.0 &= !other.0;
527 }
528
529 #[inline]
535 pub const fn toggle(&mut self, other: Self) {
536 self.0 ^= other.0;
537 }
538
539 #[inline]
545 pub const fn set(&mut self, other: Self, value: bool) {
546 if value {
547 self.insert(other)
548 } else {
549 self.remove(other)
550 }
551 }
552
553 #[inline]
559 #[must_use]
560 pub const fn intersection(self, other: Self) -> Self {
561 Self(self.0 & other.0, PhantomData)
562 }
563
564 #[inline]
569 #[must_use]
570 pub const fn union(self, other: Self) -> Self {
571 Self(self.0 | other.0, PhantomData)
572 }
573
574 #[inline]
582 #[must_use]
583 pub const fn difference(self, other: Self) -> Self {
584 Self(self.0 & !other.0, PhantomData)
585 }
586
587 #[inline]
594 #[must_use]
595 pub const fn symmetric_difference(self, other: Self) -> Self {
596 Self(self.0 ^ other.0, PhantomData)
597 }
598
599 #[inline]
605 #[must_use]
606 pub const fn complement(self) -> Self
607 where
608 U: BitFlagsSpec<$ty>,
609 {
610 Self(!self.0 & U::VALID_BITS_MASK, PhantomData)
611 }
612 }
613
614 impl<U> From<BitFlags<$ty, U>> for $ty
615 where
616 U: ?Sized,
617 {
618 #[inline]
619 fn from(flags: BitFlags<$ty, U>) -> Self {
620 flags.0
621 }
622 }
623 };
624}
625
626impl_bit_flags!(u8);
627impl_bit_flags!(u16);
628impl_bit_flags!(u32);
629impl_bit_flags!(u64);
630impl_bit_flags!(u128);
631impl_bit_flags!(usize);
632
633impl_bit_flags!(i8);
634impl_bit_flags!(i16);
635impl_bit_flags!(i32);
636impl_bit_flags!(i64);
637impl_bit_flags!(i128);
638impl_bit_flags!(isize);
639
640impl<T, U> Copy for BitFlags<T, U>
641where
642 T: Copy,
643 U: ?Sized,
644{
645}
646
647impl<T, U> Clone for BitFlags<T, U>
648where
649 T: Clone,
650 U: ?Sized,
651{
652 #[inline]
653 fn clone(&self) -> Self {
654 Self(self.0.clone(), PhantomData)
655 }
656}
657
658impl<T, U> Eq for BitFlags<T, U>
659where
660 T: Eq,
661 U: ?Sized,
662{
663}
664
665impl<T, U> PartialEq for BitFlags<T, U>
666where
667 T: PartialEq,
668 U: ?Sized,
669{
670 #[inline]
671 fn eq(&self, other: &Self) -> bool {
672 self.0 == other.0
673 }
674}
675
676impl<T, U> PartialEq<BitFlag<T, U>> for BitFlags<T, U>
677where
678 T: Copy + PartialEq + util::IntOpsExt,
679 U: ?Sized,
680{
681 #[inline]
682 fn eq(&self, other: &BitFlag<T, U>) -> bool {
683 self.eq(&Self::from(*other))
684 }
685}
686
687impl<T, U> PartialEq<BitFlags<T, U>> for BitFlag<T, U>
688where
689 T: Copy + PartialEq + util::IntOpsExt,
690 U: ?Sized,
691{
692 #[inline]
693 fn eq(&self, other: &BitFlags<T, U>) -> bool {
694 BitFlags::from(*self).eq(other)
695 }
696}
697
698impl<T, U> Ord for BitFlags<T, U>
699where
700 T: Ord,
701 U: ?Sized,
702{
703 #[inline]
704 fn cmp(&self, other: &Self) -> Ordering {
705 self.0.cmp(&other.0)
706 }
707}
708
709impl<T, U> PartialOrd for BitFlags<T, U>
710where
711 T: PartialOrd,
712 U: ?Sized,
713{
714 #[inline]
715 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
716 self.0.partial_cmp(&other.0)
717 }
718}
719
720impl<T, U> PartialOrd<BitFlag<T, U>> for BitFlags<T, U>
721where
722 T: Copy + PartialOrd + util::IntOpsExt,
723 U: ?Sized,
724{
725 #[inline]
726 fn partial_cmp(&self, other: &BitFlag<T, U>) -> Option<Ordering> {
727 self.partial_cmp(&Self::from(*other))
728 }
729}
730
731impl<T, U> PartialOrd<BitFlags<T, U>> for BitFlag<T, U>
732where
733 T: Copy + PartialOrd + util::IntOpsExt,
734 U: ?Sized,
735{
736 #[inline]
737 fn partial_cmp(&self, other: &BitFlags<T, U>) -> Option<Ordering> {
738 BitFlags::from(*self).partial_cmp(other)
739 }
740}
741
742impl<T, U> Hash for BitFlags<T, U>
743where
744 T: Hash,
745 U: ?Sized,
746{
747 #[inline]
748 fn hash<H: Hasher>(&self, state: &mut H) {
749 self.0.hash(state);
750 }
751}
752
753impl<T, U> Default for BitFlags<T, U>
754where
755 T: Default,
756 U: ?Sized,
757{
758 #[inline]
759 fn default() -> Self {
760 Self(T::default(), PhantomData)
761 }
762}
763
764impl<T, U> From<BitFlag<T, U>> for BitFlags<T, U>
765where
766 T: util::IntOpsExt,
767 U: ?Sized,
768{
769 #[inline]
770 fn from(flag: BitFlag<T, U>) -> Self {
771 let bit = flag.bit();
772 T::ONE
773 .checked_shl(u32::from(bit))
774 .map_or_else(Self::empty, Self::from_bits_retain)
775 }
776}
777
778impl<T, U> AsRef<T> for BitFlags<T, U>
779where
780 U: ?Sized,
781{
782 #[inline]
783 fn as_ref(&self) -> &T {
784 &self.0
785 }
786}
787
788impl<T, U> Borrow<T> for BitFlags<T, U>
789where
790 U: ?Sized,
791{
792 #[inline]
793 fn borrow(&self) -> &T {
794 &self.0
795 }
796}
797
798impl<T, U> BitAnd<Self> for BitFlags<T, U>
799where
800 T: BitAnd<T, Output = T>,
801 U: ?Sized,
802{
803 type Output = Self;
804
805 #[inline]
806 fn bitand(self, rhs: Self) -> Self::Output {
807 Self(self.0 & rhs.0, PhantomData)
808 }
809}
810
811impl<T, U> BitAnd<BitFlag<T, U>> for BitFlags<T, U>
812where
813 T: BitAnd<T, Output = T> + util::IntOpsExt,
814 U: ?Sized,
815{
816 type Output = Self;
817
818 #[inline]
819 fn bitand(self, rhs: BitFlag<T, U>) -> Self::Output {
820 self.bitand(Self::from(rhs))
821 }
822}
823
824impl<T, U> BitAnd<BitFlags<T, U>> for BitFlag<T, U>
825where
826 T: BitAnd<T, Output = T> + util::IntOpsExt,
827 U: ?Sized,
828{
829 type Output = BitFlags<T, U>;
830
831 #[inline]
832 fn bitand(self, rhs: BitFlags<T, U>) -> Self::Output {
833 BitFlags::from(self).bitand(rhs)
834 }
835}
836
837impl<T, U> BitAndAssign<Self> for BitFlags<T, U>
838where
839 T: BitAndAssign<T>,
840 U: ?Sized,
841{
842 #[inline]
843 fn bitand_assign(&mut self, rhs: Self) {
844 self.0 &= rhs.0;
845 }
846}
847
848impl<T, U> BitAndAssign<BitFlag<T, U>> for BitFlags<T, U>
849where
850 T: BitAndAssign<T> + util::IntOpsExt,
851 U: ?Sized,
852{
853 #[inline]
854 fn bitand_assign(&mut self, rhs: BitFlag<T, U>) {
855 self.bitand_assign(Self::from(rhs));
856 }
857}
858
859impl<T, U> BitOr<Self> for BitFlags<T, U>
860where
861 T: BitOr<T, Output = T>,
862 U: ?Sized,
863{
864 type Output = Self;
865
866 #[inline]
867 fn bitor(self, rhs: Self) -> Self::Output {
868 Self(self.0 | rhs.0, PhantomData)
869 }
870}
871
872impl<T, U> BitOr<BitFlag<T, U>> for BitFlags<T, U>
873where
874 T: BitOr<T, Output = T> + util::IntOpsExt,
875 U: ?Sized,
876{
877 type Output = Self;
878
879 #[inline]
880 fn bitor(self, rhs: BitFlag<T, U>) -> Self::Output {
881 self.bitor(Self::from(rhs))
882 }
883}
884
885impl<T, U> BitOr<BitFlags<T, U>> for BitFlag<T, U>
886where
887 T: BitOr<T, Output = T> + util::IntOpsExt,
888 U: ?Sized,
889{
890 type Output = BitFlags<T, U>;
891
892 #[inline]
893 fn bitor(self, rhs: BitFlags<T, U>) -> Self::Output {
894 BitFlags::from(self).bitor(rhs)
895 }
896}
897
898impl<T, U> BitOrAssign<Self> for BitFlags<T, U>
899where
900 T: BitOrAssign<T>,
901 U: ?Sized,
902{
903 #[inline]
904 fn bitor_assign(&mut self, rhs: Self) {
905 self.0 |= rhs.0;
906 }
907}
908
909impl<T, U> BitOrAssign<BitFlag<T, U>> for BitFlags<T, U>
910where
911 T: BitOrAssign<T> + util::IntOpsExt,
912 U: ?Sized,
913{
914 #[inline]
915 fn bitor_assign(&mut self, rhs: BitFlag<T, U>) {
916 self.bitor_assign(Self::from(rhs));
917 }
918}
919
920impl<T, U> BitXor<Self> for BitFlags<T, U>
921where
922 T: BitXor<T, Output = T>,
923 U: ?Sized,
924{
925 type Output = Self;
926
927 #[inline]
928 fn bitxor(self, rhs: Self) -> Self::Output {
929 Self(self.0 ^ rhs.0, PhantomData)
930 }
931}
932
933impl<T, U> BitXor<BitFlag<T, U>> for BitFlags<T, U>
934where
935 T: BitXor<T, Output = T> + util::IntOpsExt,
936 U: ?Sized,
937{
938 type Output = Self;
939
940 #[inline]
941 fn bitxor(self, rhs: BitFlag<T, U>) -> Self::Output {
942 self.bitxor(Self::from(rhs))
943 }
944}
945
946impl<T, U> BitXor<BitFlags<T, U>> for BitFlag<T, U>
947where
948 T: BitXor<T, Output = T> + util::IntOpsExt,
949 U: ?Sized,
950{
951 type Output = BitFlags<T, U>;
952
953 #[inline]
954 fn bitxor(self, rhs: BitFlags<T, U>) -> Self::Output {
955 BitFlags::from(self).bitxor(rhs)
956 }
957}
958
959impl<T, U> BitXorAssign<Self> for BitFlags<T, U>
960where
961 T: BitXorAssign<T>,
962 U: ?Sized,
963{
964 #[inline]
965 fn bitxor_assign(&mut self, rhs: Self) {
966 self.0 ^= rhs.0;
967 }
968}
969
970impl<T, U> BitXorAssign<BitFlag<T, U>> for BitFlags<T, U>
971where
972 T: BitXorAssign<T> + util::IntOpsExt,
973 U: ?Sized,
974{
975 #[inline]
976 fn bitxor_assign(&mut self, rhs: BitFlag<T, U>) {
977 self.bitxor_assign(Self::from(rhs));
978 }
979}
980
981impl<T, U> Sub<Self> for BitFlags<T, U>
982where
983 T: Not<Output = T> + BitAnd<T, Output = T>,
984 U: ?Sized,
985{
986 type Output = Self;
987
988 #[inline]
989 fn sub(self, rhs: Self) -> Self::Output {
990 Self(self.0 & !rhs.0, PhantomData)
991 }
992}
993
994impl<T, U> Sub<BitFlag<T, U>> for BitFlags<T, U>
995where
996 T: Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
997 U: ?Sized,
998{
999 type Output = Self;
1000
1001 #[inline]
1002 fn sub(self, rhs: BitFlag<T, U>) -> Self::Output {
1003 self.sub(Self::from(rhs))
1004 }
1005}
1006
1007impl<T, U> Sub<BitFlags<T, U>> for BitFlag<T, U>
1008where
1009 T: Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
1010 U: ?Sized,
1011{
1012 type Output = BitFlags<T, U>;
1013
1014 #[inline]
1015 fn sub(self, rhs: BitFlags<T, U>) -> Self::Output {
1016 BitFlags::from(self).sub(rhs)
1017 }
1018}
1019
1020impl<T, U> SubAssign<Self> for BitFlags<T, U>
1021where
1022 T: Not<Output = T> + BitAndAssign<T>,
1023 U: ?Sized,
1024{
1025 #[inline]
1026 fn sub_assign(&mut self, rhs: Self) {
1027 self.0 &= !rhs.0;
1028 }
1029}
1030
1031impl<T, U> SubAssign<BitFlag<T, U>> for BitFlags<T, U>
1032where
1033 T: Not<Output = T> + BitAndAssign<T> + util::IntOpsExt,
1034 U: ?Sized,
1035{
1036 #[inline]
1037 fn sub_assign(&mut self, rhs: BitFlag<T, U>) {
1038 self.sub_assign(Self::from(rhs));
1039 }
1040}
1041
1042impl<T, U> Not for BitFlags<T, U>
1043where
1044 T: Not<Output = T> + BitAnd<T, Output = T>,
1045 U: ?Sized + BitFlagsSpec<T>,
1046{
1047 type Output = Self;
1048
1049 #[inline]
1050 fn not(self) -> Self::Output {
1051 Self(!self.0 & U::VALID_BITS_MASK, PhantomData)
1052 }
1053}
1054
1055impl<T, U> fmt::Display for BitFlags<T, U>
1056where
1057 T: Copy
1058 + PartialEq
1059 + Not<Output = T>
1060 + BitAnd<T, Output = T>
1061 + Shl<usize, Output = T>
1062 + fmt::LowerHex
1063 + util::IntOpsExt,
1064 U: ?Sized + BitFlagsSpec<T>,
1065{
1066 #[expect(clippy::missing_inline_in_public_items, reason = "bloats binary size")]
1067 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1068 let mut separator = "";
1069 let mut this = self.0;
1070 for (i, names) in U::FLAG_NAMES.iter().enumerate() {
1071 let Some(i) = u32::try_from(i).ok() else {
1072 break; };
1074 let Some(mask) = T::ONE.checked_shl(i) else {
1075 break;
1076 };
1077 if let Some(name) = names.first() {
1078 let new_this = this & !mask;
1079 if this != new_this {
1080 write!(f, "{separator}{name}")?;
1081 separator = " | ";
1082 }
1083 this = new_this;
1084 }
1085 }
1086 if this != T::ZERO {
1087 write!(f, "{separator}{this:#x}")?;
1088 }
1089 Ok(())
1090 }
1091}
1092
1093impl<T, U> fmt::Debug for BitFlags<T, U>
1094where
1095 T: fmt::LowerHex,
1096 U: ?Sized,
1097{
1098 #[expect(clippy::missing_inline_in_public_items, reason = "bloats binary size")]
1099 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1100 write!(
1101 f,
1102 "BitFlags({:#x}, PhantomData<{}>)",
1103 self.0,
1104 type_name::<U>()
1105 )
1106 }
1107}
1108
1109impl<T, U> fmt::Binary for BitFlags<T, U>
1110where
1111 T: fmt::Binary,
1112 U: ?Sized,
1113{
1114 #[inline]
1115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1116 fmt::Binary::fmt(&self.0, f)
1117 }
1118}
1119
1120impl<T, U> fmt::Octal for BitFlags<T, U>
1121where
1122 T: fmt::Octal,
1123 U: ?Sized,
1124{
1125 #[inline]
1126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1127 fmt::Octal::fmt(&self.0, f)
1128 }
1129}
1130
1131impl<T, U> fmt::LowerHex for BitFlags<T, U>
1132where
1133 T: fmt::LowerHex,
1134 U: ?Sized,
1135{
1136 #[inline]
1137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1138 fmt::LowerHex::fmt(&self.0, f)
1139 }
1140}
1141
1142impl<T, U> fmt::UpperHex for BitFlags<T, U>
1143where
1144 T: fmt::UpperHex,
1145 U: ?Sized,
1146{
1147 #[inline]
1148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1149 fmt::UpperHex::fmt(&self.0, f)
1150 }
1151}
1152
1153impl<T, U> FromStr for BitFlags<T, U>
1154where
1155 T: BitOrAssign<T> + util::IntOpsExt,
1156 U: ?Sized + BitFlagsSpec<T>,
1157{
1158 type Err = BitFlagsParseError;
1159
1160 #[inline]
1161 fn from_str(input: &str) -> Result<Self, Self::Err> {
1162 Self::try_from_str(input, "|", U::DEFAULT_NAME_MATCHER)
1163 }
1164}
1165
1166impl<T, U> IntoIterator for BitFlags<T, U>
1167where
1168 T: Copy + Not<Output = T> + BitAndAssign<T> + util::IntOpsExt,
1169 U: ?Sized,
1170{
1171 type IntoIter = BitFlagsIter<T, U>;
1172 type Item = BitFlag<T, U>;
1173
1174 #[inline]
1175 fn into_iter(self) -> Self::IntoIter {
1176 BitFlagsIter::new(self)
1177 }
1178}
1179
1180impl<T, U> IntoIterator for &BitFlags<T, U>
1181where
1182 T: Copy + Not<Output = T> + BitAndAssign<T> + util::IntOpsExt,
1183 U: ?Sized,
1184{
1185 type IntoIter = BitFlagsIter<T, U>;
1186 type Item = BitFlag<T, U>;
1187
1188 #[inline]
1189 fn into_iter(self) -> Self::IntoIter {
1190 BitFlagsIter::new(*self)
1191 }
1192}
1193
1194#[expect(
1195 clippy::into_iter_without_iter,
1196 reason = "`iter` and `iter_mut` are the same"
1197)]
1198impl<T, U> IntoIterator for &mut BitFlags<T, U>
1199where
1200 T: Copy + Not<Output = T> + BitAndAssign<T> + util::IntOpsExt,
1201 U: ?Sized,
1202{
1203 type IntoIter = BitFlagsIter<T, U>;
1204 type Item = BitFlag<T, U>;
1205
1206 #[inline]
1207 fn into_iter(self) -> Self::IntoIter {
1208 BitFlagsIter::new(*self)
1209 }
1210}
1211
1212impl<T, U> Extend<Self> for BitFlags<T, U>
1213where
1214 T: BitOrAssign<T>,
1215 U: ?Sized,
1216{
1217 #[inline]
1218 fn extend<I>(&mut self, iter: I)
1219 where
1220 I: IntoIterator<Item = Self>,
1221 {
1222 for other in iter {
1223 self.0 |= other.0;
1224 }
1225 }
1226}
1227
1228impl<T, U> Extend<BitFlag<T, U>> for BitFlags<T, U>
1229where
1230 T: BitOrAssign<T> + util::IntOpsExt,
1231 U: ?Sized,
1232{
1233 #[inline]
1234 fn extend<I>(&mut self, iter: I)
1235 where
1236 I: IntoIterator<Item = BitFlag<T, U>>,
1237 {
1238 for other in iter {
1239 *self |= Self::from(other);
1240 }
1241 }
1242}
1243
1244impl<T, U> FromIterator<Self> for BitFlags<T, U>
1245where
1246 T: BitOrAssign<T> + util::IntOpsExt,
1247 U: ?Sized,
1248{
1249 #[inline]
1250 fn from_iter<I>(iter: I) -> Self
1251 where
1252 I: IntoIterator<Item = Self>,
1253 {
1254 let mut this = Self(T::ZERO, PhantomData);
1255 for other in iter {
1256 this.0 |= other.0;
1257 }
1258 this
1259 }
1260}
1261
1262impl<T, U> FromIterator<BitFlag<T, U>> for BitFlags<T, U>
1263where
1264 T: BitOrAssign<T> + util::IntOpsExt,
1265 U: ?Sized,
1266{
1267 #[inline]
1268 fn from_iter<I>(iter: I) -> Self
1269 where
1270 I: IntoIterator<Item = BitFlag<T, U>>,
1271 {
1272 let mut this = Self(T::ZERO, PhantomData);
1273 for other in iter {
1274 this |= Self::from(other);
1275 }
1276 this
1277 }
1278}
1279
1280#[cfg(feature = "arbitrary")]
1281#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
1282impl<'a, T, U> arbitrary::Arbitrary<'a> for BitFlags<T, U>
1283where
1284 T: arbitrary::Arbitrary<'a>,
1285 U: ?Sized,
1286{
1287 #[inline]
1288 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
1289 T::arbitrary(u).map(|u| Self(u, PhantomData))
1290 }
1291
1292 #[inline]
1293 fn size_hint(depth: usize) -> (usize, Option<usize>) {
1294 T::size_hint(depth)
1295 }
1296}
1297
1298#[cfg(feature = "bytemuck")]
1299#[cfg_attr(docsrs, doc(cfg(feature = "bytemuck")))]
1300unsafe impl<T, U> bytemuck::Zeroable for BitFlags<T, U>
1302where
1303 T: bytemuck::Zeroable,
1304 U: ?Sized,
1305{
1306}
1307
1308#[cfg(feature = "bytemuck")]
1309#[cfg_attr(docsrs, doc(cfg(feature = "bytemuck")))]
1310unsafe impl<T, U> bytemuck::Pod for BitFlags<T, U>
1313where
1314 T: bytemuck::Pod,
1315 U: 'static + ?Sized,
1316{
1317}
1318
1319#[cfg(feature = "serde")]
1320#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
1321impl<T, U> serde::Serialize for BitFlags<T, U>
1322where
1323 T: Copy
1324 + PartialEq
1325 + Not<Output = T>
1326 + BitAnd<T, Output = T>
1327 + Shl<usize, Output = T>
1328 + fmt::LowerHex
1329 + util::IntOpsExt,
1330 U: ?Sized + BitFlagsSpec<T>,
1331{
1332 #[inline]
1333 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1334 where
1335 S: serde::Serializer,
1336 {
1337 serializer.collect_str(&self)
1339 }
1340}
1341
1342#[cfg(feature = "serde")]
1343#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
1344impl<'de, T, U> serde::Deserialize<'de> for BitFlags<T, U>
1345where
1346 T: BitOrAssign<T> + util::IntOpsExt,
1347 U: ?Sized + BitFlagsSpec<T>,
1348{
1349 #[inline]
1350 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1351 where
1352 D: serde::Deserializer<'de>,
1353 {
1354 deserializer.deserialize_str(BitFlagsVisitor::<T, U>(PhantomData, PhantomData))
1355 }
1356}
1357
1358#[cfg(feature = "serde")]
1359#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
1360impl<T, U> serde::de::Visitor<'_> for BitFlagsVisitor<T, U>
1361where
1362 T: BitOrAssign<T> + util::IntOpsExt,
1363 U: ?Sized + BitFlagsSpec<T>,
1364{
1365 type Value = BitFlags<T, U>;
1366
1367 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1368 fmt_expected(f, "|", U::FLAG_NAMES)
1369 }
1370
1371 #[inline]
1372 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
1373 where
1374 E: serde::de::Error,
1375 {
1376 Self::Value::from_str(value).map_err(E::custom)
1377 }
1378}
1379
1380#[cfg_attr(
1382 not(feature = "alloc"),
1383 expect(
1384 missing_copy_implementations,
1385 reason = "the payload is feature-dependent"
1386 )
1387)]
1388#[derive(Clone, Debug)]
1389pub struct BitFlagsParseError {
1390 #[cfg(not(feature = "alloc"))]
1391 given: (),
1392 #[cfg(feature = "alloc")]
1393 given: alloc::string::String,
1394
1395 separator: &'static str,
1396 expected: &'static [&'static [&'static str]],
1397}
1398
1399impl fmt::Display for BitFlagsParseError {
1400 #[expect(clippy::missing_inline_in_public_items, reason = "bloats binary size")]
1401 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1402 let named_flags = self
1403 .expected
1404 .iter()
1405 .filter(|variants| !variants.is_empty())
1406 .count();
1407
1408 if named_flags == 0 {
1409 write!(f, "unrecognized hex flag, ")?;
1410 } else {
1411 write!(f, "unrecognized named flag or hex flag, ")?;
1412 }
1413 #[cfg(feature = "alloc")]
1414 write!(f, "given: \"{}\", expected ", self.given)?;
1415 #[cfg(not(feature = "alloc"))]
1416 write!(f, "expected ")?;
1417 fmt_expected(f, self.separator, self.expected)?;
1418
1419 #[cfg(not(feature = "alloc"))]
1420 let () = self.given;
1421
1422 Ok(())
1423 }
1424}
1425
1426impl core::error::Error for BitFlagsParseError {}
1427
1428#[inline]
1431fn fmt_expected(
1432 f: &mut fmt::Formatter<'_>,
1433 separator: &'static str,
1434 expected: &'static [&'static [&'static str]],
1435) -> fmt::Result {
1436 let named_flags = expected
1437 .iter()
1438 .filter(|variants| !variants.is_empty())
1439 .count();
1440
1441 if named_flags == 0 {
1442 write!(f, "a valid hex flag with \"0x\" prefix")?;
1443 } else {
1444 write!(f, "\"\", or a \"{separator}\"-separated set of")?;
1445
1446 let mut separator = " ";
1447 for names in expected {
1448 if let Some(name) = names.first() {
1449 write!(f, "{separator}\"{name}\"")?;
1450 separator = ", ";
1451 }
1452 }
1453 write!(f, ", or a valid hex flag with \"0x\" prefix")?;
1454 }
1455 Ok(())
1456}