1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use crate::{
    de::{access::string::ParsedString, position::Position},
    error::Ensure,
};

use super::{slice::SliceTokenizer, Tokenizer};

pub struct StrTokenizer<'de> {
    delegate: SliceTokenizer<'de>,
    unescaped: bool,
}
impl<'de> StrTokenizer<'de> {
    pub fn new(s: &'de str) -> Self {
        StrTokenizer { delegate: SliceTokenizer::new(s.as_bytes()), unescaped: false }
    }
}

impl<'de> Tokenizer<'de> for StrTokenizer<'de> {
    fn eat(&mut self) -> crate::Result<Option<(Position, u8)>> {
        self.delegate.eat()
    }

    fn look(&mut self) -> crate::Result<Option<(Position, u8)>> {
        self.delegate.look()
    }

    fn parse_string_content(&mut self) -> crate::Result<ParsedString<'de>> {
        let offset = self.delegate.current;
        let value = self.parse_string_content_super()?;
        match (self.unescaped, value) {
            // if string contain escape sequence, it should be unescaped
            // but unescaped string should be owned because of lifetime
            // default implementation of `Tokenizer` return always owned string
            (true, ParsedString::Borrowed(_)) => Err(Ensure::OwnedString)?,
            (true, s @ ParsedString::Owned(_)) => Ok(s),
            (false, _) => {
                let raw = &self.delegate.slice[offset..self.delegate.current];
                Ok(ParsedString::Borrowed(std::str::from_utf8(raw)?))
            }
        }
    }

    fn parse_escape_sequence(&mut self, buff: &mut Vec<u8>) -> crate::Result<()> {
        self.unescaped = true;
        self.delegate.parse_escape_sequence_super(buff)
    }
}

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

    #[test]
    fn test_behavior_fold_token() {
        behavior_fold_token(StrTokenizer::new);
    }

    #[test]
    fn test_behavior_parse_ident() {
        behavior_parse_ident(StrTokenizer::new);
    }

    #[test]
    fn test_behavior_tokenizer() {
        behavior_tokenizer(StrTokenizer::new);
    }

    #[test]
    fn test_behavior_parse_unescaped_string() {
        behavior_parse_unescaped_string(StrTokenizer::new);
    }

    #[test]
    #[should_panic]
    fn test_behavior_parse_raw_string() {
        behavior_parse_raw_string(StrTokenizer::new);
    }

    #[test]
    fn test_behavior_parse_string_err() {
        behavior_parse_string_err(StrTokenizer::new);
    }

    #[test]
    fn test_behavior_parse_number() {
        behavior_parse_number(StrTokenizer::new);
    }

    #[test]
    fn test_behavior_parse_number_err() {
        behavior_parse_number_err(StrTokenizer::new);
    }
}