infoterm 0.1.1

ncurses-compatible terminfo parsing library
Documentation
macro_rules! impl_enum {
    (
        $(#[$outer:meta])*
        $vis:vis enum $name:ident {
            $(
                $(#[$inner:meta])*
                $variant:ident => ($($str:expr),+)
            ),* $(,)?
        }
    ) => {
        $(#[$outer])*
        $vis enum $name {
            $(
                $(#[$inner])*
                $variant
            ),*
        }

        static INDEX_TO_NAME: &[(&str, &str)] = &[
            $(impl_enum!(@tuple $($str),+,)),*
        ];

        static NAME_TO_INDEX: ::phf::Map<&'static str, $name> = ::phf::phf_map! {
            $($($str => $name::$variant),+),*
        };

        impl $name {
            /// Returns the index of the capability `name` as an integer.
            ///
            /// # Panics
            ///
            /// This function panics if `name` does not match any capability.
            pub fn index(name: &str) -> usize {
                name.parse::<Self>().expect("provided string did not match any capability") as _
            }

            /// Returns `self` as an integer index.
            #[inline]
            pub fn to_index(self) -> usize {
                self as _
            }
        }

        impl ::std::fmt::Display for $name {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                let n = if f.alternate() {
                    INDEX_TO_NAME[*self as usize].1
                } else {
                    INDEX_TO_NAME[*self as usize].0
                };

                n.fmt(f)
            }
        }

        impl ::std::str::FromStr for $name {
            type Err = $crate::index::ParseCapabilityError;

            fn from_str(s: &str) -> Result<Self, Self::Err> {
                NAME_TO_INDEX
                    .get(s)
                    .copied()
                    .ok_or($crate::index::ParseCapabilityError)
            }
        }

        impl TryFrom<usize> for $name {
            type Error = $crate::index::IndexOutOfRangeError;

            fn try_from(value: usize) -> Result<Self, Self::Error> {
                if value < INDEX_TO_NAME.len() {
                    // SAFETY: All valid indices into INDEX_TO_NAME are valid discriminants of this enum.
                    Ok(unsafe { ::std::mem::transmute(value) })
                } else {
                    Err($crate::index::IndexOutOfRangeError)
                }
            }
        }

        impl From<$name> for usize {
            #[inline]
            fn from(value: $name) -> Self {
                value as usize
            }
        }
    };

    (@tuple $first:expr, $second:expr, $($rest:tt)*) => { ($first, $second) };
    (@tuple $first:expr, $($rest:tt)*) => { ($first, $first) };
}