1use core::borrow::Borrow;
2
3#[cfg(feature = "alloc")]
15#[cfg_attr(feature = "doc", doc(cfg(feature = "alloc")))]
16pub fn escape<I>(i: I) -> alloc::vec::Vec<u8>
17where
18 I: IntoIterator,
19 I::Item: Borrow<u8>,
20{
21 let mut escaped = alloc::vec::Vec::<u8>::new();
22 for b in Escape::new(i) {
23 escaped.push(b);
24 }
25 escaped
26}
27
28#[derive(Debug, PartialEq, Eq)]
30pub enum EscapeIntoError {
31 OutOfBounds,
33}
34
35pub fn escape_into<I>(out: &mut [u8], i: I) -> Result<usize, EscapeIntoError>
47where
48 I: IntoIterator,
49 I::Item: Borrow<u8>,
50{
51 let mut count = 0usize;
52 for (idx, b) in Escape::new(i).enumerate() {
53 let Some(v) = out.get_mut(idx) else {
54 return Err(EscapeIntoError::OutOfBounds);
55 };
56 *v = b;
57 count += 1;
58 }
59 Ok(count)
60}
61
62#[must_use]
64pub const fn escaped_max_len(len: usize) -> Option<usize> {
65 len.checked_mul(4)
66}
67
68pub fn escaped_len<I>(i: I) -> usize
70where
71 I: IntoIterator,
72 Escape<I>: Iterator,
73{
74 Escape::new(i).count()
75}
76
77#[derive(Debug)]
83pub struct Escape<I>
84where
85 I: IntoIterator,
86{
87 next: Next,
88 input: I::IntoIter,
89}
90
91impl<I> Clone for Escape<I>
92where
93 I: IntoIterator,
94 I::IntoIter: Clone,
95{
96 fn clone(&self) -> Self {
97 Self {
98 next: self.next.clone(),
99 input: self.input.clone(),
100 }
101 }
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
105enum Next {
106 Input,
107 Byte1(u8),
108 Byte2(u8, u8),
109 Byte3(u8, u8, u8),
110}
111
112impl<I> Escape<I>
113where
114 I: IntoIterator,
115{
116 pub fn new(i: I) -> Self {
117 Self {
118 next: Next::Input,
119 input: i.into_iter(),
120 }
121 }
122}
123
124impl<I> Iterator for Escape<I>
125where
126 I: IntoIterator,
127 I::Item: Borrow<u8>,
128{
129 type Item = u8;
130
131 fn next(&mut self) -> Option<Self::Item> {
133 match self.next {
134 Next::Input => {
135 let Some(b) = self.input.next() else {
136 return None;
137 };
138 let b = *b.borrow();
139 match b {
140 b'\\' => {
142 self.next = Next::Byte1(b'\\');
143 Some(b'\\')
144 }
145 b'\0' => {
147 self.next = Next::Byte1(b'0');
148 Some(b'\\')
149 }
150 b'\t' => {
152 self.next = Next::Byte1(b't');
153 Some(b'\\')
154 }
155 b'\r' => {
157 self.next = Next::Byte1(b'r');
158 Some(b'\\')
159 }
160 b'\n' => {
162 self.next = Next::Byte1(b'n');
163 Some(b'\\')
164 }
165 b' '..=b'~' => Some(b),
167 _ => {
169 const HEX_ALPHABET: [u8; 16] = *b"0123456789abcdef";
170 self.next = Next::Byte3(
171 b'x',
172 HEX_ALPHABET[(b >> 4) as usize],
173 HEX_ALPHABET[(b & 0xF) as usize],
174 );
175 Some(b'\\')
176 }
177 }
178 }
179 Next::Byte1(b1) => {
180 self.next = Next::Input;
181 Some(b1)
182 }
183 Next::Byte2(b1, b2) => {
184 self.next = Next::Byte1(b2);
185 Some(b1)
186 }
187 Next::Byte3(b1, b2, b3) => {
188 self.next = Next::Byte2(b2, b3);
189 Some(b1)
190 }
191 }
192 }
193
194 fn size_hint(&self) -> (usize, Option<usize>) {
195 let input_hint = self.input.size_hint();
196 (input_hint.0, input_hint.1.and_then(escaped_max_len))
197 }
198}