hex_conservative/
buf_encoder.rs1use core::borrow::Borrow;
12
13use arrayvec::ArrayString;
14
15use super::{Case, Table};
16
17pub struct BufEncoder<const CAP: usize> {
23 buf: ArrayString<CAP>,
24 table: &'static Table,
25}
26
27impl<const CAP: usize> BufEncoder<CAP> {
28 const _CHECK_EVEN_CAPACITY: () = [(); 1][CAP % 2];
29
30 #[inline]
32 pub fn new(case: Case) -> Self { BufEncoder { buf: ArrayString::new(), table: case.table() } }
33
34 #[inline]
40 #[track_caller]
41 pub fn put_byte(&mut self, byte: u8) {
42 let mut hex_chars = [0u8; 2];
43 let hex_str = self.table.byte_to_str(&mut hex_chars, byte);
44 self.buf.push_str(hex_str);
45 }
46
47 #[inline]
53 #[track_caller]
54 pub fn put_bytes<I>(&mut self, bytes: I)
55 where
56 I: IntoIterator,
57 I::Item: Borrow<u8>,
58 {
59 self.put_bytes_inner(bytes.into_iter())
60 }
61
62 #[inline]
63 #[track_caller]
64 fn put_bytes_inner<I>(&mut self, bytes: I)
65 where
66 I: Iterator,
67 I::Item: Borrow<u8>,
68 {
69 if let Some(max) = bytes.size_hint().1 {
71 assert!(max <= self.space_remaining());
72 }
73 for byte in bytes {
74 self.put_byte(*byte.borrow());
75 }
76 }
77
78 #[must_use = "this may write only part of the input buffer"]
83 #[inline]
84 #[track_caller]
85 pub fn put_bytes_min<'a>(&mut self, bytes: &'a [u8]) -> &'a [u8] {
86 let to_write = self.space_remaining().min(bytes.len());
87 self.put_bytes(&bytes[..to_write]);
88 &bytes[to_write..]
89 }
90
91 #[inline]
93 pub fn is_full(&self) -> bool { self.space_remaining() == 0 }
94
95 #[inline]
97 pub fn as_str(&self) -> &str { &self.buf }
98
99 #[inline]
101 pub fn clear(&mut self) { self.buf.clear(); }
102
103 #[inline]
107 pub fn space_remaining(&self) -> usize { self.buf.remaining_capacity() / 2 }
108
109 pub(crate) fn put_filler(&mut self, filler: char, max_count: usize) -> usize {
110 let mut buf = [0; 4];
111 let filler = filler.encode_utf8(&mut buf);
112 let max_capacity = self.buf.remaining_capacity() / filler.len();
113 let to_write = max_capacity.min(max_count);
114
115 for _ in 0..to_write {
116 self.buf.push_str(filler);
117 }
118
119 to_write
120 }
121}
122
123impl<const CAP: usize> Default for BufEncoder<CAP> {
124 fn default() -> Self { Self::new(Case::Lower) }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn empty() {
133 let encoder = BufEncoder::<2>::new(Case::Lower);
134 assert_eq!(encoder.as_str(), "");
135 assert!(!encoder.is_full());
136
137 let encoder = BufEncoder::<2>::new(Case::Upper);
138 assert_eq!(encoder.as_str(), "");
139 assert!(!encoder.is_full());
140 }
141
142 #[test]
143 fn single_byte_exact_buf() {
144 let mut encoder = BufEncoder::<2>::new(Case::Lower);
145 assert_eq!(encoder.space_remaining(), 1);
146 encoder.put_byte(42);
147 assert_eq!(encoder.as_str(), "2a");
148 assert_eq!(encoder.space_remaining(), 0);
149 assert!(encoder.is_full());
150 encoder.clear();
151 assert_eq!(encoder.space_remaining(), 1);
152 assert!(!encoder.is_full());
153
154 let mut encoder = BufEncoder::<2>::new(Case::Upper);
155 assert_eq!(encoder.space_remaining(), 1);
156 encoder.put_byte(42);
157 assert_eq!(encoder.as_str(), "2A");
158 assert_eq!(encoder.space_remaining(), 0);
159 assert!(encoder.is_full());
160 encoder.clear();
161 assert_eq!(encoder.space_remaining(), 1);
162 assert!(!encoder.is_full());
163 }
164
165 #[test]
166 fn single_byte_oversized_buf() {
167 let mut encoder = BufEncoder::<4>::new(Case::Lower);
168 assert_eq!(encoder.space_remaining(), 2);
169 encoder.put_byte(42);
170 assert_eq!(encoder.space_remaining(), 1);
171 assert_eq!(encoder.as_str(), "2a");
172 assert!(!encoder.is_full());
173 encoder.clear();
174 assert_eq!(encoder.space_remaining(), 2);
175 assert!(!encoder.is_full());
176
177 let mut encoder = BufEncoder::<4>::new(Case::Upper);
178 assert_eq!(encoder.space_remaining(), 2);
179 encoder.put_byte(42);
180 assert_eq!(encoder.space_remaining(), 1);
181 assert_eq!(encoder.as_str(), "2A");
182 assert!(!encoder.is_full());
183 encoder.clear();
184 assert_eq!(encoder.space_remaining(), 2);
185 assert!(!encoder.is_full());
186 }
187
188 #[test]
189 fn two_bytes() {
190 let mut encoder = BufEncoder::<4>::new(Case::Lower);
191 assert_eq!(encoder.space_remaining(), 2);
192 encoder.put_byte(42);
193 assert_eq!(encoder.space_remaining(), 1);
194 encoder.put_byte(255);
195 assert_eq!(encoder.space_remaining(), 0);
196 assert_eq!(encoder.as_str(), "2aff");
197 assert!(encoder.is_full());
198 encoder.clear();
199 assert_eq!(encoder.space_remaining(), 2);
200 assert!(!encoder.is_full());
201
202 let mut encoder = BufEncoder::<4>::new(Case::Upper);
203 assert_eq!(encoder.space_remaining(), 2);
204 encoder.put_byte(42);
205 assert_eq!(encoder.space_remaining(), 1);
206 encoder.put_byte(255);
207 assert_eq!(encoder.space_remaining(), 0);
208 assert_eq!(encoder.as_str(), "2AFF");
209 assert!(encoder.is_full());
210 encoder.clear();
211 assert_eq!(encoder.space_remaining(), 2);
212 assert!(!encoder.is_full());
213 }
214
215 #[test]
216 fn put_bytes_min() {
217 let mut encoder = BufEncoder::<2>::new(Case::Lower);
218 let remainder = encoder.put_bytes_min(b"");
219 assert_eq!(remainder, b"");
220 assert_eq!(encoder.as_str(), "");
221 let remainder = encoder.put_bytes_min(b"*");
222 assert_eq!(remainder, b"");
223 assert_eq!(encoder.as_str(), "2a");
224 encoder.clear();
225 let remainder = encoder.put_bytes_min(&[42, 255]);
226 assert_eq!(remainder, &[255]);
227 assert_eq!(encoder.as_str(), "2a");
228 }
229
230 #[test]
231 fn same_as_fmt() {
232 use core::fmt::{self, Write};
233
234 struct Writer {
235 buf: [u8; 2],
236 pos: usize,
237 }
238
239 impl Writer {
240 fn as_str(&self) -> &str { core::str::from_utf8(&self.buf[..self.pos]).unwrap() }
241 }
242
243 impl Write for Writer {
244 fn write_str(&mut self, s: &str) -> fmt::Result {
245 assert!(self.pos <= 2);
246 if s.len() > 2 - self.pos {
247 Err(fmt::Error)
248 } else {
249 self.buf[self.pos..(self.pos + s.len())].copy_from_slice(s.as_bytes());
250 self.pos += s.len();
251 Ok(())
252 }
253 }
254 }
255
256 let mut writer = Writer { buf: [0u8; 2], pos: 0 };
257
258 let mut encoder = BufEncoder::<2>::new(Case::Lower);
259 for i in 0..=255 {
260 write!(writer, "{:02x}", i).unwrap();
261 encoder.put_byte(i);
262 assert_eq!(encoder.as_str(), writer.as_str());
263 writer.pos = 0;
264 encoder.clear();
265 }
266
267 let mut encoder = BufEncoder::<2>::new(Case::Upper);
268 for i in 0..=255 {
269 write!(writer, "{:02X}", i).unwrap();
270 encoder.put_byte(i);
271 assert_eq!(encoder.as_str(), writer.as_str());
272 writer.pos = 0;
273 encoder.clear();
274 }
275 }
276}