/// Create a C exportable enum. These are useful for working with C FFIs.
///
/// As C has no idea about tuples or structs enums
/// using this macro must only contain Unit variants.
#[macro_export]
macro_rules! c_enum
{
   {
      $(#[$attribute: meta])* enum $name: ident : $fieldType: ty
      {
         $(
            $(#[$variantAttribute: meta])*
            variant $variant: ident = $value: expr
         ),*
      }
   } =>
   {
      $(#[$attribute])*
      #[repr(C)]
      pub enum $name
      {
         $($(#[$variantAttribute])* $variant = $value,)*
      }

      impl $name
      {
         /// Generate a variant of the enum from a given value.
         ///
         /// This is not very performant. Becareful when using this
         /// to not use this in a high performance loop.
         pub fn from_value(val: $fieldType) -> Option<$name>
         {
            // This would be better as a match statement, but
            // unfortunately, it needs to be a giant set of if
            // statements since we only have the expression type
            // to work with, not a pattern type.
            /*
            match val
            {
               $($value => {Some($name::$variant)})*

               _ => {None}
            }
            */
            $(if val == $value {return Some($name::$variant);})*

            // No variant was found.
            None
         }

         /// 'true', if the given value matches a variant
         /// of the enumeration; Otherwise, 'false'.
         pub fn is_valid_value(val: $fieldType) -> bool
         {
            match $name::from_value(val)
            {
               Some(_) =>
               {
                  true
               }

               None =>
               {
                  false
               }
            }
         }

         /// Turn an enum variant into a value.
         pub fn to_value(&self) -> $fieldType
         {
            match *self
            {
               $($name::$variant => {$value})*
            }
         }

         /// Get a str representation of this variant.
         pub fn to_str(&self) -> &'static str
         {
            match *self
            {
               $($name::$variant => {stringify!($variant)})*
            }
         }
      }

      impl ::std::fmt::Debug for $name
      {
         fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
         {
            write!(f, "{}", self.to_str())
         }
      }

      impl ::std::fmt::Display for $name
      {
         fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
         {
            write!(f, "{}", self.to_str())
         }
      }
   }
}