oneline-template 0.1.0

Library for serialization structures in one-line string. Helpful for path formatting.
Documentation
use std::str::FromStr;
use crate::template::syntax::unexpected_input_error::UnexpectedInputError;
use crate::template::syntax::syntax_parse_error::SyntaxParseError;
use crate::template::syntax::invalid_argument_template::InvalidArgumentTemplate;

#[derive(Debug)]
pub enum FunctionCallArgumentToken {
    String(String),
    Bool(bool),
    UInt(u128),
    Int(i128),
}

impl FunctionCallArgumentToken {
    const STRING_TOKEN: char = '\'';
    const ESCAPE_TOKEN: char = '\\';
    const BOOL_TRUE_TOKEN: &'static str = "true";
    const BOOL_FALSE_TOKEN: &'static str = "false";
    const UINT_TOKEN: &'static str = "uint";
    const INT_TOKEN: &'static str = "int";
    pub fn parse(input: &str) -> Result<(FunctionCallArgumentToken, &str), SyntaxParseError> {
        let original_input = input;
        if input.starts_with(Self::STRING_TOKEN) {
            return Self::parse_string(input);
        } else if input.starts_with(Self::BOOL_TRUE_TOKEN) {
            let input = &input[Self::BOOL_TRUE_TOKEN.len()..];
            let result = FunctionCallArgumentToken::Bool(true);
            return Ok((result, input));
        } else if input.starts_with(Self::BOOL_FALSE_TOKEN) {
            let input = &input[Self::BOOL_FALSE_TOKEN.len()..];
            let result = FunctionCallArgumentToken::Bool(false);
            return Ok((result, input));
        }
        let mut number = String::new();
        for c in input.chars() {
            let mut is_allowed = false;
            if c == '-' {
                is_allowed = true;
            }
            if c.is_numeric() {
                is_allowed = true;
            }
            if is_allowed {
                number.push(c);
            } else {
                break;
            }
        }
        let input = &input[number.len()..];
        if input.starts_with(Self::UINT_TOKEN) {
            let input = &input[Self::UINT_TOKEN.len()..];
            let number = u128::from_str(&number)?;
            let result = FunctionCallArgumentToken::UInt(number);
            return Ok((result, input));
        } else if input.starts_with(Self::INT_TOKEN) {
            let input = &input[Self::INT_TOKEN.len()..];
            let number = i128::from_str(&number)?;
            let result = FunctionCallArgumentToken::Int(number);
            return Ok((result, input));
        }
        let text_length = original_input.len() - input.len();
        let invalid_argument_template = &original_input[0..text_length];
        return Err(InvalidArgumentTemplate::new(invalid_argument_template, input).into());
    }

    fn parse_string(input: &str) -> Result<(FunctionCallArgumentToken, &str), SyntaxParseError> {
        let mut result = String::new();
        let mut input = &input[Self::STRING_TOKEN.len_utf8()..];
        let mut is_escape_char = false;
        let mut result_unescaped_length = 0;
        for c in input.chars() {
            if c == Self::STRING_TOKEN {
                if is_escape_char {
                    let _ = result.pop();
                    result.push(c);
                    is_escape_char = false;
                } else {
                    input = &input[result_unescaped_length..];
                    if !input.starts_with(Self::STRING_TOKEN) {
                        break;
                    }
                    input = &input[Self::STRING_TOKEN.len_utf8()..];
                    let result = FunctionCallArgumentToken::String(result);
                    return Ok((result, input));
                }
            } else if c == Self::ESCAPE_TOKEN {
                result.push(c);
                is_escape_char = true;
            } else {
                result.push(c);
                is_escape_char = false;
            }
            result_unescaped_length += c.len_utf8();
        }
        return Err(UnexpectedInputError::new(input).into());
    }
}