1use core::{marker::PhantomData, fmt::Debug};
4
5#[allow(clippy::len_without_is_empty)]
9pub trait BytesLike<'bytes>: Sized + Debug {
10 type Error: Sized + Copy + Debug;
12
13 type ExternallyTrackedLength: Sized + Copy + Debug;
18
19 fn len(&self, len: Self::ExternallyTrackedLength) -> usize;
21
22 fn peek(&self, i: usize) -> Result<u8, Self::Error>;
24
25 fn read_bytes(
29 &mut self,
30 bytes: usize,
31 ) -> Result<(Self::ExternallyTrackedLength, Self), Self::Error>;
32
33 fn read_into_slice(&mut self, slice: &mut [u8]) -> Result<(), Self::Error>;
39
40 #[inline(always)]
42 fn read_byte(&mut self) -> Result<u8, Self::Error> {
43 let mut buf = [0; 1];
44 self.read_into_slice(&mut buf)?;
45 Ok(buf[0])
46 }
47
48 #[inline(always)]
50 fn advance(&mut self, bytes: usize) -> Result<(), Self::Error> {
51 self.read_bytes(bytes).map(|_| ())
52 }
53}
54
55#[derive(Clone, Copy, Debug)]
57#[allow(dead_code)]
58pub enum SliceError {
59 Short(usize),
61}
62
63impl<'bytes> BytesLike<'bytes> for &'bytes [u8] {
64 type Error = SliceError;
65
66 type ExternallyTrackedLength = ();
67
68 #[inline(always)]
69 fn len(&self, (): ()) -> usize {
70 <[u8]>::len(self)
71 }
72
73 #[inline(always)]
74 fn peek(&self, i: usize) -> Result<u8, Self::Error> {
75 self.get(i).ok_or_else(|| SliceError::Short((i - <[u8]>::len(self)).saturating_add(1))).copied()
76 }
77
78 #[inline(always)]
79 fn read_bytes(
80 &mut self,
81 bytes: usize,
82 ) -> Result<(Self::ExternallyTrackedLength, Self), Self::Error> {
83 if <[u8]>::len(self) < bytes {
84 Err(SliceError::Short(bytes))?;
85 }
86 let res = &self[.. bytes];
87 *self = &self[bytes ..];
88 Ok(((), res))
89 }
90
91 #[inline(always)]
92 fn read_into_slice(&mut self, slice: &mut [u8]) -> Result<(), Self::Error> {
93 slice.copy_from_slice(self.read_bytes(slice.len())?.1);
94 Ok(())
95 }
96}
97
98#[derive(Debug)]
103pub(crate) struct String<'bytes, B: BytesLike<'bytes>> {
104 pub(crate) len: B::ExternallyTrackedLength,
105 pub(crate) bytes: B,
106 pub(crate) _encoding: PhantomData<&'bytes ()>,
107}
108
109impl<'bytes, B: BytesLike<'bytes>> String<'bytes, B> {
110 #[inline(always)]
112 pub(crate) fn len(&self) -> usize {
113 self.bytes.len(self.len)
114 }
115
116 #[inline(always)]
118 pub(crate) fn consume(self) -> B {
119 self.bytes
120 }
121}