1use std::str::Chars;23fn decode_unicode(chars: &mut Chars) -> Option<u16> {4 IntoIterator::into_iter([chars.next()?, chars.next()?, chars.next()?, chars.next()?])5 .map(|c| c.to_digit(16).map(|f| f as u16))6 .try_fold(0u16, |acc, v| Some((acc << 4) | (v?)))7}89pub fn unescape(s: &str) -> Option<String> {10 let mut chars = s.chars();11 let mut out = String::with_capacity(s.len());1213 while let Some(c) = chars.next() {14 if c != '\\' {15 out.push(c);16 continue;17 }18 match chars.next()? {19 c @ ('\\' | '"' | '\'') => out.push(c),20 'b' => out.push('\u{0008}'),21 'f' => out.push('\u{000c}'),22 'n' => out.push('\n'),23 'r' => out.push('\r'),24 't' => out.push('\t'),25 'u' => match decode_unicode(&mut chars)? {26 27 0xDC00..=0xDFFF => return None,28 29 n1 @ 0xD800..=0xDBFF => {30 if chars.next() != Some('\\') {31 return None;32 }33 if chars.next() != Some('u') {34 return None;35 }36 let n2 = decode_unicode(&mut chars)?;37 if !matches!(n2, 0xDC00..=0xDFFF) {38 return None;39 }40 let n = (((n1 - 0xD800) as u32) << 10 | (n2 - 0xDC00) as u32) + 0x1_0000;41 out.push(char::from_u32(n)?);42 }43 n => out.push(char::from_u32(n as u32)?),44 },45 'x' => {46 let c = IntoIterator::into_iter([chars.next()?, chars.next()?])47 .map(|c| c.to_digit(16))48 .try_fold(0u32, |acc, v| Some((acc << 8) | (v?)))?;49 out.push(char::from_u32(c)?)50 }51 _ => return None,52 }53 }54 Some(out)55}