| //! Conditional trait implementations for external libraries. |
| |
| /* |
| How do I support a new external library? |
| |
| Let's say we want to add support for `my_library`. |
| |
| First, we create a module under `external`, like `serde` with any specialized code. |
| Ideally, any utilities in here should just work off the `Flags` trait and maybe a |
| few other assumed bounds. |
| |
| Next, re-export the library from the `__private` module here. |
| |
| Next, define a macro like so: |
| |
| ```rust |
| #[macro_export] |
| #[doc(hidden)] |
| #[cfg(feature = "serde")] |
| macro_rules! __impl_external_bitflags_my_library { |
| ( |
| $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { |
| $( |
| $(#[$inner:ident $($args:tt)*])* |
| const $Flag:tt; |
| )* |
| } |
| ) => { |
| // Implementation goes here |
| }; |
| } |
| |
| #[macro_export] |
| #[doc(hidden)] |
| #[cfg(not(feature = "my_library"))] |
| macro_rules! __impl_external_bitflags_my_library { |
| ( |
| $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { |
| $( |
| $(#[$inner:ident $($args:tt)*])* |
| const $Flag:tt; |
| )* |
| } |
| ) => {}; |
| } |
| ``` |
| |
| Note that the macro is actually defined twice; once for when the `my_library` feature |
| is available, and once for when it's not. This is because the `__impl_external_bitflags_my_library` |
| macro is called in an end-user's library, not in `bitflags`. In an end-user's library we don't |
| know whether or not a particular feature of `bitflags` is enabled, so we unconditionally call |
| the macro, where the body of that macro depends on the feature flag. |
| |
| Now, we add our macro call to the `__impl_external_bitflags` macro body: |
| |
| ```rust |
| __impl_external_bitflags_my_library! { |
| $InternalBitFlags: $T, $PublicBitFlags { |
| $( |
| $(#[$inner $($args)*])* |
| const $Flag; |
| )* |
| } |
| } |
| ``` |
| */ |
| |
| pub(crate) mod __private { |
| #[cfg(feature = "serde")] |
| pub use serde; |
| |
| #[cfg(feature = "arbitrary")] |
| pub use arbitrary; |
| |
| #[cfg(feature = "bytemuck")] |
| pub use bytemuck; |
| } |
| |
| /// Implements traits from external libraries for the internal bitflags type. |
| #[macro_export] |
| #[doc(hidden)] |
| macro_rules! __impl_external_bitflags { |
| ( |
| $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { |
| $( |
| $(#[$inner:ident $($args:tt)*])* |
| const $Flag:tt; |
| )* |
| } |
| ) => { |
| // Any new library traits impls should be added here |
| // Use `serde` as an example: generate code when the feature is available, |
| // and a no-op when it isn't |
| |
| $crate::__impl_external_bitflags_serde! { |
| $InternalBitFlags: $T, $PublicBitFlags { |
| $( |
| $(#[$inner $($args)*])* |
| const $Flag; |
| )* |
| } |
| } |
| |
| $crate::__impl_external_bitflags_arbitrary! { |
| $InternalBitFlags: $T, $PublicBitFlags { |
| $( |
| $(#[$inner $($args)*])* |
| const $Flag; |
| )* |
| } |
| } |
| |
| $crate::__impl_external_bitflags_bytemuck! { |
| $InternalBitFlags: $T, $PublicBitFlags { |
| $( |
| $(#[$inner $($args)*])* |
| const $Flag; |
| )* |
| } |
| } |
| }; |
| } |
| |
| #[cfg(feature = "serde")] |
| pub mod serde; |
| |
| /// Implement `Serialize` and `Deserialize` for the internal bitflags type. |
| #[macro_export] |
| #[doc(hidden)] |
| #[cfg(feature = "serde")] |
| macro_rules! __impl_external_bitflags_serde { |
| ( |
| $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { |
| $( |
| $(#[$inner:ident $($args:tt)*])* |
| const $Flag:tt; |
| )* |
| } |
| ) => { |
| impl $crate::__private::serde::Serialize for $InternalBitFlags { |
| fn serialize<S: $crate::__private::serde::Serializer>( |
| &self, |
| serializer: S, |
| ) -> $crate::__private::core::result::Result<S::Ok, S::Error> { |
| $crate::serde::serialize( |
| &$PublicBitFlags::from_bits_retain(self.bits()), |
| serializer, |
| ) |
| } |
| } |
| |
| impl<'de> $crate::__private::serde::Deserialize<'de> for $InternalBitFlags { |
| fn deserialize<D: $crate::__private::serde::Deserializer<'de>>( |
| deserializer: D, |
| ) -> $crate::__private::core::result::Result<Self, D::Error> { |
| let flags: $PublicBitFlags = $crate::serde::deserialize(deserializer)?; |
| |
| Ok(flags.0) |
| } |
| } |
| }; |
| } |
| |
| #[macro_export] |
| #[doc(hidden)] |
| #[cfg(not(feature = "serde"))] |
| macro_rules! __impl_external_bitflags_serde { |
| ( |
| $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { |
| $( |
| $(#[$inner:ident $($args:tt)*])* |
| const $Flag:tt; |
| )* |
| } |
| ) => {}; |
| } |
| |
| #[cfg(feature = "arbitrary")] |
| pub mod arbitrary; |
| |
| #[cfg(feature = "bytemuck")] |
| mod bytemuck; |
| |
| /// Implement `Arbitrary` for the internal bitflags type. |
| #[macro_export] |
| #[doc(hidden)] |
| #[cfg(feature = "arbitrary")] |
| macro_rules! __impl_external_bitflags_arbitrary { |
| ( |
| $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { |
| $( |
| $(#[$inner:ident $($args:tt)*])* |
| const $Flag:tt; |
| )* |
| } |
| ) => { |
| impl<'a> $crate::__private::arbitrary::Arbitrary<'a> for $InternalBitFlags { |
| fn arbitrary( |
| u: &mut $crate::__private::arbitrary::Unstructured<'a>, |
| ) -> $crate::__private::arbitrary::Result<Self> { |
| $crate::arbitrary::arbitrary::<$PublicBitFlags>(u).map(|flags| flags.0) |
| } |
| } |
| }; |
| } |
| |
| #[macro_export] |
| #[doc(hidden)] |
| #[cfg(not(feature = "arbitrary"))] |
| macro_rules! __impl_external_bitflags_arbitrary { |
| ( |
| $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { |
| $( |
| $(#[$inner:ident $($args:tt)*])* |
| const $Flag:tt; |
| )* |
| } |
| ) => {}; |
| } |
| |
| /// Implement `Pod` and `Zeroable` for the internal bitflags type. |
| #[macro_export] |
| #[doc(hidden)] |
| #[cfg(feature = "bytemuck")] |
| macro_rules! __impl_external_bitflags_bytemuck { |
| ( |
| $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { |
| $( |
| $(#[$inner:ident $($args:tt)*])* |
| const $Flag:tt; |
| )* |
| } |
| ) => { |
| // SAFETY: $InternalBitFlags is guaranteed to have the same ABI as $T, |
| // and $T implements Pod |
| unsafe impl $crate::__private::bytemuck::Pod for $InternalBitFlags where |
| $T: $crate::__private::bytemuck::Pod |
| { |
| } |
| |
| // SAFETY: $InternalBitFlags is guaranteed to have the same ABI as $T, |
| // and $T implements Zeroable |
| unsafe impl $crate::__private::bytemuck::Zeroable for $InternalBitFlags where |
| $T: $crate::__private::bytemuck::Zeroable |
| { |
| } |
| }; |
| } |
| |
| #[macro_export] |
| #[doc(hidden)] |
| #[cfg(not(feature = "bytemuck"))] |
| macro_rules! __impl_external_bitflags_bytemuck { |
| ( |
| $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident { |
| $( |
| $(#[$inner:ident $($args:tt)*])* |
| const $Flag:tt; |
| )* |
| } |
| ) => {}; |
| } |