fosk 0.1.6

In-memory SQL-like query engine and lightweight data store for testing and prototyping.
Documentation
use crate::parser::{ast::Literal, ParseError, QueryParser, WordComparer};

pub struct NumberParser;

impl NumberParser {
    pub fn is_number(parser: &QueryParser) -> bool {
        let current = parser.current();
        current.is_ascii_digit() || current == '+' || current == '-'
    }

    pub fn parse(parser: &mut QueryParser) -> Result<Literal, ParseError> {
        let pivot = parser.position;
        let mut is_float = false;

        if !NumberParser::is_number(parser) {
            return Err(ParseError::new("Invalid number value", pivot, parser));
        }

        while !parser.eof() && (NumberParser::is_number(parser) || parser.current() == '.') {
            if parser.current() == '.' {
                is_float = true;
            }
            parser.next();
        }

        if !parser.eof() && !WordComparer::is_any_delimiter(parser.current()) {
            return Err(ParseError::new("Invalid number value", pivot, parser));
        }

        let number = parser.text_from_pivot(pivot);
        let number = match is_float {
            true => Literal::Float(ordered_float::NotNan::new(
                number.parse::<f64>().map_err(|_| ParseError::new("Invalid number", pivot, parser))?
            ).map_err(|_| ParseError::new("Invalid number (NaN)", pivot, parser))?),
            false => Literal::Int(number.parse::<i64>().map_err(|_| ParseError::new("Invalid number", pivot, parser))?),
        };

        Ok(number)
    }
}

#[cfg(test)]
pub mod tests {
    use crate::parser::{ast::{Literal, NumberParser}, QueryParser};

    #[test]
    pub fn test_number_parser_int() {
        let text = "32";

        let mut parser = QueryParser::new(text);

        let result = NumberParser::parse(&mut parser);

        match result {
            Ok(result) => match result {
                Literal::Int(value) => assert_eq!(value, 32),
                _ => panic!(),
            },
            Err(_) => panic!(),
        }
    }

    #[test]
    pub fn test_number_parser_int_positive() {
        let text = "+32";

        let mut parser = QueryParser::new(text);

        let result = NumberParser::parse(&mut parser);

        match result {
            Ok(result) => match result {
                Literal::Int(value) => assert_eq!(value, 32),
                _ => panic!(),
            },
            Err(_) => panic!(),
        }
    }

    #[test]
    pub fn test_number_parser_int_negative() {
        let text = "-32";

        let mut parser = QueryParser::new(text);

        let result = NumberParser::parse(&mut parser);

        match result {
            Ok(result) => match result {
                Literal::Int(value) => assert_eq!(value, -32),
                _ => panic!(),
            },
            Err(_) => panic!(),
        }
    }

    #[test]
    pub fn test_number_parser_float() {
        let text = "32.";

        let mut parser = QueryParser::new(text);

        let result = NumberParser::parse(&mut parser);

        match result {
            Ok(result) => match result {
                Literal::Float(value) => assert_eq!(value.into_inner(), 32.0),
                _ => panic!(),
            },
            Err(_) => panic!(),
        }
    }

    #[test]
    pub fn test_number_parser_float_digit() {
        let text = "32.5";

        let mut parser = QueryParser::new(text);

        let result = NumberParser::parse(&mut parser);

        match result {
            Ok(result) => match result {
                Literal::Float(value) => assert_eq!(value.into_inner(), 32.5),
                _ => panic!(),
            },
            Err(_) => panic!(),
        }
    }

    #[test]
    pub fn test_number_parser_float_positive() {
        let text = "+32.5";

        let mut parser = QueryParser::new(text);

        let result = NumberParser::parse(&mut parser);

        match result {
            Ok(result) => match result {
                Literal::Float(value) => assert_eq!(value.into_inner(), 32.5),
                _ => panic!(),
            },
            Err(_) => panic!(),
        }
    }

    #[test]
    pub fn test_number_parser_float_negative() {
        let text = "-32.5";

        let mut parser = QueryParser::new(text);

        let result = NumberParser::parse(&mut parser);

        match result {
            Ok(result) => match result {
                Literal::Float(value) => assert_eq!(value.into_inner(), -32.5),
                _ => panic!(),
            },
            Err(_) => panic!(),
        }
    }

    #[test]
    pub fn test_number_parser_comma_delimiter() {
        let text = "32,";

        let mut parser = QueryParser::new(text);

        let result = NumberParser::parse(&mut parser);

        match result {
            Ok(result) => match result {
                Literal::Int(value) => assert_eq!(value, 32),
                _ => panic!(),
            },
            Err(_) => panic!(),
        }
    }

    #[test]
    pub fn test_number_parser_space_delimiter() {
        let text = "32 ";

        let mut parser = QueryParser::new(text);

        let result = NumberParser::parse(&mut parser);

        match result {
            Ok(result) => match result {
                Literal::Int(value) => assert_eq!(value, 32),
                _ => panic!(),
            },
            Err(_) => panic!(),
        }
    }

    #[test]
    pub fn test_number_parser_break_line() {
        let text = "32\r";

        let mut parser = QueryParser::new(text);

        let result = NumberParser::parse(&mut parser);

        match result {
            Ok(result) => match result {
                Literal::Int(value) => assert_eq!(value, 32),
                _ => panic!(),
            },
            Err(_) => panic!(),
        }
    }

    #[test]
    pub fn test_number_parser_wrong_value() {
        let text = "32a";

        let mut parser = QueryParser::new(text);

        let result = NumberParser::parse(&mut parser);

        match result {
            Ok(_) => panic!(),
            Err(err) => {
                assert_eq!(err.text, "32a");
                assert_eq!(err.start, 0);
                assert_eq!(err.end, 2);
            },
        }
    }
}