clex 0.1.0

Fast C-lang lexer (library)
Documentation
pub trait Int: Sized {
    fn int_from_str(text: &str, radix: u32) -> Option<Self>;
}

macro_rules! int_impl {
    ($($(#[$meta:meta])* $type:ty;)*) => {
        $(
            $(#[$meta])*
            impl Int for $type {
                fn int_from_str(text: &str, radix: u32) -> Option<Self> {
                    <$type>::from_str_radix(text, radix).ok()
                }
            }
        )*
    };
}

int_impl! {
    u8;
    i8;
    u16;
    i16;
    u32;
    i32;
    u64;
    i64;
    u128;
    i128;
    #[cfg(feature = "ethnum")]
    ethnum::u256;
    #[cfg(feature = "ethnum")]
    ethnum::i256;
}

fn is_int_suffix(c: char) -> bool {
    matches!(c, 'u' | 'U' | 'l' | 'L')
}

pub fn extract<T: Int>(text: &str) -> Option<T> {
    let text = text.trim_end_matches(is_int_suffix);
    let (text, radix) = text
        .strip_prefix("0x")
        .map(|text| (text, 16))
        .or_else(|| text.strip_prefix("0X").map(|text| (text, 16)))
        .or_else(|| text.strip_prefix("0b").map(|text| (text, 2)))
        .or_else(|| text.strip_prefix("0B").map(|text| (text, 2)))
        .or_else(|| {
            if text != "0" {
                text.strip_prefix('0').map(|text| (text, 8))
            } else {
                None
            }
        })
        .unwrap_or((text, 10));
    T::int_from_str(text, radix)
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn not_a() {
        assert!(extract::<u8>("a").is_none());
        assert!(extract::<u16>("-").is_none());
        assert!(extract::<i32>("").is_none());
    }

    #[test]
    fn decimal() {
        assert_eq!(extract::<u8>("123"), Some(123));
        assert_eq!(extract::<i8>("123"), Some(123));
        assert_eq!(extract::<u32>("123"), Some(123));
        assert_eq!(extract::<i32>("123"), Some(123));
    }

    #[test]
    fn suffixed() {
        assert_eq!(extract::<u8>("12l"), Some(12));
        assert_eq!(extract::<u16>("12L"), Some(12));
        assert_eq!(extract::<i32>("12ll"), Some(12));
        assert_eq!(extract::<u128>("12ul"), Some(12));
        assert_eq!(extract::<u8>("12ull"), Some(12));
    }

    #[test]
    fn octal() {
        assert_eq!(extract::<i8>("07"), Some(7));
        assert_eq!(extract::<u8>("0127"), Some(0o127));
    }

    #[test]
    fn hexadecimal() {
        assert_eq!(extract::<i8>("0x0"), Some(0));
        assert_eq!(extract::<u16>("0X1a9b"), Some(0x1a9b));
    }

    #[test]
    fn binary() {
        assert_eq!(extract::<i8>("0b0"), Some(0));
        assert_eq!(extract::<u16>("0B1011"), Some(0b1011));
    }

    #[cfg(feature = "ethnum")]
    #[test]
    fn ethnum() {
        use ethnum::{AsI256, AsU256};

        assert_eq!(
            extract::<ethnum::u256>("0xffffff00000000000000000000000000"),
            Some(0xffffff00000000000000000000000000u128.as_u256())
        );
        assert_eq!(
            extract::<ethnum::i256>("0Xffffff00000000000000000000000000u"),
            Some(0xffffff00000000000000000000000000u128.as_i256())
        );
    }
}