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