fn unescape_literal(
    literal_kind: LiteralKind,
    s: &str,
    output: &mut impl GrowableBytes,
) -> Result<(), InvalidString> {
    struct Scanner<'a> {
        s: &'a [u8],
        i: usize,
    }
    impl<'a> Scanner<'a> {
        fn new(s: &'a [u8]) -> Self {
            Self { s, i: 0 }
        }
        fn is_empty(&self) -> bool {
            self.i >= self.s.len()
        }
        fn next(&mut self) -> Result<u8, InvalidString> {
            if self.i >= self.s.len() {
                return Err("string ended early".into());
            }
            let r = self.s[self.i];
            self.i += 1;
            Ok(r)
        }
        fn take_if(&mut self, f: impl Fn(u8) -> bool, size: usize) -> &'a [u8] {
            let l = usize::min(size + self.i, self.s.len());
            let mut c = self.i;
            while c < l && f(self.s[c]) {
                c += 1;
            }
            let r = &self.s[self.i..c];
            self.i = c;
            r
        }
        fn peek(&self) -> Option<u8> {
            if self.i < self.s.len() {
                Some(self.s[self.i])
            } else {
                None
            }
        }
        fn back(&mut self) {
            if self.i > 0 {
                self.i -= 1;
            }
        }
    }

    let mut s = Scanner::new(s.as_bytes());
    while !s.is_empty() {
        let c = s.next()?;
        if c != b'\\' || s.is_empty() {
            output.push(c);
        } else {
            let c = s.next()?;
            match c {
                b'a' if literal_kind == LiteralKind::LiteralLongString => output.push(b'\x07'),
                b'b' if literal_kind == LiteralKind::LiteralLongString => output.push(b'\x08'),
                b'\'' => output.extend_from_slice(b"\\\'"),
                b'n' => match literal_kind {
                    LiteralKind::LiteralLongString => {}
                    _ => output.push(b'\n'),
                },
                b'r' => match literal_kind {
                    LiteralKind::LiteralLongString => {}
                    _ => output.push(b'\r'),
                },
                b't' => output.push(b'\t'),
                b'v' => output.push(b'\x0b'),
                b'e' => output.push(b'\x1b'),
                b'f' => output.push(b'\x0c'),
                b'\\' => output.push(b'\\'),
                b'?' if literal_kind == LiteralKind::LiteralLongString => output.push(b'\x3f'),
                b'$' if literal_kind != LiteralKind::LiteralLongString => output.push(b'$'),
                b'\"' => match literal_kind {
                    LiteralKind::LiteralDoubleQuote | LiteralKind::LiteralLongString => {
                        output.push(b'\"')
                    }
                    _ => output.extend_from_slice(b"\\\""),
                },
                b'u' if literal_kind != LiteralKind::LiteralLongString
                    && s.peek() == Some(b'{') =>
                {
                    let _ = s.next()?;
                    let unicode = s.take_if(|c| c != b'}', 6);
                    let n = parse_int(unicode, 16)?;
                    codepoint_to_utf8(n, output)?;
                    let n = s.next()?;
                    if n != b'}' {
                        return Err("Invalid UTF-8 escape sequence".into());
                    }
                }
                b'x' | b'X' => {
                    let hex = s.take_if(is_hex, 2);
                    if hex.len() == 0 {
                        output.push(b'\\');
                        output.push(c);
                    } else {
                        let c = parse_numeric_escape(false, hex, 16)?;
                        output.push(c as u8);
                    }
                }
                c if is_oct(c) => {
                    s.back();
                    let oct = s.take_if(is_oct, 3);
                    let c = parse_numeric_escape(true, oct, 8)?;
                    output.push(c as u8);
                }
                c => {
                    output.push(b'\\');
                    output.push(c);
                }
            }
        }
    }
    Ok(())
}
/// Copies `s` into `output`, replacing escape sequences with the characters
/// they represent.
///
/// The output is NOT guaranteed to be valid UTF-8. While this function will
/// return `Err` in some cases where the input contains an escape sequence
/// specifying an invalid codepoint, it will return invalid UTF-8 in some
/// circumstances (e.g., for invalid UTF-8 encoded as hex or octal byte escapes,
/// or UTF-16 encoded as \u escapes).
Copies `s` into `output`, replacing escape sequences with the characters
they represent.

The output is NOT guaranteed to be valid UTF-8. While this function will
return `Err` in some cases where the input contains an escape sequence
specifying an invalid codepoint, it will return invalid UTF-8 in some
circumstances .
Copies ` s ` into ` output ` replacing escape sequences with the characters they represent . The output is NOT guaranteed to be valid UTF - 8 . While this function will return ` Err ` in some cases where the input contains an escape sequence specifying an invalid codepoint it will return invalid UTF - 8 in some circumstances .
fn unescape_literal(
    literal_kind: LiteralKind,
    s: &str,
    output: &mut impl GrowableBytes,
) -> Result<(), InvalidString> {
    struct Scanner<'a> {
        s: &'a [u8],
        i: usize,
    }
    impl<'a> Scanner<'a> {
        fn new(s: &'a [u8]) -> Self {
            Self { s, i: 0 }
        }
        fn is_empty(&self) -> bool {
            self.i >= self.s.len()
        }
        fn next(&mut self) -> Result<u8, InvalidString> {
            if self.i >= self.s.len() {
                return Err("string ended early".into());
            }
            let r = self.s[self.i];
            self.i += 1;
            Ok(r)
        }
        fn take_if(&mut self, f: impl Fn(u8) -> bool, size: usize) -> &'a [u8] {
            let l = usize::min(size + self.i, self.s.len());
            let mut c = self.i;
            while c < l && f(self.s[c]) {
                c += 1;
            }
            let r = &self.s[self.i..c];
            self.i = c;
            r
        }
        fn peek(&self) -> Option<u8> {
            if self.i < self.s.len() {
                Some(self.s[self.i])
            } else {
                None
            }
        }
        fn back(&mut self) {
            if self.i > 0 {
                self.i -= 1;
            }
        }
    }
    let mut s = Scanner::new(s.as_bytes());
    while !s.is_empty() {
        let c = s.next()?;
        if c != b'\\' || s.is_empty() {
            output.push(c);
        } else {
            let c = s.next()?;
            match c {
                b'a' if literal_kind == LiteralKind::LiteralLongString => output.push(b'\x07'),
                b'b' if literal_kind == LiteralKind::LiteralLongString => output.push(b'\x08'),
                b'\'' => output.extend_from_slice(b"\\\'"),
                b'n' => match literal_kind {
                    LiteralKind::LiteralLongString => {}
                    _ => output.push(b'\n'),
                },
                b'r' => match literal_kind {
                    LiteralKind::LiteralLongString => {}
                    _ => output.push(b'\r'),
                },
                b't' => output.push(b'\t'),
                b'v' => output.push(b'\x0b'),
                b'e' => output.push(b'\x1b'),
                b'f' => output.push(b'\x0c'),
                b'\\' => output.push(b'\\'),
                b'?' if literal_kind == LiteralKind::LiteralLongString => output.push(b'\x3f'),
                b'$' if literal_kind != LiteralKind::LiteralLongString => output.push(b'$'),
                b'\"' => match literal_kind {
                    LiteralKind::LiteralDoubleQuote | LiteralKind::LiteralLongString => {
                        output.push(b'\"')
                    }
                    _ => output.extend_from_slice(b"\\\""),
                },
                b'u' if literal_kind != LiteralKind::LiteralLongString
                    && s.peek() == Some(b'{') =>
                {
                    let _ = s.next()?;
                    let unicode = s.take_if(|c| c != b'}', 6);
                    let n = parse_int(unicode, 16)?;
                    codepoint_to_utf8(n, output)?;
                    let n = s.next()?;
                    if n != b'}' {
                        return Err("Invalid UTF-8 escape sequence".into());
                    }
                }
                b'x' | b'X' => {
                    let hex = s.take_if(is_hex, 2);
                    if hex.len() == 0 {
                        output.push(b'\\');
                        output.push(c);
                    } else {
                        let c = parse_numeric_escape(false, hex, 16)?;
                        output.push(c as u8);
                    }
                }
                c if is_oct(c) => {
                    s.back();
                    let oct = s.take_if(is_oct, 3);
                    let c = parse_numeric_escape(true, oct, 8)?;
                    output.push(c as u8);
                }
                c => {
                    output.push(b'\\');
                    output.push(c);
                }
            }
        }
    }
    Ok(())
}
fn unescape_literal ( literal_kind : LiteralKind , s : & str , output : & mut impl GrowableBytes , ) -> Result < ( ) , InvalidString > { struct Scanner < ' a > { s : & ' a [ u8 ] , i : usize , } impl < ' a > Scanner < ' a > { fn new ( s : & ' a [ u8 ] ) -> Self { Self { s , i : 0 } } fn is_empty ( & self ) -> bool { self . i >= self . s . len ( ) } fn next ( & mut self ) -> Result < u8 , InvalidString > { if self . i >= self . s . len ( ) { return Err ( " " . into ( ) ) ; } let r = self . s [ self . i ] ; self . i += 1 ; Ok ( r ) } fn take_if ( & mut self , f : impl Fn ( u8 ) -> bool , size : usize ) -> & ' a [ u8 ] { let l = usize :: min ( size + self . i , self . s . len ( ) ) ; let mut c = self . i ; while c < l && f ( self . s [ c ] ) { c += 1 ; } let r = & self . s [ self . i .. c ] ; self . i = c ; r } fn peek ( & self ) -> Option < u8 > { if self . i < self . s . len ( ) { Some ( self . s [ self . i ] ) } else { None } } fn back ( & mut self ) { if self . i > 0 { self . i -= 1 ; } } } let mut s = Scanner :: new ( s . as_bytes ( ) ) ; while ! s . is_empty ( ) { let c = s . next ( ) ? ; if c != b'\\' || s . is_empty ( ) { output . push ( c ) ; } else { let c = s . next ( ) ? ; match c { b'a' if literal_kind == LiteralKind :: LiteralLongString => output . push ( b'\x07' ) , b'b' if literal_kind == LiteralKind :: LiteralLongString => output . push ( b'\x08' ) , b'\'' => output . extend_from_slice ( b" \\ \' " ) , b'n' => match literal_kind { LiteralKind :: LiteralLongString => { } _ => output . push ( b'\n' ) , } , b'r' => match literal_kind { LiteralKind :: LiteralLongString => { } _ => output . push ( b'\r' ) , } , b't' => output . push ( b'\t' ) , b'v' => output . push ( b'\x0b' ) , b'e' => output . push ( b'\x1b' ) , b'f' => output . push ( b'\x0c' ) , b'\\' => output . push ( b'\\' ) , b'?' if literal_kind == LiteralKind :: LiteralLongString => output . push ( b'\x3f' ) , b'$' if literal_kind != LiteralKind :: LiteralLongString => output . push ( b'$' ) , b'\"' => match literal_kind { LiteralKind :: LiteralDoubleQuote | LiteralKind :: LiteralLongString => { output . push ( b'\"' ) } _ => output . extend_from_slice ( b" \\ \" " ) , } , b'u' if literal_kind != LiteralKind :: LiteralLongString && s . peek ( ) == Some ( b'{' ) => { let _ = s . next ( ) ? ; let unicode = s . take_if ( | c | c != b'}' , 6 ) ; let n = parse_int ( unicode , 16 ) ? ; codepoint_to_utf8 ( n , output ) ? ; let n = s . next ( ) ? ; if n != b'}' { return Err ( " " . into ( ) ) ; } } b'x' | b'X' => { let hex = s . take_if ( is_hex , 2 ) ; if hex . len ( ) == 0 { output . push ( b'\\' ) ; output . push ( c ) ; } else { let c = parse_numeric_escape ( false , hex , 16 ) ? ; output . push ( c as u8 ) ; } } c if is_oct ( c ) => { s . back ( ) ; let oct = s . take_if ( is_oct , 3 ) ; let c = parse_numeric_escape ( true , oct , 8 ) ? ; output . push ( c as u8 ) ; } c => { output . push ( b'\\' ) ; output . push ( c ) ; } } } } Ok ( ( ) ) }
Copies `s` into `output`, replacing escape sequences with the characters
they represent.
Copies ` s ` into ` output ` replacing escape sequences with the characters they represent .
literal_kind
LiteralKind
s
&str
output
&mut impl GrowableBytes
literal_kind
LiteralKind
s
&str
output
&mut impl GrowableBytes