1 //! Working with byte slices that have an associated endianity.
3 use alloc
::borrow
::Cow
;
4 use alloc
::string
::String
;
5 use core
::ops
::{Deref, Index, Range, RangeFrom, RangeTo}
;
8 use crate::endianity
::Endianity
;
9 use crate::read
::{Error, Reader, ReaderOffsetId, Result}
;
11 /// A `&[u8]` slice with endianity metadata.
13 /// This implements the `Reader` trait, which is used for all reading of DWARF sections.
14 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
15 pub struct EndianSlice
<'input
, Endian
>
23 impl<'input
, Endian
> EndianSlice
<'input
, Endian
>
27 /// Construct a new `EndianSlice` with the given slice and endianity.
29 pub fn new(slice
: &'input
[u8], endian
: Endian
) -> EndianSlice
<'input
, Endian
> {
30 EndianSlice { slice, endian }
33 /// Return a reference to the raw slice.
36 #[deprecated(note = "Method renamed to EndianSlice::slice; use that instead.")]
37 pub fn buf(&self) -> &'input
[u8] {
41 /// Return a reference to the raw slice.
43 pub fn slice(&self) -> &'input
[u8] {
47 /// Split the slice in two at the given index, resulting in the tuple where
48 /// the first item has range [0, idx), and the second has range [idx,
49 /// len). Panics if the index is out of bounds.
54 ) -> (EndianSlice
<'input
, Endian
>, EndianSlice
<'input
, Endian
>) {
55 (self.range_to(..idx
), self.range_from(idx
..))
58 /// Find the first occurence of a byte in the slice, and return its index.
60 pub fn find(&self, byte
: u8) -> Option
<usize> {
61 self.slice
.iter().position(|ch
| *ch
== byte
)
64 /// Return the offset of the start of the slice relative to the start
65 /// of the given slice.
67 pub fn offset_from(&self, base
: EndianSlice
<'input
, Endian
>) -> usize {
68 let base_ptr
= base
.slice
.as_ptr() as *const u8 as usize;
69 let ptr
= self.slice
.as_ptr() as *const u8 as usize;
70 debug_assert
!(base_ptr
<= ptr
);
71 debug_assert
!(ptr
+ self.slice
.len() <= base_ptr
+ base
.slice
.len());
75 /// Converts the slice to a string using `str::from_utf8`.
77 /// Returns an error if the slice contains invalid characters.
79 pub fn to_string(&self) -> Result
<&'input
str> {
80 str::from_utf8(self.slice
).map_err(|_
| Error
::BadUtf8
)
83 /// Converts the slice to a string, including invalid characters,
84 /// using `String::from_utf8_lossy`.
86 pub fn to_string_lossy(&self) -> Cow
<'input
, str> {
87 String
::from_utf8_lossy(self.slice
)
91 fn read_slice(&mut self, len
: usize) -> Result
<&'input
[u8]> {
92 if self.slice
.len() < len
{
93 Err(Error
::UnexpectedEof(self.offset_id()))
95 let val
= &self.slice
[..len
];
96 self.slice
= &self.slice
[len
..];
104 /// Unfortunately, `std::ops::Index` *must* return a reference, so we can't
105 /// implement `Index<Range<usize>>` to return a new `EndianSlice` the way we would
106 /// like to. Instead, we abandon fancy indexing operators and have these plain
108 impl<'input
, Endian
> EndianSlice
<'input
, Endian
>
112 /// Take the given `start..end` range of the underlying slice and return a
113 /// new `EndianSlice`.
116 /// use gimli::{EndianSlice, LittleEndian};
118 /// let slice = &[0x01, 0x02, 0x03, 0x04];
119 /// let endian_slice = EndianSlice::new(slice, LittleEndian);
120 /// assert_eq!(endian_slice.range(1..3),
121 /// EndianSlice::new(&slice[1..3], LittleEndian));
123 pub fn range(&self, idx
: Range
<usize>) -> EndianSlice
<'input
, Endian
> {
125 slice
: &self.slice
[idx
],
130 /// Take the given `start..` range of the underlying slice and return a new
134 /// use gimli::{EndianSlice, LittleEndian};
136 /// let slice = &[0x01, 0x02, 0x03, 0x04];
137 /// let endian_slice = EndianSlice::new(slice, LittleEndian);
138 /// assert_eq!(endian_slice.range_from(2..),
139 /// EndianSlice::new(&slice[2..], LittleEndian));
141 pub fn range_from(&self, idx
: RangeFrom
<usize>) -> EndianSlice
<'input
, Endian
> {
143 slice
: &self.slice
[idx
],
148 /// Take the given `..end` range of the underlying slice and return a new
152 /// use gimli::{EndianSlice, LittleEndian};
154 /// let slice = &[0x01, 0x02, 0x03, 0x04];
155 /// let endian_slice = EndianSlice::new(slice, LittleEndian);
156 /// assert_eq!(endian_slice.range_to(..3),
157 /// EndianSlice::new(&slice[..3], LittleEndian));
159 pub fn range_to(&self, idx
: RangeTo
<usize>) -> EndianSlice
<'input
, Endian
> {
161 slice
: &self.slice
[idx
],
167 impl<'input
, Endian
> Index
<usize> for EndianSlice
<'input
, Endian
>
172 fn index(&self, idx
: usize) -> &Self::Output
{
177 impl<'input
, Endian
> Index
<RangeFrom
<usize>> for EndianSlice
<'input
, Endian
>
182 fn index(&self, idx
: RangeFrom
<usize>) -> &Self::Output
{
187 impl<'input
, Endian
> Deref
for EndianSlice
<'input
, Endian
>
192 fn deref(&self) -> &Self::Target
{
197 impl<'input
, Endian
> Into
<&'input
[u8]> for EndianSlice
<'input
, Endian
>
201 fn into(self) -> &'input
[u8] {
206 impl<'input
, Endian
> Reader
for EndianSlice
<'input
, Endian
>
210 type Endian
= Endian
;
214 fn endian(&self) -> Endian
{
219 fn len(&self) -> usize {
224 fn is_empty(&self) -> bool
{
225 self.slice
.is_empty()
229 fn empty(&mut self) {
234 fn truncate(&mut self, len
: usize) -> Result
<()> {
235 if self.slice
.len() < len
{
236 Err(Error
::UnexpectedEof(self.offset_id()))
238 self.slice
= &self.slice
[..len
];
244 fn offset_from(&self, base
: &Self) -> usize {
245 self.offset_from(*base
)
249 fn offset_id(&self) -> ReaderOffsetId
{
250 ReaderOffsetId(self.slice
.as_ptr() as u64)
254 fn lookup_offset_id(&self, id
: ReaderOffsetId
) -> Option
<Self::Offset
> {
256 let self_id
= self.slice
.as_ptr() as u64;
257 let self_len
= self.slice
.len() as u64;
258 if id
>= self_id
&& id
<= self_id
+ self_len
{
259 Some((id
- self_id
) as usize)
266 fn find(&self, byte
: u8) -> Result
<usize> {
268 .ok_or_else(|| Error
::UnexpectedEof(self.offset_id()))
272 fn skip(&mut self, len
: usize) -> Result
<()> {
273 if self.slice
.len() < len
{
274 Err(Error
::UnexpectedEof(self.offset_id()))
276 self.slice
= &self.slice
[len
..];
282 fn split(&mut self, len
: usize) -> Result
<Self> {
283 let slice
= self.read_slice(len
)?
;
284 Ok(EndianSlice
::new(slice
, self.endian
))
288 fn to_slice(&self) -> Result
<Cow
<[u8]>> {
289 Ok(self.slice
.into())
293 fn to_string(&self) -> Result
<Cow
<str>> {
294 match str::from_utf8(self.slice
) {
295 Ok(s
) => Ok(s
.into()),
296 _
=> Err(Error
::BadUtf8
),
301 fn to_string_lossy(&self) -> Result
<Cow
<str>> {
302 Ok(String
::from_utf8_lossy(self.slice
))
306 fn read_slice(&mut self, buf
: &mut [u8]) -> Result
<()> {
307 let slice
= self.read_slice(buf
.len())?
;
308 buf
.clone_from_slice(slice
);
316 use crate::endianity
::NativeEndian
;
319 fn test_endian_slice_split_at() {
320 let endian
= NativeEndian
;
321 let slice
= &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
322 let eb
= EndianSlice
::new(slice
, endian
);
326 EndianSlice
::new(&slice
[..3], endian
),
327 EndianSlice
::new(&slice
[3..], endian
)
334 fn test_endian_slice_split_at_out_of_bounds() {
335 let slice
= &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
336 let eb
= EndianSlice
::new(slice
, NativeEndian
);