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