muesli 0.1.0

healthy implementation of PHP's serialization and session formats in Rust
Documentation
use winnow::{
    binary::length_take,
    combinator::{opt, terminated},
    token::take_while,
    Parser, Result,
};

pub(crate) fn unsigned_integer<'s>(input: &mut &'s [u8]) -> Result<&'s [u8]> {
    take_while(1.., b'0'..=b'9').parse_next(input)
}

pub(crate) fn signed_integer<'s>(input: &mut &'s [u8]) -> Result<&'s [u8]> {
    (opt(b'-'), unsigned_integer).take().parse_next(input)
}

pub(crate) fn float<'s>(input: &mut &'s [u8]) -> Result<&'s [u8]> {
    (signed_integer, opt((b'.', unsigned_integer)))
        .take()
        .parse_next(input)
}

pub(crate) fn size(input: &mut &[u8]) -> Result<usize> {
    unsigned_integer.parse_to().parse_next(input)
}

pub(crate) fn sized_string<'s>(input: &mut &'s [u8]) -> Result<&'s [u8]> {
    terminated(length_take(terminated(size, b":\"")), b'"').parse_next(input)
}

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

    #[test]
    fn parse_unsigned_integer() {
        let cases = [
            (b"0".as_slice(), Some((b"".as_slice(), b"0".as_slice()))),
            (b"123".as_slice(), Some((b"".as_slice(), b"123".as_slice()))),
            (
                b"745a".as_slice(),
                Some((b"a".as_slice(), b"745".as_slice())),
            ),
            (
                b"592.6".as_slice(),
                Some((b".6".as_slice(), b"592".as_slice())),
            ),
            (b"".as_slice(), None),
            (b"a".as_slice(), None),
            (b"-123".as_slice(), None),
        ];

        run_cases(unsigned_integer, &cases);
    }

    #[test]
    fn parse_signed_integer() {
        let cases = [
            (b"-0".as_slice(), Some((b"".as_slice(), b"-0".as_slice()))),
            (b"123".as_slice(), Some((b"".as_slice(), b"123".as_slice()))),
            (
                b"745a".as_slice(),
                Some((b"a".as_slice(), b"745".as_slice())),
            ),
            (
                b"592.6".as_slice(),
                Some((b".6".as_slice(), b"592".as_slice())),
            ),
            (
                b"-592.6".as_slice(),
                Some((b".6".as_slice(), b"-592".as_slice())),
            ),
            (b"".as_slice(), None),
            (b"a".as_slice(), None),
        ];

        run_cases(signed_integer, &cases);
    }

    #[test]
    fn parse_float() {
        let cases = [
            (b"-0".as_slice(), Some((b"".as_slice(), b"-0".as_slice()))),
            (b"123".as_slice(), Some((b"".as_slice(), b"123".as_slice()))),
            (
                b"745a".as_slice(),
                Some((b"a".as_slice(), b"745".as_slice())),
            ),
            (
                b"592.6".as_slice(),
                Some((b"".as_slice(), b"592.6".as_slice())),
            ),
            (
                b"-592.6".as_slice(),
                Some((b"".as_slice(), b"-592.6".as_slice())),
            ),
            (b"".as_slice(), None),
            (b"a".as_slice(), None),
        ];

        run_cases(float, &cases);
    }

    #[test]
    fn parse_size() {
        let cases = [
            (b"1".as_slice(), Some((b"".as_slice(), 1))),
            (
                b"1234567890".as_slice(),
                Some((b"".as_slice(), 1_234_567_890)),
            ),
            (b"323;".as_slice(), Some((b";".as_slice(), 323))),
            (b"".as_slice(), None),
            (b"a".as_slice(), None),
            (b"a:\"asd\"".as_slice(), None),
            (b"-2:\"asd\"".as_slice(), None),
        ];

        run_cases(size, &cases);
    }

    #[test]
    fn parse_sized_string() {
        let cases = [
            (
                b"1:\"a\"".as_slice(),
                Some((b"".as_slice(), b"a".as_slice())),
            ),
            (
                b"10:\"1234567890\"".as_slice(),
                Some((b"".as_slice(), b"1234567890".as_slice())),
            ),
            (b"".as_slice(), None),
            (b"a".as_slice(), None),
            (b"a:\"asd\"".as_slice(), None),
            (b"-2:\"asd\"".as_slice(), None),
        ];

        run_cases(sized_string, &cases);
    }
}