// Thanks to Tokio for this macro macro_rules! feature { ( #![$meta:meta] $($item:item)* ) => { $( #[cfg($meta)] #[cfg_attr(docsrs, doc(cfg($meta)))] $item )* } } /// The `libc_bitflags!` macro helps with a common use case of defining a public bitflags type /// with values from the libc crate. It is used the same way as the `bitflags!` macro, except /// that only the name of the flag value has to be given. /// /// The `libc` crate must be in scope with the name `libc`. /// /// # Example /// ```ignore /// libc_bitflags!{ /// pub struct ProtFlags: libc::c_int { /// PROT_NONE; /// PROT_READ; /// /// PROT_WRITE enables write protect /// PROT_WRITE; /// PROT_EXEC; /// #[cfg(any(target_os = "linux", target_os = "android"))] /// PROT_GROWSDOWN; /// #[cfg(any(target_os = "linux", target_os = "android"))] /// PROT_GROWSUP; /// } /// } /// ``` /// /// Example with casting, due to a mistake in libc. In this example, the /// various flags have different types, so we cast the broken ones to the right /// type. /// /// ```ignore /// libc_bitflags!{ /// pub struct SaFlags: libc::c_ulong { /// SA_NOCLDSTOP as libc::c_ulong; /// SA_NOCLDWAIT; /// SA_NODEFER as libc::c_ulong; /// SA_ONSTACK; /// SA_RESETHAND as libc::c_ulong; /// SA_RESTART as libc::c_ulong; /// SA_SIGINFO; /// } /// } /// ``` macro_rules! libc_bitflags { ( $(#[$outer:meta])* pub struct $BitFlags:ident: $T:ty { $( $(#[$inner:ident $($args:tt)*])* $Flag:ident $(as $cast:ty)*; )+ } ) => { ::bitflags::bitflags! { $(#[$outer])* pub struct $BitFlags: $T { $( $(#[$inner $($args)*])* const $Flag = libc::$Flag $(as $cast)*; )+ } } }; } /// The `libc_enum!` macro helps with a common use case of defining an enum exclusively using /// values from the `libc` crate. This macro supports both `pub` and private `enum`s. /// /// The `libc` crate must be in scope with the name `libc`. /// /// # Example /// ```ignore /// libc_enum!{ /// pub enum ProtFlags { /// PROT_NONE, /// PROT_READ, /// PROT_WRITE, /// PROT_EXEC, /// #[cfg(any(target_os = "linux", target_os = "android"))] /// PROT_GROWSDOWN, /// #[cfg(any(target_os = "linux", target_os = "android"))] /// PROT_GROWSUP, /// } /// } /// ``` // Some targets don't use all rules. #[allow(unknown_lints)] #[allow(unused_macro_rules)] macro_rules! libc_enum { // Exit rule. (@make_enum name: $BitFlags:ident, { $v:vis attrs: [$($attrs:tt)*], entries: [$($entries:tt)*], } ) => { $($attrs)* #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] $v enum $BitFlags { $($entries)* } }; // Exit rule including TryFrom (@make_enum name: $BitFlags:ident, { $v:vis attrs: [$($attrs:tt)*], entries: [$($entries:tt)*], from_type: $repr:path, try_froms: [$($try_froms:tt)*] } ) => { $($attrs)* #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] $v enum $BitFlags { $($entries)* } impl ::std::convert::TryFrom<$repr> for $BitFlags { type Error = $crate::Error; #[allow(unused_doc_comments)] fn try_from(x: $repr) -> $crate::Result { match x { $($try_froms)* _ => Err($crate::Error::EINVAL) } } } }; // Done accumulating. (@accumulate_entries name: $BitFlags:ident, { $v:vis attrs: $attrs:tt, }, $entries:tt, $try_froms:tt; ) => { libc_enum! { @make_enum name: $BitFlags, { $v attrs: $attrs, entries: $entries, } } }; // Done accumulating and want TryFrom (@accumulate_entries name: $BitFlags:ident, { $v:vis attrs: $attrs:tt, from_type: $repr:path, }, $entries:tt, $try_froms:tt; ) => { libc_enum! { @make_enum name: $BitFlags, { $v attrs: $attrs, entries: $entries, from_type: $repr, try_froms: $try_froms } } }; // Munch an attr. (@accumulate_entries name: $BitFlags:ident, $prefix:tt, [$($entries:tt)*], [$($try_froms:tt)*]; #[$attr:meta] $($tail:tt)* ) => { libc_enum! { @accumulate_entries name: $BitFlags, $prefix, [ $($entries)* #[$attr] ], [ $($try_froms)* #[$attr] ]; $($tail)* } }; // Munch last ident if not followed by a comma. (@accumulate_entries name: $BitFlags:ident, $prefix:tt, [$($entries:tt)*], [$($try_froms:tt)*]; $entry:ident ) => { libc_enum! { @accumulate_entries name: $BitFlags, $prefix, [ $($entries)* $entry = libc::$entry, ], [ $($try_froms)* libc::$entry => Ok($BitFlags::$entry), ]; } }; // Munch an ident; covers terminating comma case. (@accumulate_entries name: $BitFlags:ident, $prefix:tt, [$($entries:tt)*], [$($try_froms:tt)*]; $entry:ident, $($tail:tt)* ) => { libc_enum! { @accumulate_entries name: $BitFlags, $prefix, [ $($entries)* $entry = libc::$entry, ], [ $($try_froms)* libc::$entry => Ok($BitFlags::$entry), ]; $($tail)* } }; // Munch an ident and cast it to the given type; covers terminating comma. (@accumulate_entries name: $BitFlags:ident, $prefix:tt, [$($entries:tt)*], [$($try_froms:tt)*]; $entry:ident as $ty:ty, $($tail:tt)* ) => { libc_enum! { @accumulate_entries name: $BitFlags, $prefix, [ $($entries)* $entry = libc::$entry as $ty, ], [ $($try_froms)* libc::$entry as $ty => Ok($BitFlags::$entry), ]; $($tail)* } }; // Entry rule. ( $(#[$attr:meta])* $v:vis enum $BitFlags:ident { $($vals:tt)* } ) => { libc_enum! { @accumulate_entries name: $BitFlags, { $v attrs: [$(#[$attr])*], }, [], []; $($vals)* } }; // Entry rule including TryFrom ( $(#[$attr:meta])* $v:vis enum $BitFlags:ident { $($vals:tt)* } impl TryFrom<$repr:path> ) => { libc_enum! { @accumulate_entries name: $BitFlags, { $v attrs: [$(#[$attr])*], from_type: $repr, }, [], []; $($vals)* } }; }