#
bitflags/
external.rs

    1//! Conditional trait implementations for external libraries.
    2
    3/*
    4How do I support a new external library?
    5
    6Let's say we want to add support for `my_library`.
    7
    8First, we create a module under `external`, like `serde` with any specialized code.
    9Ideally, any utilities in here should just work off the `Flags` trait and maybe a
    10few other assumed bounds.
    11
    12Next, re-export the library from the `__private` module here.
    13
    14Next, define a macro like so:
    15
    16```rust
    17#[macro_export]
    18#[doc(hidden)]
    19#[cfg(feature = "serde")]
    20macro_rules! __impl_external_bitflags_my_library {
    21    (
    22        $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
    23            $(
    24                $(#[$inner:ident $($args:tt)*])*
    25                const $Flag:tt;
    26            )*
    27        }
    28    ) => {
    29        // Implementation goes here
    30    };
    31}
    32
    33#[macro_export]
    34#[doc(hidden)]
    35#[cfg(not(feature = "my_library"))]
    36macro_rules! __impl_external_bitflags_my_library {
    37    (
    38        $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
    39            $(
    40                $(#[$inner:ident $($args:tt)*])*
    41                const $Flag:tt;
    42            )*
    43        }
    44    ) => {};
    45}
    46```
    47
    48Note that the macro is actually defined twice; once for when the `my_library` feature
    49is available, and once for when it's not. This is because the `__impl_external_bitflags_my_library`
    50macro is called in an end-user's library, not in `bitflags`. In an end-user's library we don't
    51know whether or not a particular feature of `bitflags` is enabled, so we unconditionally call
    52the macro, where the body of that macro depends on the feature flag.
    53
    54Now, we add our macro call to the `__impl_external_bitflags` macro body:
    55
    56```rust
    57__impl_external_bitflags_my_library! {
    58    $InternalBitFlags: $T, $PublicBitFlags {
    59        $(
    60            $(#[$inner $($args)*])*
    61            const $Flag;
    62        )*
    63    }
    64}
    65```
    66*/
    67
    68pub(crate) mod __private {
    69    #[cfg(feature = "serde")]
    70    pub use serde_core as serde;
    71
    72    #[cfg(feature = "arbitrary")]
    73    pub use arbitrary;
    74
    75    #[cfg(feature = "bytemuck")]
    76    pub use bytemuck;
    77}
    78
    79/// Implements traits from external libraries for the internal bitflags type.
    80#[macro_export]
    81#[doc(hidden)]
    82macro_rules! __impl_external_bitflags {
    83    (
    84        $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
    85            $(
    86                $(#[$inner:ident $($args:tt)*])*
    87                const $Flag:tt;
    88            )*
    89        }
    90    ) => {
    91        // Any new library traits impls should be added here
    92        // Use `serde` as an example: generate code when the feature is available,
    93        // and a no-op when it isn't
    94
    95        $crate::__impl_external_bitflags_serde! {
    96            $InternalBitFlags: $T, $PublicBitFlags {
    97                $(
    98                    $(#[$inner $($args)*])*
    99                    const $Flag;
    100                )*
    101            }
    102        }
    103
    104        $crate::__impl_external_bitflags_arbitrary! {
    105            $InternalBitFlags: $T, $PublicBitFlags {
    106                $(
    107                    $(#[$inner $($args)*])*
    108                    const $Flag;
    109                )*
    110            }
    111        }
    112
    113        $crate::__impl_external_bitflags_bytemuck! {
    114            $InternalBitFlags: $T, $PublicBitFlags {
    115                $(
    116                    $(#[$inner $($args)*])*
    117                    const $Flag;
    118                )*
    119            }
    120        }
    121    };
    122}
    123
    124#[cfg(feature = "serde")]
    125pub mod serde;
    126
    127/// Implement `Serialize` and `Deserialize` for the internal bitflags type.
    128#[macro_export]
    129#[doc(hidden)]
    130#[cfg(feature = "serde")]
    131macro_rules! __impl_external_bitflags_serde {
    132    (
    133        $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
    134            $(
    135                $(#[$inner:ident $($args:tt)*])*
    136                const $Flag:tt;
    137            )*
    138        }
    139    ) => {
    140        impl $crate::__private::serde::Serialize for $InternalBitFlags {
    141            fn serialize<S: $crate::__private::serde::Serializer>(
    142                &self,
    143                serializer: S,
    144            ) -> $crate::__private::core::result::Result<S::Ok, S::Error> {
    145                $crate::serde::serialize(
    146                    &$PublicBitFlags::from_bits_retain(self.bits()),
    147                    serializer,
    148                )
    149            }
    150        }
    151
    152        impl<'de> $crate::__private::serde::Deserialize<'de> for $InternalBitFlags {
    153            fn deserialize<D: $crate::__private::serde::Deserializer<'de>>(
    154                deserializer: D,
    155            ) -> $crate::__private::core::result::Result<Self, D::Error> {
    156                let flags: $PublicBitFlags = $crate::serde::deserialize(deserializer)?;
    157
    158                $crate::__private::core::result::Result::Ok(flags.0)
    159            }
    160        }
    161    };
    162}
    163
    164#[macro_export]
    165#[doc(hidden)]
    166#[cfg(not(feature = "serde"))]
    167macro_rules! __impl_external_bitflags_serde {
    168    (
    169        $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
    170            $(
    171                $(#[$inner:ident $($args:tt)*])*
    172                const $Flag:tt;
    173            )*
    174        }
    175    ) => {};
    176}
    177
    178#[cfg(feature = "arbitrary")]
    179pub mod arbitrary;
    180
    181#[cfg(feature = "bytemuck")]
    182mod bytemuck;
    183
    184/// Implement `Arbitrary` for the internal bitflags type.
    185#[macro_export]
    186#[doc(hidden)]
    187#[cfg(feature = "arbitrary")]
    188macro_rules! __impl_external_bitflags_arbitrary {
    189    (
    190            $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
    191                $(
    192                    $(#[$inner:ident $($args:tt)*])*
    193                    const $Flag:tt;
    194                )*
    195            }
    196    ) => {
    197        impl<'a> $crate::__private::arbitrary::Arbitrary<'a> for $InternalBitFlags {
    198            fn arbitrary(
    199                u: &mut $crate::__private::arbitrary::Unstructured<'a>,
    200            ) -> $crate::__private::arbitrary::Result<Self> {
    201                $crate::arbitrary::arbitrary::<$PublicBitFlags>(u).map(|flags| flags.0)
    202            }
    203        }
    204    };
    205}
    206
    207#[macro_export]
    208#[doc(hidden)]
    209#[cfg(not(feature = "arbitrary"))]
    210macro_rules! __impl_external_bitflags_arbitrary {
    211    (
    212        $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
    213            $(
    214                $(#[$inner:ident $($args:tt)*])*
    215                const $Flag:tt;
    216            )*
    217        }
    218    ) => {};
    219}
    220
    221/// Implement `Pod` and `Zeroable` for the internal bitflags type.
    222#[macro_export]
    223#[doc(hidden)]
    224#[cfg(feature = "bytemuck")]
    225macro_rules! __impl_external_bitflags_bytemuck {
    226    (
    227        $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
    228            $(
    229                $(#[$inner:ident $($args:tt)*])*
    230                const $Flag:tt;
    231            )*
    232        }
    233    ) => {
    234        // SAFETY: $InternalBitFlags is guaranteed to have the same ABI as $T,
    235        // and $T implements Pod
    236        unsafe impl $crate::__private::bytemuck::Pod for $InternalBitFlags where
    237            $T: $crate::__private::bytemuck::Pod
    238        {
    239        }
    240
    241        // SAFETY: $InternalBitFlags is guaranteed to have the same ABI as $T,
    242        // and $T implements Zeroable
    243        unsafe impl $crate::__private::bytemuck::Zeroable for $InternalBitFlags where
    244            $T: $crate::__private::bytemuck::Zeroable
    245        {
    246        }
    247    };
    248}
    249
    250#[macro_export]
    251#[doc(hidden)]
    252#[cfg(not(feature = "bytemuck"))]
    253macro_rules! __impl_external_bitflags_bytemuck {
    254    (
    255        $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
    256            $(
    257                $(#[$inner:ident $($args:tt)*])*
    258                const $Flag:tt;
    259            )*
    260        }
    261    ) => {};
    262}