]> git.proxmox.com Git - rustc.git/blob - vendor/gimli/src/read/endian_slice.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / vendor / gimli / src / read / endian_slice.rs
1 //! Working with byte slices that have an associated endianity.
2
3 use alloc::borrow::Cow;
4 use alloc::string::String;
5 use core::ops::{Deref, Index, Range, RangeFrom, RangeTo};
6 use core::str;
7
8 use crate::endianity::Endianity;
9 use crate::read::{Error, Reader, ReaderOffsetId, Result};
10
11 /// A `&[u8]` slice with endianity metadata.
12 ///
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>
16 where
17 Endian: Endianity,
18 {
19 slice: &'input [u8],
20 endian: Endian,
21 }
22
23 impl<'input, Endian> EndianSlice<'input, Endian>
24 where
25 Endian: Endianity,
26 {
27 /// Construct a new `EndianSlice` with the given slice and endianity.
28 #[inline]
29 pub fn new(slice: &'input [u8], endian: Endian) -> EndianSlice<'input, Endian> {
30 EndianSlice { slice, endian }
31 }
32
33 /// Return a reference to the raw slice.
34 #[inline]
35 #[doc(hidden)]
36 #[deprecated(note = "Method renamed to EndianSlice::slice; use that instead.")]
37 pub fn buf(&self) -> &'input [u8] {
38 self.slice
39 }
40
41 /// Return a reference to the raw slice.
42 #[inline]
43 pub fn slice(&self) -> &'input [u8] {
44 self.slice
45 }
46
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.
50 #[inline]
51 pub fn split_at(
52 &self,
53 idx: usize,
54 ) -> (EndianSlice<'input, Endian>, EndianSlice<'input, Endian>) {
55 (self.range_to(..idx), self.range_from(idx..))
56 }
57
58 /// Find the first occurence of a byte in the slice, and return its index.
59 #[inline]
60 pub fn find(&self, byte: u8) -> Option<usize> {
61 self.slice.iter().position(|ch| *ch == byte)
62 }
63
64 /// Return the offset of the start of the slice relative to the start
65 /// of the given slice.
66 #[inline]
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());
72 ptr - base_ptr
73 }
74
75 /// Converts the slice to a string using `str::from_utf8`.
76 ///
77 /// Returns an error if the slice contains invalid characters.
78 #[inline]
79 pub fn to_string(&self) -> Result<&'input str> {
80 str::from_utf8(self.slice).map_err(|_| Error::BadUtf8)
81 }
82
83 /// Converts the slice to a string, including invalid characters,
84 /// using `String::from_utf8_lossy`.
85 #[inline]
86 pub fn to_string_lossy(&self) -> Cow<'input, str> {
87 String::from_utf8_lossy(self.slice)
88 }
89
90 #[inline]
91 fn read_slice(&mut self, len: usize) -> Result<&'input [u8]> {
92 if self.slice.len() < len {
93 Err(Error::UnexpectedEof(self.offset_id()))
94 } else {
95 let val = &self.slice[..len];
96 self.slice = &self.slice[len..];
97 Ok(val)
98 }
99 }
100 }
101
102 /// # Range Methods
103 ///
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
107 /// old methods.
108 impl<'input, Endian> EndianSlice<'input, Endian>
109 where
110 Endian: Endianity,
111 {
112 /// Take the given `start..end` range of the underlying slice and return a
113 /// new `EndianSlice`.
114 ///
115 /// ```
116 /// use gimli::{EndianSlice, LittleEndian};
117 ///
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));
122 /// ```
123 pub fn range(&self, idx: Range<usize>) -> EndianSlice<'input, Endian> {
124 EndianSlice {
125 slice: &self.slice[idx],
126 endian: self.endian,
127 }
128 }
129
130 /// Take the given `start..` range of the underlying slice and return a new
131 /// `EndianSlice`.
132 ///
133 /// ```
134 /// use gimli::{EndianSlice, LittleEndian};
135 ///
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));
140 /// ```
141 pub fn range_from(&self, idx: RangeFrom<usize>) -> EndianSlice<'input, Endian> {
142 EndianSlice {
143 slice: &self.slice[idx],
144 endian: self.endian,
145 }
146 }
147
148 /// Take the given `..end` range of the underlying slice and return a new
149 /// `EndianSlice`.
150 ///
151 /// ```
152 /// use gimli::{EndianSlice, LittleEndian};
153 ///
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));
158 /// ```
159 pub fn range_to(&self, idx: RangeTo<usize>) -> EndianSlice<'input, Endian> {
160 EndianSlice {
161 slice: &self.slice[idx],
162 endian: self.endian,
163 }
164 }
165 }
166
167 impl<'input, Endian> Index<usize> for EndianSlice<'input, Endian>
168 where
169 Endian: Endianity,
170 {
171 type Output = u8;
172 fn index(&self, idx: usize) -> &Self::Output {
173 &self.slice[idx]
174 }
175 }
176
177 impl<'input, Endian> Index<RangeFrom<usize>> for EndianSlice<'input, Endian>
178 where
179 Endian: Endianity,
180 {
181 type Output = [u8];
182 fn index(&self, idx: RangeFrom<usize>) -> &Self::Output {
183 &self.slice[idx]
184 }
185 }
186
187 impl<'input, Endian> Deref for EndianSlice<'input, Endian>
188 where
189 Endian: Endianity,
190 {
191 type Target = [u8];
192 fn deref(&self) -> &Self::Target {
193 self.slice
194 }
195 }
196
197 impl<'input, Endian> Into<&'input [u8]> for EndianSlice<'input, Endian>
198 where
199 Endian: Endianity,
200 {
201 fn into(self) -> &'input [u8] {
202 self.slice
203 }
204 }
205
206 impl<'input, Endian> Reader for EndianSlice<'input, Endian>
207 where
208 Endian: Endianity,
209 {
210 type Endian = Endian;
211 type Offset = usize;
212
213 #[inline]
214 fn endian(&self) -> Endian {
215 self.endian
216 }
217
218 #[inline]
219 fn len(&self) -> usize {
220 self.slice.len()
221 }
222
223 #[inline]
224 fn is_empty(&self) -> bool {
225 self.slice.is_empty()
226 }
227
228 #[inline]
229 fn empty(&mut self) {
230 self.slice = &[];
231 }
232
233 #[inline]
234 fn truncate(&mut self, len: usize) -> Result<()> {
235 if self.slice.len() < len {
236 Err(Error::UnexpectedEof(self.offset_id()))
237 } else {
238 self.slice = &self.slice[..len];
239 Ok(())
240 }
241 }
242
243 #[inline]
244 fn offset_from(&self, base: &Self) -> usize {
245 self.offset_from(*base)
246 }
247
248 #[inline]
249 fn offset_id(&self) -> ReaderOffsetId {
250 ReaderOffsetId(self.slice.as_ptr() as u64)
251 }
252
253 #[inline]
254 fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<Self::Offset> {
255 let id = id.0;
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)
260 } else {
261 None
262 }
263 }
264
265 #[inline]
266 fn find(&self, byte: u8) -> Result<usize> {
267 self.find(byte)
268 .ok_or_else(|| Error::UnexpectedEof(self.offset_id()))
269 }
270
271 #[inline]
272 fn skip(&mut self, len: usize) -> Result<()> {
273 if self.slice.len() < len {
274 Err(Error::UnexpectedEof(self.offset_id()))
275 } else {
276 self.slice = &self.slice[len..];
277 Ok(())
278 }
279 }
280
281 #[inline]
282 fn split(&mut self, len: usize) -> Result<Self> {
283 let slice = self.read_slice(len)?;
284 Ok(EndianSlice::new(slice, self.endian))
285 }
286
287 #[inline]
288 fn to_slice(&self) -> Result<Cow<[u8]>> {
289 Ok(self.slice.into())
290 }
291
292 #[inline]
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),
297 }
298 }
299
300 #[inline]
301 fn to_string_lossy(&self) -> Result<Cow<str>> {
302 Ok(String::from_utf8_lossy(self.slice))
303 }
304
305 #[inline]
306 fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> {
307 let slice = self.read_slice(buf.len())?;
308 buf.copy_from_slice(slice);
309 Ok(())
310 }
311 }
312
313 #[cfg(test)]
314 mod tests {
315 use super::*;
316 use crate::endianity::NativeEndian;
317
318 #[test]
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);
323 assert_eq!(
324 eb.split_at(3),
325 (
326 EndianSlice::new(&slice[..3], endian),
327 EndianSlice::new(&slice[3..], endian)
328 )
329 );
330 }
331
332 #[test]
333 #[should_panic]
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);
337 eb.split_at(30);
338 }
339 }