1use std::borrow::Cow;
2
3const HEX_DIGITS: [u8; 16] = [b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F'];
4
5pub fn escape(s: &str) -> Cow<str>
18{ let bytes = s.as_bytes();
19 if let Some(pos) = bytes.iter().position(|c| match *c {b'"' | b'\\' | 0..=31 => true, _ => false})
20 { Cow::Owned(String::from_utf8(do_escape_bytes(bytes, pos)).unwrap())
21 }
22 else
23 { Cow::Borrowed(s)
24 }
25}
26
27pub fn escape_bytes(bytes: &[u8]) -> Cow<[u8]>
29{ if let Some(pos) = bytes.iter().position(|c| match *c {b'"' | b'\\' | 0..=31 => true, _ => false})
30 { Cow::Owned(do_escape_bytes(bytes, pos))
31 }
32 else
33 { Cow::Borrowed(bytes)
34 }
35}
36
37fn do_escape_bytes(bytes: &[u8], mut pos: usize) -> Vec<u8>
38{ let mut buffer = Vec::with_capacity(bytes.len() + 8);
39 let mut from = 0;
40 loop
41 { buffer.extend_from_slice(&bytes[from .. pos]);
42 let c = bytes[pos];
43 if c >= 32
44 { buffer.push(b'\\');
45 buffer.push(c);
46 }
47 else
48 { match c
49 { 9 =>
50 { buffer.push(b'\\');
51 buffer.push(b't');
52 }
53 13 =>
54 { buffer.push(b'\\');
55 buffer.push(b'r');
56 }
57 10 =>
58 { buffer.push(b'\\');
59 buffer.push(b'n');
60 }
61 8 =>
62 { buffer.push(b'\\');
63 buffer.push(b'b');
64 }
65 12 =>
66 { buffer.push(b'\\');
67 buffer.push(b'f');
68 }
69 _ =>
70 { buffer.push(b'\\');
71 buffer.push(b'u');
72 buffer.push(b'0');
73 buffer.push(b'0');
74 buffer.push(HEX_DIGITS[(c >> 4) as usize]);
75 buffer.push(HEX_DIGITS[(c & 0xF) as usize]);
76 }
77 }
78 }
79 from = pos + 1;
80 if let Some(new_pos) = &bytes[from ..].iter().position(|c| match *c {b'"' | b'\\' | 0..=31 => true, _ => false})
81 { pos = from + *new_pos;
82 }
83 else
84 { buffer.extend_from_slice(&bytes[from .. ]);
85 break;
86 }
87 }
88 buffer
89}