1use core::borrow::Borrow;
12
13use arrayvec::ArrayString;
14
15use super::{Case, Table};
16
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
42pub struct BufEncoder<const CAP: usize> {
43 buf: ArrayString<CAP>,
44 table: &'static Table,
45}
46
47impl<const CAP: usize> BufEncoder<CAP> {
48 const _CHECK_EVEN_CAPACITY: () = [(); 1][CAP % 2];
49
50 #[inline]
52 pub fn new(case: Case) -> Self {
53 let () = Self::_CHECK_EVEN_CAPACITY;
54 BufEncoder { buf: ArrayString::new(), table: case.table() }
55 }
56
57 #[inline]
63 #[track_caller]
64 pub fn put_byte(&mut self, byte: u8) {
65 let mut hex_chars = [0u8; 2];
66 let hex_str = self.table.byte_to_str(&mut hex_chars, byte);
67 self.buf.push_str(hex_str);
68 }
69
70 #[inline]
76 #[track_caller]
77 pub fn put_bytes<I>(&mut self, bytes: I)
78 where
79 I: IntoIterator,
80 I::Item: Borrow<u8>,
81 {
82 self.put_bytes_inner(bytes.into_iter());
83 }
84
85 #[inline]
86 #[track_caller]
87 fn put_bytes_inner<I>(&mut self, bytes: I)
88 where
89 I: Iterator,
90 I::Item: Borrow<u8>,
91 {
92 if let Some(max) = bytes.size_hint().1 {
94 assert!(max <= self.space_remaining());
95 }
96 for byte in bytes {
97 self.put_byte(*byte.borrow());
98 }
99 }
100
101 #[must_use = "this may write only part of the input buffer"]
106 #[inline]
107 #[track_caller]
108 pub fn put_bytes_min<'a>(&mut self, bytes: &'a [u8]) -> &'a [u8] {
109 let to_write = self.space_remaining().min(bytes.len());
110 self.put_bytes(&bytes[..to_write]);
111 &bytes[to_write..]
112 }
113
114 #[inline]
116 pub fn is_full(&self) -> bool { self.buf.is_full() }
117
118 #[inline]
120 pub fn as_str(&self) -> &str { &self.buf }
121
122 #[inline]
124 pub fn clear(&mut self) { self.buf.clear(); }
125
126 #[inline]
130 pub fn space_remaining(&self) -> usize { self.buf.remaining_capacity() / 2 }
131
132 pub(crate) fn put_filler(&mut self, filler: char, max_count: usize) -> usize {
133 let mut buf = [0; 4];
134 let filler = filler.encode_utf8(&mut buf);
135 let max_capacity = self.buf.remaining_capacity() / filler.len();
136 let to_write = max_capacity.min(max_count);
137
138 for _ in 0..to_write {
139 self.buf.push_str(filler);
140 }
141
142 to_write
143 }
144}
145
146impl<const CAP: usize> Default for BufEncoder<CAP> {
147 #[inline]
148 fn default() -> Self { Self::new(Case::Lower) }
149}
150
151impl<const CAP: usize, A: Borrow<u8>> FromIterator<A> for BufEncoder<CAP> {
152 fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
153 let mut encoder = Self::default();
154 encoder.put_bytes(iter);
155 encoder
156 }
157}
158
159impl<const CAP: usize, A: Borrow<u8>> Extend<A> for BufEncoder<CAP> {
160 fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) { self.put_bytes(iter); }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn empty() {
169 let encoder = BufEncoder::<2>::new(Case::Lower);
170 assert_eq!(encoder.as_str(), "");
171 assert!(!encoder.is_full());
172
173 let encoder = BufEncoder::<2>::new(Case::Upper);
174 assert_eq!(encoder.as_str(), "");
175 assert!(!encoder.is_full());
176 }
177
178 #[test]
179 fn single_byte_exact_buf() {
180 let mut encoder = BufEncoder::<2>::new(Case::Lower);
181 assert_eq!(encoder.space_remaining(), 1);
182 encoder.put_byte(42);
183 assert_eq!(encoder.as_str(), "2a");
184 assert_eq!(encoder.space_remaining(), 0);
185 assert!(encoder.is_full());
186 encoder.clear();
187 assert_eq!(encoder.space_remaining(), 1);
188 assert!(!encoder.is_full());
189
190 let mut encoder = BufEncoder::<2>::new(Case::Upper);
191 assert_eq!(encoder.space_remaining(), 1);
192 encoder.put_byte(42);
193 assert_eq!(encoder.as_str(), "2A");
194 assert_eq!(encoder.space_remaining(), 0);
195 assert!(encoder.is_full());
196 encoder.clear();
197 assert_eq!(encoder.space_remaining(), 1);
198 assert!(!encoder.is_full());
199 }
200
201 #[test]
202 fn single_byte_oversized_buf() {
203 let mut encoder = BufEncoder::<4>::new(Case::Lower);
204 assert_eq!(encoder.space_remaining(), 2);
205 encoder.put_byte(42);
206 assert_eq!(encoder.space_remaining(), 1);
207 assert_eq!(encoder.as_str(), "2a");
208 assert!(!encoder.is_full());
209 encoder.clear();
210 assert_eq!(encoder.space_remaining(), 2);
211 assert!(!encoder.is_full());
212
213 let mut encoder = BufEncoder::<4>::new(Case::Upper);
214 assert_eq!(encoder.space_remaining(), 2);
215 encoder.put_byte(42);
216 assert_eq!(encoder.space_remaining(), 1);
217 assert_eq!(encoder.as_str(), "2A");
218 assert!(!encoder.is_full());
219 encoder.clear();
220 assert_eq!(encoder.space_remaining(), 2);
221 assert!(!encoder.is_full());
222 }
223
224 #[test]
225 fn two_bytes() {
226 let mut encoder = BufEncoder::<4>::new(Case::Lower);
227 assert_eq!(encoder.space_remaining(), 2);
228 encoder.put_byte(42);
229 assert_eq!(encoder.space_remaining(), 1);
230 encoder.put_byte(255);
231 assert_eq!(encoder.space_remaining(), 0);
232 assert_eq!(encoder.as_str(), "2aff");
233 assert!(encoder.is_full());
234 encoder.clear();
235 assert_eq!(encoder.space_remaining(), 2);
236 assert!(!encoder.is_full());
237
238 let mut encoder = BufEncoder::<4>::new(Case::Upper);
239 assert_eq!(encoder.space_remaining(), 2);
240 encoder.put_byte(42);
241 assert_eq!(encoder.space_remaining(), 1);
242 encoder.put_byte(255);
243 assert_eq!(encoder.space_remaining(), 0);
244 assert_eq!(encoder.as_str(), "2AFF");
245 assert!(encoder.is_full());
246 encoder.clear();
247 assert_eq!(encoder.space_remaining(), 2);
248 assert!(!encoder.is_full());
249 }
250
251 #[test]
252 fn put_bytes_min() {
253 let mut encoder = BufEncoder::<2>::new(Case::Lower);
254 let remainder = encoder.put_bytes_min(b"");
255 assert_eq!(remainder, b"");
256 assert_eq!(encoder.as_str(), "");
257 let remainder = encoder.put_bytes_min(b"*");
258 assert_eq!(remainder, b"");
259 assert_eq!(encoder.as_str(), "2a");
260 encoder.clear();
261 let remainder = encoder.put_bytes_min(&[42, 255]);
262 assert_eq!(remainder, &[255]);
263 assert_eq!(encoder.as_str(), "2a");
264 }
265
266 #[test]
267 fn put_filler() {
268 let mut encoder = BufEncoder::<8>::new(Case::Lower);
269 assert_eq!(encoder.put_filler(' ', 0), 0);
270 assert_eq!(encoder.as_str(), "");
271 assert_eq!(encoder.put_filler('a', 1), 1);
272 assert_eq!(encoder.as_str(), "a");
273 assert_eq!(encoder.put_filler('é', 2), 2); assert_eq!(encoder.as_str(), "aéé");
275 assert_eq!(encoder.put_filler('é', 4), 1); assert_eq!(encoder.as_str(), "aééé");
277 }
278
279 #[test]
280 fn from_iterator() {
281 let bytes = [0x00_u8, 0xab, 0xff];
282 let encoder: BufEncoder<6> = bytes.iter().collect(); assert_eq!(encoder.as_str(), "00abff");
284
285 let encoder: BufEncoder<6> = bytes.into_iter().collect(); assert_eq!(encoder.as_str(), "00abff");
287 }
288
289 #[test]
290 fn extend() {
291 let mut encoder = BufEncoder::<8>::new(Case::Upper);
292 encoder.put_byte(0x00);
293 encoder.extend([0xab_u8, 0xff]);
294 assert_eq!(encoder.as_str(), "00ABFF");
295
296 let mut encoder = BufEncoder::<6>::new(Case::Lower);
297 encoder.put_byte(0x42);
298 encoder.extend([0xab_u8, 0xff]);
299 assert_eq!(encoder.as_str(), "42abff");
300 }
301
302 #[test]
303 fn same_as_fmt() {
304 use core::fmt::{self, Write};
305
306 struct Writer {
307 buf: [u8; 2],
308 pos: usize,
309 }
310
311 impl Writer {
312 fn as_str(&self) -> &str { core::str::from_utf8(&self.buf[..self.pos]).unwrap() }
313 }
314
315 impl Write for Writer {
316 fn write_str(&mut self, s: &str) -> fmt::Result {
317 assert!(self.pos <= 2);
318 if s.len() > 2 - self.pos {
319 Err(fmt::Error)
320 } else {
321 self.buf[self.pos..(self.pos + s.len())].copy_from_slice(s.as_bytes());
322 self.pos += s.len();
323 Ok(())
324 }
325 }
326 }
327
328 let mut writer = Writer { buf: [0u8; 2], pos: 0 };
329
330 let mut encoder = BufEncoder::<2>::new(Case::Lower);
331 for i in 0..=255 {
332 write!(writer, "{:02x}", i).unwrap();
333 encoder.put_byte(i);
334 assert_eq!(encoder.as_str(), writer.as_str());
335 writer.pos = 0;
336 encoder.clear();
337 }
338
339 let mut encoder = BufEncoder::<2>::new(Case::Upper);
340 for i in 0..=255 {
341 write!(writer, "{:02X}", i).unwrap();
342 encoder.put_byte(i);
343 assert_eq!(encoder.as_str(), writer.as_str());
344 writer.pos = 0;
345 encoder.clear();
346 }
347 }
348}