nix_compat/aterm/
escape.rs1use std::sync::LazyLock;
2
3use aho_corasick::AhoCorasick;
4
5const PATTERNS: [&str; 5] = ["\\", "\n", "\r", "\t", "\""];
6const REPLACEMENTS: [&str; 5] = ["\\\\", "\\n", "\\r", "\\t", "\\\""];
7static AC: LazyLock<AhoCorasick> = LazyLock::new(|| {
8 AhoCorasick::builder()
9 .build(PATTERNS)
10 .expect("to init aho-corasick with PATTERNS")
11});
12
13pub fn write_escaped<P: AsRef<[u8]>>(s: P, w: &mut impl std::io::Write) -> std::io::Result<()> {
16 AC.try_stream_replace_all(s.as_ref(), w, &REPLACEMENTS)
17}
18
19#[cfg(test)]
20mod tests {
21 use super::write_escaped;
22 use rstest::rstest;
23
24 #[rstest]
25 #[case::empty(b"", b"")]
26 #[case::doublequote(b"\"", b"\\\"")]
27 #[case::colon(b":", b":")]
28 #[case::complex(b"foo\n\rbar\\baz", b"foo\\n\\rbar\\\\baz")]
29 fn escape(#[case] input: &[u8], #[case] expected: &[u8]) {
30 let mut buf = Vec::new();
31 write_escaped(input, &mut buf).unwrap();
32
33 assert_eq!(expected, buf.as_slice());
34 }
35}