|
46 | 46 | //!
|
47 | 47 | //! - [`serde`](https://serde.rs/) implements `Serialize` and `Deserialize`
|
48 | 48 | //! for `BitFlags<T>`.
|
| 49 | +//! - [`zerocopy`](https://github.com/google/zerocopy/) implements `Immutable`, `IntoBytes`, |
| 50 | +//! `FromZeros`, `TryFromBytes`, and `KnownLayout` for all `BitFlags<T>` and `Unaligned` if the value type is unaligned. |
49 | 51 | //! - `std` implements `std::error::Error` for `FromBitsError`.
|
50 | 52 | //!
|
51 | 53 | //! ## `const fn`-compatible APIs
|
@@ -523,6 +525,14 @@ pub use crate::const_api::ConstToken;
|
523 | 525 | /// `BitFlags` value where that isn't the case is only possible with
|
524 | 526 | /// incorrect unsafe code.
|
525 | 527 | #[derive(Copy, Clone)]
|
| 528 | +#[cfg_attr( |
| 529 | + feature = "zerocopy", |
| 530 | + derive( |
| 531 | + zerocopy_derive::Immutable, |
| 532 | + zerocopy_derive::KnownLayout, |
| 533 | + zerocopy_derive::IntoBytes, |
| 534 | + ) |
| 535 | +)] |
526 | 536 | #[repr(transparent)]
|
527 | 537 | pub struct BitFlags<T, N = <T as _internal::RawBitFlags>::Numeric> {
|
528 | 538 | val: N,
|
@@ -1032,3 +1042,69 @@ mod impl_serde {
|
1032 | 1042 | }
|
1033 | 1043 | }
|
1034 | 1044 | }
|
| 1045 | + |
| 1046 | +#[cfg(feature = "zerocopy")] |
| 1047 | +mod impl_zerocopy { |
| 1048 | + use super::{BitFlag, BitFlags}; |
| 1049 | + use zerocopy::{FromZeros, Immutable, TryFromBytes, Unaligned}; |
| 1050 | + |
| 1051 | + // All zeros is always valid |
| 1052 | + unsafe impl<T> FromZeros for BitFlags<T> |
| 1053 | + where |
| 1054 | + T: BitFlag, |
| 1055 | + T::Numeric: Immutable, |
| 1056 | + T::Numeric: FromZeros, |
| 1057 | + { |
| 1058 | + fn only_derive_is_allowed_to_implement_this_trait() {} |
| 1059 | + } |
| 1060 | + |
| 1061 | + // Mark all BitFlags as Unaligned if the underlying number type is unaligned |
| 1062 | + unsafe impl<T> Unaligned for BitFlags<T> |
| 1063 | + where |
| 1064 | + T: BitFlag, |
| 1065 | + T::Numeric: Unaligned, |
| 1066 | + { |
| 1067 | + fn only_derive_is_allowed_to_implement_this_trait() {} |
| 1068 | + } |
| 1069 | + |
| 1070 | + // Assert that there are no invalid bytes set |
| 1071 | + unsafe impl<T> TryFromBytes for BitFlags<T> |
| 1072 | + where |
| 1073 | + T: BitFlag, |
| 1074 | + T::Numeric: Immutable, |
| 1075 | + T::Numeric: TryFromBytes, |
| 1076 | + { |
| 1077 | + fn only_derive_is_allowed_to_implement_this_trait() |
| 1078 | + where |
| 1079 | + Self: Sized, |
| 1080 | + { |
| 1081 | + } |
| 1082 | + |
| 1083 | + #[inline] |
| 1084 | + fn is_bit_valid< |
| 1085 | + ZerocopyAliasing: zerocopy::pointer::invariant::Aliasing |
| 1086 | + + zerocopy::pointer::invariant::AtLeast<zerocopy::pointer::invariant::Shared>, |
| 1087 | + >( |
| 1088 | + candidate: zerocopy::Maybe<'_, Self, ZerocopyAliasing>, |
| 1089 | + ) -> bool { |
| 1090 | + // SAFETY: |
| 1091 | + // - The cast preserves address. The caller has promised that the |
| 1092 | + // cast results in an object of equal or lesser size, and so the |
| 1093 | + // cast returns a pointer which references a subset of the bytes |
| 1094 | + // of `p`. |
| 1095 | + // - The cast preserves provenance. |
| 1096 | + // - The caller has promised that the destination type has |
| 1097 | + // `UnsafeCell`s at the same byte ranges as the source type. |
| 1098 | + let candidate = unsafe { candidate.cast_unsized::<T::Numeric, _>(|p| p as *mut _) }; |
| 1099 | + |
| 1100 | + // SAFETY: The caller has promised that the referenced memory region |
| 1101 | + // will contain a valid `$repr`. |
| 1102 | + let my_candidate = |
| 1103 | + unsafe { candidate.assume_validity::<zerocopy::pointer::invariant::Valid>() }; |
| 1104 | + { |
| 1105 | + (my_candidate.read_unaligned::<zerocopy::pointer::BecauseImmutable>() ^ T::ALL_BITS) |
| 1106 | + == T::EMPTY |
| 1107 | + } |
| 1108 | + } |
| 1109 | + } |
| 1110 | +} |
0 commit comments