Revision control
Copy as Markdown
Other Tools
//! 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;
)*
}
) => {};
}