1 // Thanks to Tokio for this macro 2 macro_rules! feature { 3 ( 4 #![$meta:meta] 5 $($item:item)* 6 ) => { 7 $( 8 #[cfg($meta)] 9 #[cfg_attr(docsrs, doc(cfg($meta)))] 10 $item 11 )* 12 } 13 } 14 15 /// The `libc_bitflags!` macro helps with a common use case of defining a public bitflags type 16 /// with values from the libc crate. It is used the same way as the `bitflags!` macro, except 17 /// that only the name of the flag value has to be given. 18 /// 19 /// The `libc` crate must be in scope with the name `libc`. 20 /// 21 /// # Example 22 /// ```ignore 23 /// libc_bitflags!{ 24 /// pub struct ProtFlags: libc::c_int { 25 /// PROT_NONE; 26 /// PROT_READ; 27 /// /// PROT_WRITE enables write protect 28 /// PROT_WRITE; 29 /// PROT_EXEC; 30 /// #[cfg(linux_android)] 31 /// PROT_GROWSDOWN; 32 /// #[cfg(linux_android)] 33 /// PROT_GROWSUP; 34 /// } 35 /// } 36 /// ``` 37 /// 38 /// Example with casting, due to a mistake in libc. In this example, the 39 /// various flags have different types, so we cast the broken ones to the right 40 /// type. 41 /// 42 /// ```ignore 43 /// libc_bitflags!{ 44 /// pub struct SaFlags: libc::c_ulong { 45 /// SA_NOCLDSTOP as libc::c_ulong; 46 /// SA_NOCLDWAIT; 47 /// SA_NODEFER as libc::c_ulong; 48 /// SA_ONSTACK; 49 /// SA_RESETHAND as libc::c_ulong; 50 /// SA_RESTART as libc::c_ulong; 51 /// SA_SIGINFO; 52 /// } 53 /// } 54 /// ``` 55 macro_rules! libc_bitflags { 56 ( 57 $(#[$outer:meta])* 58 pub struct $BitFlags:ident: $T:ty { 59 $( 60 $(#[$inner:ident $($args:tt)*])* 61 $Flag:ident $(as $cast:ty)*; 62 )+ 63 } 64 ) => { 65 ::bitflags::bitflags! { 66 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 67 #[repr(transparent)] 68 $(#[$outer])* 69 pub struct $BitFlags: $T { 70 $( 71 $(#[$inner $($args)*])* 72 const $Flag = libc::$Flag $(as $cast)*; 73 )+ 74 } 75 } 76 }; 77 } 78 79 /// The `libc_enum!` macro helps with a common use case of defining an enum exclusively using 80 /// values from the `libc` crate. This macro supports both `pub` and private `enum`s. 81 /// 82 /// The `libc` crate must be in scope with the name `libc`. 83 /// 84 /// # Example 85 /// ```ignore 86 /// libc_enum!{ 87 /// pub enum ProtFlags { 88 /// PROT_NONE, 89 /// PROT_READ, 90 /// PROT_WRITE, 91 /// PROT_EXEC, 92 /// #[cfg(linux_android)] 93 /// PROT_GROWSDOWN, 94 /// #[cfg(linux_android)] 95 /// PROT_GROWSUP, 96 /// } 97 /// } 98 /// ``` 99 // Some targets don't use all rules. 100 #[allow(unused_macro_rules)] 101 macro_rules! libc_enum { 102 // Exit rule. 103 (@make_enum 104 name: $BitFlags:ident, 105 { 106 $v:vis 107 attrs: [$($attrs:tt)*], 108 entries: [$($entries:tt)*], 109 } 110 ) => { 111 $($attrs)* 112 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 113 $v enum $BitFlags { 114 $($entries)* 115 } 116 }; 117 118 // Exit rule including TryFrom 119 (@make_enum 120 name: $BitFlags:ident, 121 { 122 $v:vis 123 attrs: [$($attrs:tt)*], 124 entries: [$($entries:tt)*], 125 from_type: $repr:path, 126 try_froms: [$($try_froms:tt)*] 127 } 128 ) => { 129 $($attrs)* 130 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 131 $v enum $BitFlags { 132 $($entries)* 133 } 134 impl ::std::convert::TryFrom<$repr> for $BitFlags { 135 type Error = $crate::Error; 136 #[allow(unused_doc_comments)] 137 #[allow(deprecated)] 138 #[allow(unused_attributes)] 139 fn try_from(x: $repr) -> $crate::Result<Self> { 140 match x { 141 $($try_froms)* 142 _ => Err($crate::Error::EINVAL) 143 } 144 } 145 } 146 }; 147 148 // Done accumulating. 149 (@accumulate_entries 150 name: $BitFlags:ident, 151 { 152 $v:vis 153 attrs: $attrs:tt, 154 }, 155 $entries:tt, 156 $try_froms:tt; 157 ) => { 158 libc_enum! { 159 @make_enum 160 name: $BitFlags, 161 { 162 $v 163 attrs: $attrs, 164 entries: $entries, 165 } 166 } 167 }; 168 169 // Done accumulating and want TryFrom 170 (@accumulate_entries 171 name: $BitFlags:ident, 172 { 173 $v:vis 174 attrs: $attrs:tt, 175 from_type: $repr:path, 176 }, 177 $entries:tt, 178 $try_froms:tt; 179 ) => { 180 libc_enum! { 181 @make_enum 182 name: $BitFlags, 183 { 184 $v 185 attrs: $attrs, 186 entries: $entries, 187 from_type: $repr, 188 try_froms: $try_froms 189 } 190 } 191 }; 192 193 // Munch an attr. 194 (@accumulate_entries 195 name: $BitFlags:ident, 196 $prefix:tt, 197 [$($entries:tt)*], 198 [$($try_froms:tt)*]; 199 #[$attr:meta] $($tail:tt)* 200 ) => { 201 libc_enum! { 202 @accumulate_entries 203 name: $BitFlags, 204 $prefix, 205 [ 206 $($entries)* 207 #[$attr] 208 ], 209 [ 210 $($try_froms)* 211 #[$attr] 212 ]; 213 $($tail)* 214 } 215 }; 216 217 // Munch last ident if not followed by a comma. 218 (@accumulate_entries 219 name: $BitFlags:ident, 220 $prefix:tt, 221 [$($entries:tt)*], 222 [$($try_froms:tt)*]; 223 $entry:ident 224 ) => { 225 libc_enum! { 226 @accumulate_entries 227 name: $BitFlags, 228 $prefix, 229 [ 230 $($entries)* 231 $entry = libc::$entry, 232 ], 233 [ 234 $($try_froms)* 235 libc::$entry => Ok($BitFlags::$entry), 236 ]; 237 } 238 }; 239 240 // Munch an ident; covers terminating comma case. 241 (@accumulate_entries 242 name: $BitFlags:ident, 243 $prefix:tt, 244 [$($entries:tt)*], 245 [$($try_froms:tt)*]; 246 $entry:ident, 247 $($tail:tt)* 248 ) => { 249 libc_enum! { 250 @accumulate_entries 251 name: $BitFlags, 252 $prefix, 253 [ 254 $($entries)* 255 $entry = libc::$entry, 256 ], 257 [ 258 $($try_froms)* 259 libc::$entry => Ok($BitFlags::$entry), 260 ]; 261 $($tail)* 262 } 263 }; 264 265 // Munch an ident and cast it to the given type; covers terminating comma. 266 (@accumulate_entries 267 name: $BitFlags:ident, 268 $prefix:tt, 269 [$($entries:tt)*], 270 [$($try_froms:tt)*]; 271 $entry:ident as $ty:ty, 272 $($tail:tt)* 273 ) => { 274 libc_enum! { 275 @accumulate_entries 276 name: $BitFlags, 277 $prefix, 278 [ 279 $($entries)* 280 $entry = libc::$entry as $ty, 281 ], 282 [ 283 $($try_froms)* 284 libc::$entry as $ty => Ok($BitFlags::$entry), 285 ]; 286 $($tail)* 287 } 288 }; 289 290 // Entry rule. 291 ( 292 $(#[$attr:meta])* 293 $v:vis enum $BitFlags:ident { 294 $($vals:tt)* 295 } 296 ) => { 297 libc_enum! { 298 @accumulate_entries 299 name: $BitFlags, 300 { 301 $v 302 attrs: [$(#[$attr])*], 303 }, 304 [], 305 []; 306 $($vals)* 307 } 308 }; 309 310 // Entry rule including TryFrom 311 ( 312 $(#[$attr:meta])* 313 $v:vis enum $BitFlags:ident { 314 $($vals:tt)* 315 } 316 impl TryFrom<$repr:path> 317 ) => { 318 libc_enum! { 319 @accumulate_entries 320 name: $BitFlags, 321 { 322 $v 323 attrs: [$(#[$attr])*], 324 from_type: $repr, 325 }, 326 [], 327 []; 328 $($vals)* 329 } 330 }; 331 } 332