1 //! Conditional trait implementations for external libraries.
2 
3 /*
4 How do I support a new external library?
5 
6 Let's say we want to add support for `my_library`.
7 
8 First, we create a module under `external`, like `serde` with any specialized code.
9 Ideally, any utilities in here should just work off the `Flags` trait and maybe a
10 few other assumed bounds.
11 
12 Next, re-export the library from the `__private` module here.
13 
14 Next, define a macro like so:
15 
16 ```rust
17 #[macro_export]
18 #[doc(hidden)]
19 #[cfg(feature = "serde")]
20 macro_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"))]
36 macro_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 
48 Note that the macro is actually defined twice; once for when the `my_library` feature
49 is available, and once for when it's not. This is because the `__impl_external_bitflags_my_library`
50 macro is called in an end-user's library, not in `bitflags`. In an end-user's library we don't
51 know whether or not a particular feature of `bitflags` is enabled, so we unconditionally call
52 the macro, where the body of that macro depends on the feature flag.
53 
54 Now, 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 
68 pub(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)]
82 macro_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")]
125 pub mod serde;
126 
127 /// Implement `Serialize` and `Deserialize` for the internal bitflags type.
128 #[macro_export]
129 #[doc(hidden)]
130 #[cfg(feature = "serde")]
131 macro_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"))]
167 macro_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")]
179 pub mod arbitrary;
180 
181 #[cfg(feature = "bytemuck")]
182 mod bytemuck;
183 
184 /// Implement `Arbitrary` for the internal bitflags type.
185 #[macro_export]
186 #[doc(hidden)]
187 #[cfg(feature = "arbitrary")]
188 macro_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"))]
210 macro_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")]
225 macro_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"))]
253 macro_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 }
263