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