kbvm 0.1.5

An implementation of the XKB specification
Documentation
#[cfg(test)]
mod tests;

pub(crate) trait FromBytes: Sized {
    fn from_bytes_dec(b: &[u8]) -> Option<Self>;

    fn from_bytes_hex(b: &[u8]) -> Option<Self>;

    fn from_bytes(b: &[u8], hex: bool) -> Option<Self> {
        match hex {
            true => Self::from_bytes_hex(b),
            false => Self::from_bytes_dec(b),
        }
    }
}

macro_rules! from_bytes {
    ($ty:ty, $signed:expr) => {
        impl FromBytes for $ty {
            fn from_bytes_dec(b: &[u8]) -> Option<Self> {
                if b.len() == 0 {
                    return None;
                }
                let mut res = 0 as $ty;
                for &c in b {
                    match c {
                        b'0'..=b'9' => res = res.checked_mul(10)?.checked_add((c - b'0') as $ty)?,
                        _ => return None,
                    }
                }
                Some(res)
            }

            fn from_bytes_hex(mut b: &[u8]) -> Option<Self> {
                if b.len() == 0 {
                    return None;
                }
                const MAX_BYTES: usize = <$ty>::BITS as usize / 8;
                const MAX_CHARS: usize = MAX_BYTES * 2;
                if b.len() > MAX_CHARS || ($signed && b.len() == MAX_CHARS) {
                    while b.len() > 0 && b[0] == b'0' {
                        b = &b[1..];
                    }
                    if b.len() > MAX_CHARS {
                        return None;
                    }
                    if $signed && b.len() == MAX_CHARS {
                        if matches!(b[0], b'8'..=b'9' | b'A'..=b'F' | b'a'..=b'f') {
                            return None;
                        }
                    }
                }
                let mut res = 0;
                for &c in b {
                    res = res << 4
                        | match c {
                        b'0'..=b'9' => c - b'0',
                        b'A'..=b'F' => c - b'A' + 10,
                        b'a'..=b'f' => c - b'a' + 10,
                        _ => return None,
                    } as $ty;
                }
                Some(res)
            }
        }
    };
}

from_bytes!(u32, false);
from_bytes!(i64, true);