1use core::fmt;
4
5#[derive(Debug)]
6pub enum EscapedStringFragment<'a> {
8 NotEscaped(&'a str),
10 Escaped(char),
12}
13
14#[derive(Debug)]
15pub enum StringUnescapeError {
17 InvalidEscapeSequence,
19}
20
21impl fmt::Display for StringUnescapeError {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 match self {
24 StringUnescapeError::InvalidEscapeSequence => write!(
25 f,
26 "Failed to unescape a character due to an invalid escape sequence."
27 ),
28 }
29 }
30}
31
32#[cfg(feature = "std")]
33impl std::error::Error for StringUnescapeError {}
34
35fn unescape_next_fragment(
36 escaped_string: &str,
37) -> Result<(EscapedStringFragment<'_>, &str), StringUnescapeError> {
38 Ok(if let Some(rest) = escaped_string.strip_prefix('\\') {
39 let mut escaped_string_chars = rest.chars();
40
41 let unescaped_char = match escaped_string_chars.next() {
42 Some('"') => '"',
43 Some('\\') => '\\',
44 Some('/') => '/',
45 Some('b') => '\x08',
46 Some('f') => '\x0C',
47 Some('n') => '\n',
48 Some('r') => '\r',
49 Some('t') => '\t',
50 Some('u') => {
51 fn split_first_slice(s: &str, len: usize) -> Option<(&str, &str)> {
52 Some((s.get(..len)?, s.get(len..)?))
53 }
54
55 let (escape_sequence, remaining_escaped_string_chars) =
56 split_first_slice(escaped_string_chars.as_str(), 4)
57 .ok_or(StringUnescapeError::InvalidEscapeSequence)?;
58
59 escaped_string_chars = remaining_escaped_string_chars.chars();
60
61 u32::from_str_radix(escape_sequence, 16)
62 .ok()
63 .and_then(char::from_u32)
64 .ok_or(StringUnescapeError::InvalidEscapeSequence)?
65 }
66 _ => return Err(StringUnescapeError::InvalidEscapeSequence),
67 };
68
69 (
70 EscapedStringFragment::Escaped(unescaped_char),
71 escaped_string_chars.as_str(),
72 )
73 } else {
74 let (fragment, rest) =
75 escaped_string.split_at(escaped_string.find('\\').unwrap_or(escaped_string.len()));
76
77 (EscapedStringFragment::NotEscaped(fragment), rest)
78 })
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
99#[serde(rename = "__serde_json_core_escaped_string__")]
100pub struct EscapedStr<'a>(pub &'a str);
101
102impl<'a> EscapedStr<'a> {
103 pub(crate) const NAME: &'static str = "__serde_json_core_escaped_string__";
104
105 pub fn fragments(&self) -> EscapedStringFragmentIter<'a> {
107 EscapedStringFragmentIter(self.0)
108 }
109}
110
111pub struct EscapedStringFragmentIter<'a>(&'a str);
113
114impl<'a> EscapedStringFragmentIter<'a> {
115 pub fn as_str(&self) -> EscapedStr<'a> {
117 EscapedStr(self.0)
118 }
119}
120
121impl<'a> Iterator for EscapedStringFragmentIter<'a> {
122 type Item = Result<EscapedStringFragment<'a>, StringUnescapeError>;
123
124 fn next(&mut self) -> Option<Self::Item> {
125 if self.0.is_empty() {
126 return None;
127 }
128
129 Some(unescape_next_fragment(self.0).map(|(fragment, rest)| {
130 self.0 = rest;
131
132 fragment
133 }))
134 }
135}