pub(crate) fn escape_literal(s: &str) -> String {
let mut out = String::with_capacity(s.len());
for c in s.chars() {
match c {
'\\' => out.push_str("\\\\"),
'"' => out.push_str("\\\""),
'\n' => out.push_str("\\n"),
'\r' => out.push_str("\\r"),
'\t' => out.push_str("\\t"),
'\u{08}' => out.push_str("\\b"),
'\u{0C}' => out.push_str("\\f"),
c if c.is_control() => out.push_str(&format!("\\u{:04X}", c as u32)),
c => out.push(c),
}
}
out
}
#[cfg(test)]
mod tests {
use super::escape_literal;
#[test]
fn escapes_line_jumps_and_controls() {
assert_eq!(escape_literal("a\nb\r\nc"), "a\\nb\\r\\nc");
assert_eq!(escape_literal("t\tb\u{08}f\u{0C}"), "t\\tb\\bf\\f");
assert_eq!(escape_literal("nul\u{0}del\u{7F}"), "nul\\u0000del\\u007F");
assert_eq!(escape_literal(r#"q"s\"#), r#"q\"s\\"#);
assert_eq!(escape_literal("plain ünïcode"), "plain ünïcode");
}
}