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(any(target_os = "linux", target_os = "android"))] 31 /// PROT_GROWSDOWN; 32 /// #[cfg(any(target_os = "linux", target_os = "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 $(#[$outer])* 67 pub struct $BitFlags: $T { 68 $( 69 $(#[$inner $($args)*])* 70 const $Flag = libc::$Flag $(as $cast)*; 71 )+ 72 } 73 } 74 }; 75 } 76 77 /// The `libc_enum!` macro helps with a common use case of defining an enum exclusively using 78 /// values from the `libc` crate. This macro supports both `pub` and private `enum`s. 79 /// 80 /// The `libc` crate must be in scope with the name `libc`. 81 /// 82 /// # Example 83 /// ```ignore 84 /// libc_enum!{ 85 /// pub enum ProtFlags { 86 /// PROT_NONE, 87 /// PROT_READ, 88 /// PROT_WRITE, 89 /// PROT_EXEC, 90 /// #[cfg(any(target_os = "linux", target_os = "android"))] 91 /// PROT_GROWSDOWN, 92 /// #[cfg(any(target_os = "linux", target_os = "android"))] 93 /// PROT_GROWSUP, 94 /// } 95 /// } 96 /// ``` 97 // Some targets don't use all rules. 98 #[allow(unknown_lints)] 99 #[allow(unused_macro_rules)] 100 macro_rules! libc_enum { 101 // Exit rule. 102 (@make_enum 103 name: $BitFlags:ident, 104 { 105 $v:vis 106 attrs: [$($attrs:tt)*], 107 entries: [$($entries:tt)*], 108 } 109 ) => { 110 $($attrs)* 111 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 112 $v enum $BitFlags { 113 $($entries)* 114 } 115 }; 116 117 // Exit rule including TryFrom 118 (@make_enum 119 name: $BitFlags:ident, 120 { 121 $v:vis 122 attrs: [$($attrs:tt)*], 123 entries: [$($entries:tt)*], 124 from_type: $repr:path, 125 try_froms: [$($try_froms:tt)*] 126 } 127 ) => { 128 $($attrs)* 129 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 130 $v enum $BitFlags { 131 $($entries)* 132 } 133 impl ::std::convert::TryFrom<$repr> for $BitFlags { 134 type Error = $crate::Error; 135 #[allow(unused_doc_comments)] 136 fn try_from(x: $repr) -> $crate::Result<Self> { 137 match x { 138 $($try_froms)* 139 _ => Err($crate::Error::EINVAL) 140 } 141 } 142 } 143 }; 144 145 // Done accumulating. 146 (@accumulate_entries 147 name: $BitFlags:ident, 148 { 149 $v:vis 150 attrs: $attrs:tt, 151 }, 152 $entries:tt, 153 $try_froms:tt; 154 ) => { 155 libc_enum! { 156 @make_enum 157 name: $BitFlags, 158 { 159 $v 160 attrs: $attrs, 161 entries: $entries, 162 } 163 } 164 }; 165 166 // Done accumulating and want TryFrom 167 (@accumulate_entries 168 name: $BitFlags:ident, 169 { 170 $v:vis 171 attrs: $attrs:tt, 172 from_type: $repr:path, 173 }, 174 $entries:tt, 175 $try_froms:tt; 176 ) => { 177 libc_enum! { 178 @make_enum 179 name: $BitFlags, 180 { 181 $v 182 attrs: $attrs, 183 entries: $entries, 184 from_type: $repr, 185 try_froms: $try_froms 186 } 187 } 188 }; 189 190 // Munch an attr. 191 (@accumulate_entries 192 name: $BitFlags:ident, 193 $prefix:tt, 194 [$($entries:tt)*], 195 [$($try_froms:tt)*]; 196 #[$attr:meta] $($tail:tt)* 197 ) => { 198 libc_enum! { 199 @accumulate_entries 200 name: $BitFlags, 201 $prefix, 202 [ 203 $($entries)* 204 #[$attr] 205 ], 206 [ 207 $($try_froms)* 208 #[$attr] 209 ]; 210 $($tail)* 211 } 212 }; 213 214 // Munch last ident if not followed by a comma. 215 (@accumulate_entries 216 name: $BitFlags:ident, 217 $prefix:tt, 218 [$($entries:tt)*], 219 [$($try_froms:tt)*]; 220 $entry:ident 221 ) => { 222 libc_enum! { 223 @accumulate_entries 224 name: $BitFlags, 225 $prefix, 226 [ 227 $($entries)* 228 $entry = libc::$entry, 229 ], 230 [ 231 $($try_froms)* 232 libc::$entry => Ok($BitFlags::$entry), 233 ]; 234 } 235 }; 236 237 // Munch an ident; covers terminating comma case. 238 (@accumulate_entries 239 name: $BitFlags:ident, 240 $prefix:tt, 241 [$($entries:tt)*], 242 [$($try_froms:tt)*]; 243 $entry:ident, 244 $($tail:tt)* 245 ) => { 246 libc_enum! { 247 @accumulate_entries 248 name: $BitFlags, 249 $prefix, 250 [ 251 $($entries)* 252 $entry = libc::$entry, 253 ], 254 [ 255 $($try_froms)* 256 libc::$entry => Ok($BitFlags::$entry), 257 ]; 258 $($tail)* 259 } 260 }; 261 262 // Munch an ident and cast it to the given type; covers terminating comma. 263 (@accumulate_entries 264 name: $BitFlags:ident, 265 $prefix:tt, 266 [$($entries:tt)*], 267 [$($try_froms:tt)*]; 268 $entry:ident as $ty:ty, 269 $($tail:tt)* 270 ) => { 271 libc_enum! { 272 @accumulate_entries 273 name: $BitFlags, 274 $prefix, 275 [ 276 $($entries)* 277 $entry = libc::$entry as $ty, 278 ], 279 [ 280 $($try_froms)* 281 libc::$entry as $ty => Ok($BitFlags::$entry), 282 ]; 283 $($tail)* 284 } 285 }; 286 287 // Entry rule. 288 ( 289 $(#[$attr:meta])* 290 $v:vis enum $BitFlags:ident { 291 $($vals:tt)* 292 } 293 ) => { 294 libc_enum! { 295 @accumulate_entries 296 name: $BitFlags, 297 { 298 $v 299 attrs: [$(#[$attr])*], 300 }, 301 [], 302 []; 303 $($vals)* 304 } 305 }; 306 307 // Entry rule including TryFrom 308 ( 309 $(#[$attr:meta])* 310 $v:vis enum $BitFlags:ident { 311 $($vals:tt)* 312 } 313 impl TryFrom<$repr:path> 314 ) => { 315 libc_enum! { 316 @accumulate_entries 317 name: $BitFlags, 318 { 319 $v 320 attrs: [$(#[$attr])*], 321 from_type: $repr, 322 }, 323 [], 324 []; 325 $($vals)* 326 } 327 }; 328 } 329