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;
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                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}