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