1#[cfg(feature = "read")]
4use alloc::borrow::Cow;
5#[cfg(feature = "read")]
6use alloc::string::String;
7use core::fmt;
8use core::ops::{Deref, Range, RangeFrom, RangeTo};
9use core::str;
10
11use crate::endianity::Endianity;
12use crate::read::{Error, Reader, ReaderOffsetId, Result};
13
14#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
18pub struct EndianSlice<'input, Endian>
19where
20 Endian: Endianity,
21{
22 slice: &'input [u8],
23 endian: Endian,
24}
25
26impl<'input, Endian> EndianSlice<'input, Endian>
27where
28 Endian: Endianity,
29{
30 #[inline]
32 pub fn new(slice: &'input [u8], endian: Endian) -> EndianSlice<'input, Endian> {
33 EndianSlice { slice, endian }
34 }
35
36 #[inline]
38 pub fn slice(&self) -> &'input [u8] {
39 self.slice
40 }
41
42 #[inline]
46 pub fn split_at(
47 &self,
48 idx: usize,
49 ) -> (EndianSlice<'input, Endian>, EndianSlice<'input, Endian>) {
50 (self.range_to(..idx), self.range_from(idx..))
51 }
52
53 #[inline]
55 pub fn find(&self, byte: u8) -> Option<usize> {
56 self.slice.iter().position(|ch| *ch == byte)
57 }
58
59 #[inline]
62 pub fn offset_from(&self, base: EndianSlice<'input, Endian>) -> usize {
63 let base_ptr = base.slice.as_ptr() as usize;
64 let ptr = self.slice.as_ptr() as usize;
65 debug_assert!(base_ptr <= ptr);
66 debug_assert!(ptr + self.slice.len() <= base_ptr + base.slice.len());
67 ptr - base_ptr
68 }
69
70 #[inline]
74 pub fn to_string(&self) -> Result<&'input str> {
75 str::from_utf8(self.slice).map_err(|_| Error::BadUtf8)
76 }
77
78 #[cfg(feature = "read")]
81 #[inline]
82 pub fn to_string_lossy(&self) -> Cow<'input, str> {
83 String::from_utf8_lossy(self.slice)
84 }
85
86 #[inline]
87 fn read_slice(&mut self, len: usize) -> Result<&'input [u8]> {
88 if self.slice.len() < len {
89 Err(Error::UnexpectedEof(self.offset_id()))
90 } else {
91 let val = &self.slice[..len];
92 self.slice = &self.slice[len..];
93 Ok(val)
94 }
95 }
96}
97
98impl<'input, Endian> EndianSlice<'input, Endian>
105where
106 Endian: Endianity,
107{
108 pub fn range(&self, idx: Range<usize>) -> EndianSlice<'input, Endian> {
120 EndianSlice {
121 slice: &self.slice[idx],
122 endian: self.endian,
123 }
124 }
125
126 pub fn range_from(&self, idx: RangeFrom<usize>) -> EndianSlice<'input, Endian> {
138 EndianSlice {
139 slice: &self.slice[idx],
140 endian: self.endian,
141 }
142 }
143
144 pub fn range_to(&self, idx: RangeTo<usize>) -> EndianSlice<'input, Endian> {
156 EndianSlice {
157 slice: &self.slice[idx],
158 endian: self.endian,
159 }
160 }
161}
162
163impl<'input, Endian> Deref for EndianSlice<'input, Endian>
164where
165 Endian: Endianity,
166{
167 type Target = [u8];
168 fn deref(&self) -> &Self::Target {
169 self.slice
170 }
171}
172
173impl<'input, Endian: Endianity> fmt::Debug for EndianSlice<'input, Endian> {
174 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
175 fmt.debug_tuple("EndianSlice")
176 .field(&self.endian)
177 .field(&DebugBytes(self.slice))
178 .finish()
179 }
180}
181
182struct DebugBytes<'input>(&'input [u8]);
183
184impl<'input> core::fmt::Debug for DebugBytes<'input> {
185 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
186 let mut list = fmt.debug_list();
187 list.entries(self.0.iter().take(8).copied().map(DebugByte));
188 if self.0.len() > 8 {
189 list.entry(&DebugLen(self.0.len()));
190 }
191 list.finish()
192 }
193}
194
195struct DebugByte(u8);
196
197impl fmt::Debug for DebugByte {
198 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
199 write!(fmt, "0x{:02x}", self.0)
200 }
201}
202
203struct DebugLen(usize);
204
205impl fmt::Debug for DebugLen {
206 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
207 write!(fmt, "...; {}", self.0)
208 }
209}
210
211impl<'input, Endian> Reader for EndianSlice<'input, Endian>
212where
213 Endian: Endianity,
214{
215 type Endian = Endian;
216 type Offset = usize;
217
218 #[inline]
219 fn endian(&self) -> Endian {
220 self.endian
221 }
222
223 #[inline]
224 fn len(&self) -> usize {
225 self.slice.len()
226 }
227
228 #[inline]
229 fn is_empty(&self) -> bool {
230 self.slice.is_empty()
231 }
232
233 #[inline]
234 fn empty(&mut self) {
235 self.slice = &[];
236 }
237
238 #[inline]
239 fn truncate(&mut self, len: usize) -> Result<()> {
240 if self.slice.len() < len {
241 Err(Error::UnexpectedEof(self.offset_id()))
242 } else {
243 self.slice = &self.slice[..len];
244 Ok(())
245 }
246 }
247
248 #[inline]
249 fn offset_from(&self, base: &Self) -> usize {
250 self.offset_from(*base)
251 }
252
253 #[inline]
254 fn offset_id(&self) -> ReaderOffsetId {
255 ReaderOffsetId(self.slice.as_ptr() as u64)
256 }
257
258 #[inline]
259 fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<Self::Offset> {
260 let id = id.0;
261 let self_id = self.slice.as_ptr() as u64;
262 let self_len = self.slice.len() as u64;
263 if id >= self_id && id <= self_id + self_len {
264 Some((id - self_id) as usize)
265 } else {
266 None
267 }
268 }
269
270 #[inline]
271 fn find(&self, byte: u8) -> Result<usize> {
272 self.find(byte)
273 .ok_or_else(|| Error::UnexpectedEof(self.offset_id()))
274 }
275
276 #[inline]
277 fn skip(&mut self, len: usize) -> Result<()> {
278 if self.slice.len() < len {
279 Err(Error::UnexpectedEof(self.offset_id()))
280 } else {
281 self.slice = &self.slice[len..];
282 Ok(())
283 }
284 }
285
286 #[inline]
287 fn split(&mut self, len: usize) -> Result<Self> {
288 let slice = self.read_slice(len)?;
289 Ok(EndianSlice::new(slice, self.endian))
290 }
291
292 #[cfg(not(feature = "read"))]
293 fn cannot_implement() -> super::reader::seal_if_no_alloc::Sealed {
294 super::reader::seal_if_no_alloc::Sealed
295 }
296
297 #[cfg(feature = "read")]
298 #[inline]
299 fn to_slice(&self) -> Result<Cow<'_, [u8]>> {
300 Ok(self.slice.into())
301 }
302
303 #[cfg(feature = "read")]
304 #[inline]
305 fn to_string(&self) -> Result<Cow<'_, str>> {
306 match str::from_utf8(self.slice) {
307 Ok(s) => Ok(s.into()),
308 _ => Err(Error::BadUtf8),
309 }
310 }
311
312 #[cfg(feature = "read")]
313 #[inline]
314 fn to_string_lossy(&self) -> Result<Cow<'_, str>> {
315 Ok(String::from_utf8_lossy(self.slice))
316 }
317
318 #[inline]
319 fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> {
320 let slice = self.read_slice(buf.len())?;
321 buf.copy_from_slice(slice);
322 Ok(())
323 }
324}
325
326#[cfg(test)]
327mod tests {
328 use super::*;
329 use crate::endianity::NativeEndian;
330
331 #[test]
332 fn test_endian_slice_split_at() {
333 let endian = NativeEndian;
334 let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
335 let eb = EndianSlice::new(slice, endian);
336 assert_eq!(
337 eb.split_at(3),
338 (
339 EndianSlice::new(&slice[..3], endian),
340 EndianSlice::new(&slice[3..], endian)
341 )
342 );
343 }
344
345 #[test]
346 #[should_panic]
347 fn test_endian_slice_split_at_out_of_bounds() {
348 let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
349 let eb = EndianSlice::new(slice, NativeEndian);
350 eb.split_at(30);
351 }
352}