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 #[doc(hidden)]
39 #[deprecated(note = "Method renamed to EndianSlice::slice; use that instead.")]
40 pub fn buf(&self) -> &'input [u8] {
41 self.slice
42 }
43
44 #[inline]
46 pub fn slice(&self) -> &'input [u8] {
47 self.slice
48 }
49
50 #[inline]
54 pub fn split_at(
55 &self,
56 idx: usize,
57 ) -> (EndianSlice<'input, Endian>, EndianSlice<'input, Endian>) {
58 (self.range_to(..idx), self.range_from(idx..))
59 }
60
61 #[inline]
63 pub fn find(&self, byte: u8) -> Option<usize> {
64 self.slice.iter().position(|ch| *ch == byte)
65 }
66
67 #[inline]
70 pub fn offset_from(&self, base: EndianSlice<'input, Endian>) -> usize {
71 let base_ptr = base.slice.as_ptr() as usize;
72 let ptr = self.slice.as_ptr() as usize;
73 debug_assert!(base_ptr <= ptr);
74 debug_assert!(ptr + self.slice.len() <= base_ptr + base.slice.len());
75 ptr - base_ptr
76 }
77
78 #[inline]
82 pub fn to_string(&self) -> Result<&'input str> {
83 str::from_utf8(self.slice).map_err(|_| Error::BadUtf8)
84 }
85
86 #[cfg(feature = "read")]
89 #[inline]
90 pub fn to_string_lossy(&self) -> Cow<'input, str> {
91 String::from_utf8_lossy(self.slice)
92 }
93
94 #[inline]
95 fn read_slice(&mut self, len: usize) -> Result<&'input [u8]> {
96 if self.slice.len() < len {
97 Err(Error::UnexpectedEof(self.offset_id()))
98 } else {
99 let val = &self.slice[..len];
100 self.slice = &self.slice[len..];
101 Ok(val)
102 }
103 }
104}
105
106impl<'input, Endian> EndianSlice<'input, Endian>
113where
114 Endian: Endianity,
115{
116 pub fn range(&self, idx: Range<usize>) -> EndianSlice<'input, Endian> {
128 EndianSlice {
129 slice: &self.slice[idx],
130 endian: self.endian,
131 }
132 }
133
134 pub fn range_from(&self, idx: RangeFrom<usize>) -> EndianSlice<'input, Endian> {
146 EndianSlice {
147 slice: &self.slice[idx],
148 endian: self.endian,
149 }
150 }
151
152 pub fn range_to(&self, idx: RangeTo<usize>) -> EndianSlice<'input, Endian> {
164 EndianSlice {
165 slice: &self.slice[idx],
166 endian: self.endian,
167 }
168 }
169}
170
171impl<'input, Endian> Deref for EndianSlice<'input, Endian>
172where
173 Endian: Endianity,
174{
175 type Target = [u8];
176 fn deref(&self) -> &Self::Target {
177 self.slice
178 }
179}
180
181impl<'input, Endian: Endianity> fmt::Debug for EndianSlice<'input, Endian> {
182 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
183 fmt.debug_tuple("EndianSlice")
184 .field(&self.endian)
185 .field(&DebugBytes(self.slice))
186 .finish()
187 }
188}
189
190struct DebugBytes<'input>(&'input [u8]);
191
192impl<'input> core::fmt::Debug for DebugBytes<'input> {
193 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
194 let mut list = fmt.debug_list();
195 list.entries(self.0.iter().take(8).copied().map(DebugByte));
196 if self.0.len() > 8 {
197 list.entry(&DebugLen(self.0.len()));
198 }
199 list.finish()
200 }
201}
202
203struct DebugByte(u8);
204
205impl fmt::Debug for DebugByte {
206 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
207 write!(fmt, "0x{:02x}", self.0)
208 }
209}
210
211struct DebugLen(usize);
212
213impl fmt::Debug for DebugLen {
214 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
215 write!(fmt, "...; {}", self.0)
216 }
217}
218
219impl<'input, Endian> Reader for EndianSlice<'input, Endian>
220where
221 Endian: Endianity,
222{
223 type Endian = Endian;
224 type Offset = usize;
225
226 #[inline]
227 fn endian(&self) -> Endian {
228 self.endian
229 }
230
231 #[inline]
232 fn len(&self) -> usize {
233 self.slice.len()
234 }
235
236 #[inline]
237 fn is_empty(&self) -> bool {
238 self.slice.is_empty()
239 }
240
241 #[inline]
242 fn empty(&mut self) {
243 self.slice = &[];
244 }
245
246 #[inline]
247 fn truncate(&mut self, len: usize) -> Result<()> {
248 if self.slice.len() < len {
249 Err(Error::UnexpectedEof(self.offset_id()))
250 } else {
251 self.slice = &self.slice[..len];
252 Ok(())
253 }
254 }
255
256 #[inline]
257 fn offset_from(&self, base: &Self) -> usize {
258 self.offset_from(*base)
259 }
260
261 #[inline]
262 fn offset_id(&self) -> ReaderOffsetId {
263 ReaderOffsetId(self.slice.as_ptr() as u64)
264 }
265
266 #[inline]
267 fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<Self::Offset> {
268 let id = id.0;
269 let self_id = self.slice.as_ptr() as u64;
270 let self_len = self.slice.len() as u64;
271 if id >= self_id && id <= self_id + self_len {
272 Some((id - self_id) as usize)
273 } else {
274 None
275 }
276 }
277
278 #[inline]
279 fn find(&self, byte: u8) -> Result<usize> {
280 self.find(byte)
281 .ok_or_else(|| Error::UnexpectedEof(self.offset_id()))
282 }
283
284 #[inline]
285 fn skip(&mut self, len: usize) -> Result<()> {
286 if self.slice.len() < len {
287 Err(Error::UnexpectedEof(self.offset_id()))
288 } else {
289 self.slice = &self.slice[len..];
290 Ok(())
291 }
292 }
293
294 #[inline]
295 fn split(&mut self, len: usize) -> Result<Self> {
296 let slice = self.read_slice(len)?;
297 Ok(EndianSlice::new(slice, self.endian))
298 }
299
300 #[cfg(not(feature = "read"))]
301 fn cannot_implement() -> super::reader::seal_if_no_alloc::Sealed {
302 super::reader::seal_if_no_alloc::Sealed
303 }
304
305 #[cfg(feature = "read")]
306 #[inline]
307 fn to_slice(&self) -> Result<Cow<'_, [u8]>> {
308 Ok(self.slice.into())
309 }
310
311 #[cfg(feature = "read")]
312 #[inline]
313 fn to_string(&self) -> Result<Cow<'_, str>> {
314 match str::from_utf8(self.slice) {
315 Ok(s) => Ok(s.into()),
316 _ => Err(Error::BadUtf8),
317 }
318 }
319
320 #[cfg(feature = "read")]
321 #[inline]
322 fn to_string_lossy(&self) -> Result<Cow<'_, str>> {
323 Ok(String::from_utf8_lossy(self.slice))
324 }
325
326 #[inline]
327 fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> {
328 let slice = self.read_slice(buf.len())?;
329 buf.copy_from_slice(slice);
330 Ok(())
331 }
332}
333
334#[cfg(test)]
335mod tests {
336 use super::*;
337 use crate::endianity::NativeEndian;
338
339 #[test]
340 fn test_endian_slice_split_at() {
341 let endian = NativeEndian;
342 let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
343 let eb = EndianSlice::new(slice, endian);
344 assert_eq!(
345 eb.split_at(3),
346 (
347 EndianSlice::new(&slice[..3], endian),
348 EndianSlice::new(&slice[3..], endian)
349 )
350 );
351 }
352
353 #[test]
354 #[should_panic]
355 fn test_endian_slice_split_at_out_of_bounds() {
356 let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
357 let eb = EndianSlice::new(slice, NativeEndian);
358 eb.split_at(30);
359 }
360}