lazy_template/enclosed/
simple_escape.rs

1use super::{ComponentParserInput, ParserConfig};
2use crate::Parse;
3use derive_more::{Display, Error};
4use split_first_char::split_first_char;
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) = split_first_char(input.text).ok_or(None)?;
29
30        if head != '\\' {
31            return Err(None);
32        }
33
34        let (escape_code, rest) =
35            split_first_char(tail).ok_or(Some(ParseError::UnexpectedEndOfInput))?;
36
37        let char = escape_bracket(escape_code, input.config)
38            .or_else(|| make_special_character(escape_code))
39            .ok_or(ParseError::UnsupportedEscapeCode(escape_code))
40            .map_err(Some)?;
41
42        Ok((char, rest))
43    }
44}
45
46fn escape_bracket(escape_code: char, config: ParserConfig) -> Option<char> {
47    (escape_code == config.open_bracket || escape_code == config.close_bracket)
48        .then_some(escape_code)
49}
50
51fn make_special_character(escape_code: char) -> Option<char> {
52    Some(match escape_code {
53        '\\' => '\\',
54        '0' => '\0',
55        'b' => '\x08',
56        'e' => '\x1b',
57        'n' => '\n',
58        'r' => '\r',
59        't' => '\t',
60        _ => return None,
61    })
62}