1use core::borrow::Borrow;
12
13pub use out_bytes::OutBytes;
14
15use super::Case;
16
17pub trait AsOutBytes: out_bytes::Sealed {
30 fn as_out_bytes(&self) -> &OutBytes;
32
33 fn as_mut_out_bytes(&mut self) -> &mut OutBytes;
35}
36
37pub trait FixedLenBuf: Sized + AsOutBytes {
41 fn uninit() -> Self;
46}
47
48mod out_bytes {
52 use super::AsOutBytes;
53
54 #[repr(transparent)]
65 pub struct OutBytes([u8]);
66
67 impl OutBytes {
68 #[track_caller]
76 pub(crate) fn assume_init(&self, len: usize) -> &[u8] { &self.0[..len] }
77
78 #[track_caller]
84 pub(crate) fn write(&mut self, pos: usize, bytes: &[u8]) {
85 self.0[pos..(pos + bytes.len())].copy_from_slice(bytes);
86 }
87
88 pub(crate) fn len(&self) -> usize { self.0.len() }
90
91 fn from_bytes(slice: &[u8]) -> &Self {
92 unsafe { &*(slice as *const [u8] as *const Self) }
100 }
101
102 fn from_mut_bytes(slice: &mut [u8]) -> &mut Self {
103 unsafe { &mut *(slice as *mut [u8] as *mut Self) }
111 }
112 }
113
114 macro_rules! impl_encode {
115 ($($len:expr),* $(,)?) => {
116 $(
117 impl super::FixedLenBuf for [u8; $len] {
118 fn uninit() -> Self {
119 [0u8; $len]
120 }
121 }
122
123 impl AsOutBytes for [u8; $len] {
124 fn as_out_bytes(&self) -> &OutBytes {
125 OutBytes::from_bytes(self)
126 }
127
128 fn as_mut_out_bytes(&mut self) -> &mut OutBytes {
129 OutBytes::from_mut_bytes(self)
130 }
131 }
132
133 impl Sealed for [u8; $len] {}
134
135 impl<'a> super::super::display::DisplayHex for &'a [u8; $len / 2] {
136 type Display = super::super::display::DisplayArray<core::slice::Iter<'a, u8>, [u8; $len]>;
137 fn as_hex(self) -> Self::Display {
138 super::super::display::DisplayArray::new(self.iter())
139 }
140
141 fn hex_reserve_suggestion(self) -> usize {
142 $len
143 }
144 }
145 )*
146 }
147 }
148
149 impl<T: AsOutBytes + ?Sized> AsOutBytes for &'_ mut T {
150 fn as_out_bytes(&self) -> &OutBytes { (**self).as_out_bytes() }
151
152 fn as_mut_out_bytes(&mut self) -> &mut OutBytes { (**self).as_mut_out_bytes() }
153 }
154
155 impl<T: AsOutBytes + ?Sized> Sealed for &'_ mut T {}
156
157 impl AsOutBytes for OutBytes {
158 fn as_out_bytes(&self) -> &OutBytes { self }
159
160 fn as_mut_out_bytes(&mut self) -> &mut OutBytes { self }
161 }
162
163 impl Sealed for OutBytes {}
164
165 impl_encode!(
168 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 40, 64, 66, 128, 130, 256, 512,
169 1024, 2048, 4096, 8192
170 );
171
172 pub trait Sealed {}
174}
175
176pub struct BufEncoder<T: AsOutBytes> {
182 buf: T,
183 pos: usize,
184}
185
186impl<T: AsOutBytes> BufEncoder<T> {
187 #[inline]
192 pub fn new(buf: T) -> Self { BufEncoder { buf, pos: 0 } }
193
194 #[inline]
200 #[track_caller]
201 pub fn put_byte(&mut self, byte: u8, case: Case) {
202 self.buf.as_mut_out_bytes().write(self.pos, &super::byte_to_hex(byte, case.table()));
203 self.pos += 2;
204 }
205
206 #[inline]
212 #[track_caller]
213 pub fn put_bytes<I>(&mut self, bytes: I, case: Case)
214 where
215 I: IntoIterator,
216 I::Item: Borrow<u8>,
217 {
218 self.put_bytes_inner(bytes.into_iter(), case)
219 }
220
221 #[inline]
222 #[track_caller]
223 fn put_bytes_inner<I>(&mut self, bytes: I, case: Case)
224 where
225 I: Iterator,
226 I::Item: Borrow<u8>,
227 {
228 if let Some(max) = bytes.size_hint().1 {
230 assert!(max <= self.space_remaining());
231 }
232 for byte in bytes {
233 self.put_byte(*byte.borrow(), case);
234 }
235 }
236
237 #[must_use = "this may write only part of the input buffer"]
242 #[inline]
243 #[track_caller]
244 pub fn put_bytes_min<'a>(&mut self, bytes: &'a [u8], case: Case) -> &'a [u8] {
245 let to_write = self.space_remaining().min(bytes.len());
246 self.put_bytes(&bytes[..to_write], case);
247 &bytes[to_write..]
248 }
249
250 #[inline]
252 pub fn is_full(&self) -> bool { self.pos == self.buf.as_out_bytes().len() }
253
254 #[inline]
256 pub fn as_str(&self) -> &str {
257 core::str::from_utf8(self.buf.as_out_bytes().assume_init(self.pos))
258 .expect("we only write ASCII")
259 }
260
261 #[inline]
263 pub fn clear(&mut self) { self.pos = 0; }
264
265 #[inline]
269 pub fn space_remaining(&self) -> usize { (self.buf.as_out_bytes().len() - self.pos) / 2 }
270}
271
272#[cfg(test)]
273mod tests {
274 use super::*;
275
276 #[test]
277 fn empty() {
278 let mut buf = [0u8; 2];
279 let encoder = BufEncoder::new(&mut buf);
280 assert_eq!(encoder.as_str(), "");
281 assert!(!encoder.is_full());
282 }
283
284 #[test]
285 fn single_byte_exact_buf() {
286 let mut buf = [0u8; 2];
287 let mut encoder = BufEncoder::new(&mut buf);
288 assert_eq!(encoder.space_remaining(), 1);
289 encoder.put_byte(42, Case::Lower);
290 assert_eq!(encoder.as_str(), "2a");
291 assert_eq!(encoder.space_remaining(), 0);
292 assert!(encoder.is_full());
293 encoder.clear();
294 assert_eq!(encoder.space_remaining(), 1);
295 assert!(!encoder.is_full());
296 encoder.put_byte(42, Case::Upper);
297 assert_eq!(encoder.as_str(), "2A");
298 assert_eq!(encoder.space_remaining(), 0);
299 assert!(encoder.is_full());
300 }
301
302 #[test]
303 fn single_byte_oversized_buf() {
304 let mut buf = [0u8; 4];
305 let mut encoder = BufEncoder::new(&mut buf);
306 assert_eq!(encoder.space_remaining(), 2);
307 encoder.put_byte(42, Case::Lower);
308 assert_eq!(encoder.space_remaining(), 1);
309 assert_eq!(encoder.as_str(), "2a");
310 assert!(!encoder.is_full());
311 encoder.clear();
312 assert_eq!(encoder.space_remaining(), 2);
313 encoder.put_byte(42, Case::Upper);
314 assert_eq!(encoder.as_str(), "2A");
315 assert_eq!(encoder.space_remaining(), 1);
316 assert!(!encoder.is_full());
317 }
318
319 #[test]
320 fn two_bytes() {
321 let mut buf = [0u8; 4];
322 let mut encoder = BufEncoder::new(&mut buf);
323 encoder.put_byte(42, Case::Lower);
324 assert_eq!(encoder.space_remaining(), 1);
325 encoder.put_byte(255, Case::Lower);
326 assert_eq!(encoder.space_remaining(), 0);
327 assert_eq!(encoder.as_str(), "2aff");
328 assert!(encoder.is_full());
329 encoder.clear();
330 assert!(!encoder.is_full());
331 encoder.put_byte(42, Case::Upper);
332 encoder.put_byte(255, Case::Upper);
333 assert_eq!(encoder.as_str(), "2AFF");
334 assert!(encoder.is_full());
335 }
336
337 #[test]
338 fn put_bytes_min() {
339 let mut buf = [0u8; 2];
340 let mut encoder = BufEncoder::new(&mut buf);
341 let remainder = encoder.put_bytes_min(b"", Case::Lower);
342 assert_eq!(remainder, b"");
343 assert_eq!(encoder.as_str(), "");
344 let remainder = encoder.put_bytes_min(b"*", Case::Lower);
345 assert_eq!(remainder, b"");
346 assert_eq!(encoder.as_str(), "2a");
347 encoder.clear();
348 let remainder = encoder.put_bytes_min(&[42, 255], Case::Lower);
349 assert_eq!(remainder, &[255]);
350 assert_eq!(encoder.as_str(), "2a");
351 }
352
353 #[test]
354 fn same_as_fmt() {
355 use core::fmt::{self, Write};
356
357 struct Writer {
358 buf: [u8; 2],
359 pos: usize,
360 }
361
362 impl Writer {
363 fn as_str(&self) -> &str { core::str::from_utf8(&self.buf[..self.pos]).unwrap() }
364 }
365
366 impl Write for Writer {
367 fn write_str(&mut self, s: &str) -> fmt::Result {
368 assert!(self.pos <= 2);
369 if s.len() > 2 - self.pos {
370 Err(fmt::Error)
371 } else {
372 self.buf[self.pos..(self.pos + s.len())].copy_from_slice(s.as_bytes());
373 self.pos += s.len();
374 Ok(())
375 }
376 }
377 }
378
379 let mut writer = Writer { buf: [0u8; 2], pos: 0 };
380 let mut buf = [0u8; 2];
381 let mut encoder = BufEncoder::new(&mut buf);
382
383 for i in 0..=255 {
384 write!(writer, "{:02x}", i).unwrap();
385 encoder.put_byte(i, Case::Lower);
386 assert_eq!(encoder.as_str(), writer.as_str());
387 writer.pos = 0;
388 encoder.clear();
389 }
390 for i in 0..=255 {
391 write!(writer, "{:02X}", i).unwrap();
392 encoder.put_byte(i, Case::Upper);
393 assert_eq!(encoder.as_str(), writer.as_str());
394 writer.pos = 0;
395 encoder.clear();
396 }
397 }
398}