lazy_template/enclosed/
simple_escape.rs

1use super::{ComponentParserInput, ParserConfig};
2use crate::Parse;
3use derive_more::{Display, Error};
4use split_char_from_str::SplitCharFromStr;
5
6pub type ParserInput<'a> = ComponentParserInput<'a>;
7
8#[derive(Debug, Clone, Copy)]
9pub struct SimpleEscapeParser;
10pub type Parser = SimpleEscapeParser;
11
12pub type SimpleEscape = char;
13pub type ParseOutput = SimpleEscape;
14
15#[derive(Debug, Display, Error, Clone, Copy)]
16pub enum ParseError {
17    #[display("Unsupported escape code {_0:?}")]
18    UnsupportedEscapeCode(#[error(not(source))] char),
19    #[display("Unexpected end of input")]
20    UnexpectedEndOfInput,
21}
22
23impl<'a> Parse<'a, ParserInput<'a>> for Parser {
24    type Output = ParseOutput;
25    type Error = Option<ParseError>;
26
27    fn parse(&self, input: ParserInput<'a>) -> Result<(Self::Output, &'a str), Self::Error> {
28        let (head, tail) = input.text.split_first_char().ok_or(None)?;
29
30        if head != '\\' {
31            return Err(None);
32        }
33
34        let (escape_code, rest) = tail
35            .split_first_char()
36            .ok_or(ParseError::UnexpectedEndOfInput)
37            .map_err(Some)?;
38
39        let char = escape_bracket(escape_code, input.config)
40            .or_else(|| make_special_character(escape_code))
41            .ok_or(ParseError::UnsupportedEscapeCode(escape_code))
42            .map_err(Some)?;
43
44        Ok((char, rest))
45    }
46}
47
48fn escape_bracket(escape_code: char, config: ParserConfig) -> Option<char> {
49    (escape_code == config.open_bracket || escape_code == config.close_bracket)
50        .then_some(escape_code)
51}
52
53fn make_special_character(escape_code: char) -> Option<char> {
54    Some(match escape_code {
55        '\\' => '\\',
56        '0' => '\0',
57        'b' => '\x08',
58        'e' => '\x1b',
59        'n' => '\n',
60        'r' => '\r',
61        't' => '\t',
62        _ => return None,
63    })
64}