1 | use core::num::NonZeroUsize; |
2 | |
3 | use crate::error::Needed; |
4 | use crate::lib::std::iter::{Cloned, Enumerate}; |
5 | use crate::lib::std::slice::Iter; |
6 | use crate::lib::std::{cmp::Ordering, fmt, ops}; |
7 | use crate::stream::AsBytes; |
8 | use crate::stream::Checkpoint; |
9 | use crate::stream::Compare; |
10 | use crate::stream::CompareResult; |
11 | use crate::stream::FindSlice; |
12 | use crate::stream::Offset; |
13 | #[cfg (feature = "unstable-recover" )] |
14 | #[cfg (feature = "std" )] |
15 | use crate::stream::Recover; |
16 | use crate::stream::SliceLen; |
17 | use crate::stream::Stream; |
18 | use crate::stream::StreamIsPartial; |
19 | use crate::stream::UpdateSlice; |
20 | |
21 | /// Improved `Debug` experience for `&[u8]` byte streams |
22 | #[allow (clippy::derived_hash_with_manual_eq)] |
23 | #[derive (Hash)] |
24 | #[repr (transparent)] |
25 | pub struct Bytes([u8]); |
26 | |
27 | impl Bytes { |
28 | /// Make a stream out of a byte slice-like. |
29 | #[inline ] |
30 | pub fn new<B: ?Sized + AsRef<[u8]>>(bytes: &B) -> &Self { |
31 | Self::from_bytes(slice:bytes.as_ref()) |
32 | } |
33 | |
34 | #[inline ] |
35 | fn from_bytes(slice: &[u8]) -> &Self { |
36 | unsafe { crate::lib::std::mem::transmute(src:slice) } |
37 | } |
38 | |
39 | #[inline ] |
40 | fn as_bytes(&self) -> &[u8] { |
41 | &self.0 |
42 | } |
43 | } |
44 | |
45 | impl SliceLen for &Bytes { |
46 | #[inline (always)] |
47 | fn slice_len(&self) -> usize { |
48 | self.len() |
49 | } |
50 | } |
51 | |
52 | impl<'i> Stream for &'i Bytes { |
53 | type Token = u8; |
54 | type Slice = &'i [u8]; |
55 | |
56 | type IterOffsets = Enumerate<Cloned<Iter<'i, u8>>>; |
57 | |
58 | type Checkpoint = Checkpoint<Self, Self>; |
59 | |
60 | #[inline (always)] |
61 | fn iter_offsets(&self) -> Self::IterOffsets { |
62 | self.iter().cloned().enumerate() |
63 | } |
64 | #[inline (always)] |
65 | fn eof_offset(&self) -> usize { |
66 | self.len() |
67 | } |
68 | |
69 | #[inline (always)] |
70 | fn next_token(&mut self) -> Option<Self::Token> { |
71 | if self.is_empty() { |
72 | None |
73 | } else { |
74 | let token = self[0]; |
75 | *self = &self[1..]; |
76 | Some(token) |
77 | } |
78 | } |
79 | |
80 | #[inline (always)] |
81 | fn peek_token(&self) -> Option<Self::Token> { |
82 | if self.is_empty() { |
83 | None |
84 | } else { |
85 | Some(self[0]) |
86 | } |
87 | } |
88 | |
89 | #[inline (always)] |
90 | fn offset_for<P>(&self, predicate: P) -> Option<usize> |
91 | where |
92 | P: Fn(Self::Token) -> bool, |
93 | { |
94 | self.iter().position(|b| predicate(*b)) |
95 | } |
96 | #[inline (always)] |
97 | fn offset_at(&self, tokens: usize) -> Result<usize, Needed> { |
98 | if let Some(needed) = tokens.checked_sub(self.len()).and_then(NonZeroUsize::new) { |
99 | Err(Needed::Size(needed)) |
100 | } else { |
101 | Ok(tokens) |
102 | } |
103 | } |
104 | #[inline (always)] |
105 | fn next_slice(&mut self, offset: usize) -> Self::Slice { |
106 | let (slice, next) = self.0.split_at(offset); |
107 | *self = Bytes::from_bytes(next); |
108 | slice |
109 | } |
110 | #[inline (always)] |
111 | unsafe fn next_slice_unchecked(&mut self, offset: usize) -> Self::Slice { |
112 | #[cfg (debug_assertions)] |
113 | self.peek_slice(offset); |
114 | |
115 | // SAFETY: `Stream::next_slice_unchecked` requires `offset` to be in bounds |
116 | let slice = unsafe { self.0.get_unchecked(..offset) }; |
117 | // SAFETY: `Stream::next_slice_unchecked` requires `offset` to be in bounds |
118 | let next = unsafe { self.0.get_unchecked(offset..) }; |
119 | *self = Bytes::from_bytes(next); |
120 | slice |
121 | } |
122 | #[inline (always)] |
123 | fn peek_slice(&self, offset: usize) -> Self::Slice { |
124 | &self[..offset] |
125 | } |
126 | #[inline (always)] |
127 | unsafe fn peek_slice_unchecked(&self, offset: usize) -> Self::Slice { |
128 | #[cfg (debug_assertions)] |
129 | self.peek_slice(offset); |
130 | |
131 | // SAFETY: `Stream::next_slice_unchecked` requires `offset` to be in bounds |
132 | let slice = unsafe { self.0.get_unchecked(..offset) }; |
133 | slice |
134 | } |
135 | |
136 | #[inline (always)] |
137 | fn checkpoint(&self) -> Self::Checkpoint { |
138 | Checkpoint::<_, Self>::new(*self) |
139 | } |
140 | #[inline (always)] |
141 | fn reset(&mut self, checkpoint: &Self::Checkpoint) { |
142 | *self = checkpoint.inner; |
143 | } |
144 | |
145 | #[inline (always)] |
146 | fn raw(&self) -> &dyn crate::lib::std::fmt::Debug { |
147 | self |
148 | } |
149 | } |
150 | |
151 | #[cfg (feature = "unstable-recover" )] |
152 | #[cfg (feature = "std" )] |
153 | impl<E> Recover<E> for &Bytes { |
154 | #[inline (always)] |
155 | fn record_err( |
156 | &mut self, |
157 | _token_start: &Self::Checkpoint, |
158 | _err_start: &Self::Checkpoint, |
159 | err: E, |
160 | ) -> Result<(), E> { |
161 | Err(err) |
162 | } |
163 | |
164 | /// Report whether the [`Stream`] can save off errors for recovery |
165 | #[inline (always)] |
166 | fn is_recovery_supported() -> bool { |
167 | false |
168 | } |
169 | } |
170 | |
171 | impl StreamIsPartial for &Bytes { |
172 | type PartialState = (); |
173 | |
174 | #[inline ] |
175 | fn complete(&mut self) -> Self::PartialState { |
176 | // Already complete |
177 | } |
178 | |
179 | #[inline ] |
180 | fn restore_partial(&mut self, _state: Self::PartialState) {} |
181 | |
182 | #[inline (always)] |
183 | fn is_partial_supported() -> bool { |
184 | false |
185 | } |
186 | } |
187 | |
188 | impl Offset for &Bytes { |
189 | #[inline (always)] |
190 | fn offset_from(&self, start: &Self) -> usize { |
191 | self.as_bytes().offset_from(&start.as_bytes()) |
192 | } |
193 | } |
194 | |
195 | impl<'a> Offset<<&'a Bytes as Stream>::Checkpoint> for &'a Bytes { |
196 | #[inline (always)] |
197 | fn offset_from(&self, other: &<&'a Bytes as Stream>::Checkpoint) -> usize { |
198 | self.checkpoint().offset_from(start:other) |
199 | } |
200 | } |
201 | |
202 | impl AsBytes for &Bytes { |
203 | #[inline (always)] |
204 | fn as_bytes(&self) -> &[u8] { |
205 | (*self).as_bytes() |
206 | } |
207 | } |
208 | |
209 | impl<'a, T> Compare<T> for &'a Bytes |
210 | where |
211 | &'a [u8]: Compare<T>, |
212 | { |
213 | #[inline (always)] |
214 | fn compare(&self, t: T) -> CompareResult { |
215 | let bytes: &[u8] = (*self).as_bytes(); |
216 | bytes.compare(t) |
217 | } |
218 | } |
219 | |
220 | impl<'i, S> FindSlice<S> for &'i Bytes |
221 | where |
222 | &'i [u8]: FindSlice<S>, |
223 | { |
224 | #[inline (always)] |
225 | fn find_slice(&self, substr: S) -> Option<crate::lib::std::ops::Range<usize>> { |
226 | let bytes: &[u8] = (*self).as_bytes(); |
227 | let offset: Option> = bytes.find_slice(substr); |
228 | offset |
229 | } |
230 | } |
231 | |
232 | impl UpdateSlice for &Bytes { |
233 | #[inline (always)] |
234 | fn update_slice(self, inner: Self::Slice) -> Self { |
235 | Bytes::new(bytes:inner) |
236 | } |
237 | } |
238 | |
239 | impl fmt::Display for Bytes { |
240 | #[inline ] |
241 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
242 | <Self as fmt::UpperHex>::fmt(self, f) |
243 | } |
244 | } |
245 | |
246 | impl fmt::Debug for Bytes { |
247 | #[inline ] |
248 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
249 | <Self as fmt::UpperHex>::fmt(self, f) |
250 | } |
251 | } |
252 | |
253 | impl fmt::LowerHex for Bytes { |
254 | #[inline ] |
255 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
256 | for byte: &u8 in self.as_bytes() { |
257 | write!(f, " {byte:0>2x}" )?; |
258 | } |
259 | Ok(()) |
260 | } |
261 | } |
262 | |
263 | impl fmt::UpperHex for Bytes { |
264 | #[inline ] |
265 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
266 | for (i: usize, byte: &u8) in self.as_bytes().iter().enumerate() { |
267 | if 0 < i { |
268 | let absolute: usize = (self.as_bytes().as_ptr() as usize) + i; |
269 | if f.alternate() && absolute != 0 && absolute % 4 == 0 { |
270 | write!(f, "_" )?; |
271 | } |
272 | } |
273 | write!(f, " {byte:0>2X}" )?; |
274 | } |
275 | Ok(()) |
276 | } |
277 | } |
278 | |
279 | impl ops::Deref for Bytes { |
280 | type Target = [u8]; |
281 | |
282 | #[inline ] |
283 | fn deref(&self) -> &[u8] { |
284 | self.as_bytes() |
285 | } |
286 | } |
287 | |
288 | impl ops::Index<usize> for Bytes { |
289 | type Output = u8; |
290 | |
291 | #[inline ] |
292 | fn index(&self, idx: usize) -> &u8 { |
293 | &self.as_bytes()[idx] |
294 | } |
295 | } |
296 | |
297 | impl ops::Index<ops::RangeFull> for Bytes { |
298 | type Output = Bytes; |
299 | |
300 | #[inline ] |
301 | fn index(&self, _: ops::RangeFull) -> &Bytes { |
302 | self |
303 | } |
304 | } |
305 | |
306 | impl ops::Index<ops::Range<usize>> for Bytes { |
307 | type Output = Bytes; |
308 | |
309 | #[inline ] |
310 | fn index(&self, r: ops::Range<usize>) -> &Bytes { |
311 | Bytes::new(&self.as_bytes()[r.start..r.end]) |
312 | } |
313 | } |
314 | |
315 | impl ops::Index<ops::RangeInclusive<usize>> for Bytes { |
316 | type Output = Bytes; |
317 | |
318 | #[inline ] |
319 | fn index(&self, r: ops::RangeInclusive<usize>) -> &Bytes { |
320 | Bytes::new(&self.as_bytes()[*r.start()..=*r.end()]) |
321 | } |
322 | } |
323 | |
324 | impl ops::Index<ops::RangeFrom<usize>> for Bytes { |
325 | type Output = Bytes; |
326 | |
327 | #[inline ] |
328 | fn index(&self, r: ops::RangeFrom<usize>) -> &Bytes { |
329 | Bytes::new(&self.as_bytes()[r.start..]) |
330 | } |
331 | } |
332 | |
333 | impl ops::Index<ops::RangeTo<usize>> for Bytes { |
334 | type Output = Bytes; |
335 | |
336 | #[inline ] |
337 | fn index(&self, r: ops::RangeTo<usize>) -> &Bytes { |
338 | Bytes::new(&self.as_bytes()[..r.end]) |
339 | } |
340 | } |
341 | |
342 | impl ops::Index<ops::RangeToInclusive<usize>> for Bytes { |
343 | type Output = Bytes; |
344 | |
345 | #[inline ] |
346 | fn index(&self, r: ops::RangeToInclusive<usize>) -> &Bytes { |
347 | Bytes::new(&self.as_bytes()[..=r.end]) |
348 | } |
349 | } |
350 | |
351 | impl AsRef<[u8]> for Bytes { |
352 | #[inline ] |
353 | fn as_ref(&self) -> &[u8] { |
354 | self.as_bytes() |
355 | } |
356 | } |
357 | |
358 | impl AsRef<Bytes> for [u8] { |
359 | #[inline ] |
360 | fn as_ref(&self) -> &Bytes { |
361 | Bytes::new(self) |
362 | } |
363 | } |
364 | |
365 | impl AsRef<Bytes> for str { |
366 | #[inline ] |
367 | fn as_ref(&self) -> &Bytes { |
368 | Bytes::new(self) |
369 | } |
370 | } |
371 | |
372 | #[cfg (feature = "alloc" )] |
373 | impl crate::lib::std::borrow::ToOwned for Bytes { |
374 | type Owned = crate::lib::std::vec::Vec<u8>; |
375 | |
376 | #[inline ] |
377 | fn to_owned(&self) -> Self::Owned { |
378 | crate::lib::std::vec::Vec::from(self.as_bytes()) |
379 | } |
380 | } |
381 | |
382 | #[cfg (feature = "alloc" )] |
383 | impl crate::lib::std::borrow::Borrow<Bytes> for crate::lib::std::vec::Vec<u8> { |
384 | #[inline ] |
385 | fn borrow(&self) -> &Bytes { |
386 | Bytes::from_bytes(self.as_slice()) |
387 | } |
388 | } |
389 | |
390 | impl<'a> Default for &'a Bytes { |
391 | fn default() -> &'a Bytes { |
392 | Bytes::new(bytes:b"" ) |
393 | } |
394 | } |
395 | |
396 | impl<'a> From<&'a [u8]> for &'a Bytes { |
397 | #[inline ] |
398 | fn from(s: &'a [u8]) -> &'a Bytes { |
399 | Bytes::new(bytes:s) |
400 | } |
401 | } |
402 | |
403 | impl<'a> From<&'a Bytes> for &'a [u8] { |
404 | #[inline ] |
405 | fn from(s: &'a Bytes) -> &'a [u8] { |
406 | Bytes::as_bytes(self:s) |
407 | } |
408 | } |
409 | |
410 | impl<'a> From<&'a str> for &'a Bytes { |
411 | #[inline ] |
412 | fn from(s: &'a str) -> &'a Bytes { |
413 | Bytes::new(s.as_bytes()) |
414 | } |
415 | } |
416 | |
417 | impl Eq for Bytes {} |
418 | |
419 | impl PartialEq<Bytes> for Bytes { |
420 | #[inline ] |
421 | fn eq(&self, other: &Bytes) -> bool { |
422 | self.as_bytes() == other.as_bytes() |
423 | } |
424 | } |
425 | |
426 | impl_partial_eq!(Bytes, [u8]); |
427 | impl_partial_eq!(Bytes, &'a [u8]); |
428 | impl_partial_eq!(Bytes, str); |
429 | impl_partial_eq!(Bytes, &'a str); |
430 | |
431 | impl PartialOrd for Bytes { |
432 | #[inline ] |
433 | fn partial_cmp(&self, other: &Bytes) -> Option<Ordering> { |
434 | Some(self.cmp(other)) |
435 | } |
436 | } |
437 | |
438 | impl Ord for Bytes { |
439 | #[inline ] |
440 | fn cmp(&self, other: &Bytes) -> Ordering { |
441 | Ord::cmp(self.as_bytes(), other.as_bytes()) |
442 | } |
443 | } |
444 | |
445 | impl_partial_ord!(Bytes, [u8]); |
446 | impl_partial_ord!(Bytes, &'a [u8]); |
447 | impl_partial_ord!(Bytes, str); |
448 | impl_partial_ord!(Bytes, &'a str); |
449 | |
450 | #[cfg (all(test, feature = "std" ))] |
451 | mod display { |
452 | use crate::stream::Bytes; |
453 | |
454 | #[test ] |
455 | fn clean() { |
456 | assert_eq!(&format!("{}" , Bytes::new(b"abc" )), "616263" ); |
457 | assert_eq!(&format!("{}" , Bytes::new(b" \xf0\x28\x8c\xbc" )), "F0288CBC" ); |
458 | } |
459 | } |
460 | |
461 | #[cfg (all(test, feature = "std" ))] |
462 | mod debug { |
463 | use crate::stream::Bytes; |
464 | |
465 | #[test ] |
466 | fn test_debug() { |
467 | assert_eq!( |
468 | "000000206674797069736F6D0000020069736F6D69736F32617663316D70" , |
469 | format!( |
470 | "{:?}" , |
471 | Bytes::new(b" \0\0\0 ftypisom \0\0\x02\0isomiso2avc1mp" ) |
472 | ), |
473 | ); |
474 | } |
475 | |
476 | #[test ] |
477 | fn test_pretty_debug() { |
478 | // Output can change from run-to-run |
479 | let _ = format!( |
480 | "{:#?}" , |
481 | Bytes::new(b" \0\0\0 ftypisom \0\0\x02\0isomiso2avc1mp" ) |
482 | ); |
483 | } |
484 | |
485 | #[test ] |
486 | fn test_sliced() { |
487 | // Output can change from run-to-run |
488 | let total = Bytes::new(b"12345678901234567890" ); |
489 | let _ = format!("{total:#?}" ); |
490 | let _ = format!("{:#?}" , &total[1..]); |
491 | let _ = format!("{:#?}" , &total[10..]); |
492 | } |
493 | } |
494 | |