segsource/segment/
data.rs

1use super::Segment;
2use crate::{
3    error::{Error, Result},
4    marker::Integer,
5    Endidness,
6};
7use core::convert::TryFrom;
8/// An alias for a segment that deals with binary data.
9pub type DataSegment<'s> = Segment<'s, u8>;
10
11macro_rules! make_num_method {
12    ($type:ty, $name:ident, $method:ident, $($doc:literal),+) => {
13        $(#[doc = $doc])+
14        pub fn $name(&self) -> Result<$type> {
15            self.$method::<$type>()
16        }
17    };
18}
19macro_rules! make_num_method_with_offset {
20    ($type:ty, $name:ident, $method:ident, $($doc:literal),+) => {
21        $(#[doc = $doc])+
22        pub fn $name(&self, offset: usize) -> Result<$type> {
23            self.$method::<$type>(offset)
24        }
25    };
26}
27
28impl<'s> DataSegment<'s> {
29    /// Creates a new [`Segment`] using the provided endidness.
30    ///
31    /// Note: Only available if the [`Segment`]'s I is `u8`.
32    #[inline]
33    pub fn with_endidness(data: &'s [u8], endidness: Endidness) -> Self {
34        Self::new_full(data, 0, 0, endidness)
35    }
36
37    /// Creates a new [`Segment`] using the provided endidness and initial offset.
38    ///
39    /// Note: Only available if the [`Segment`]'s I is `u8`.
40    #[inline]
41    pub fn with_offset_and_endidness(
42        data: &'s [u8],
43        initial_offset: usize,
44        endidness: Endidness,
45    ) -> Self {
46        Self::new_full(data, initial_offset, 0, endidness)
47    }
48
49    #[inline]
50    /// The endidness of the [`Segment`].
51    ///
52    /// Note: Only available if the [`Segment`]'s I is `u8`.
53    pub fn endidness(&self) -> Endidness {
54        self.endidness
55    }
56
57    /// Fills the provided buffer with the next n bytes, where n is the length of the buffer. This
58    /// then advances the [`Segment::current_offset`] by n.
59    ///
60    /// Note: Only available if the [`Segment`]'s I is `u8`.
61    pub fn next_bytes(&self, buf: &mut [u8]) -> Result<()> {
62        //FIXME not async/threadsafe
63        for i in 0..buf.len() {
64            buf[i] = self.next_u8()?;
65        }
66        Ok(())
67    }
68
69    fn int_at_pos<N: Integer>(&self, pos: usize) -> Result<N> {
70        self.validate_pos(pos, N::WIDTH - 1)?;
71        Ok(N::with_endidness(
72            &self.data[pos..pos + N::WIDTH],
73            self.endidness,
74        ))
75    }
76
77    /// Gets an integer of the provided type (e.g. `u8`, `i8`, `u16`, `i16`, etcetera) at the given
78    /// offset without altering the [`Segment::current_offset`]. In most cases, you should use
79    /// methods like [`Segment::u8_at`] instead.
80    ///
81    /// Note: Only available if the [`Segment`]'s I is `u8`.
82    pub fn int_at<N: Integer>(&self, offset: usize) -> Result<N> {
83        self.validate_offset(offset, N::WIDTH - 1)?;
84        Ok(N::with_endidness(
85            &self[offset..offset + N::WIDTH],
86            self.endidness,
87        ))
88    }
89
90    #[inline]
91    /// See the documentation for [`Segment::int_at`].
92    ///
93    /// Note: Only available if the [`Segment`]'s I is `u8`.
94    pub fn u8_at(&self, offset: usize) -> Result<u8> {
95        self.item_at(offset)
96    }
97    make_num_method_with_offset! {u16, u16_at, int_at,
98    "See the documentation for [`Segment::int_at`].\n\n",
99    "Note: Only available if the [`Segment`]'s I is `u8`."}
100
101    make_num_method_with_offset! {u32, u32_at, int_at,
102    "See the documentation for [`Segment::int_at`].\n\n",
103    "Note: Only available if the [`Segment`]'s I is `u8`."}
104
105    make_num_method_with_offset! {u64, u64_at, int_at,
106    "See the documentation for [`Segment::int_at`].\n\n",
107    "Note: Only available if the [`Segment`]'s I is `u8`."}
108
109    make_num_method_with_offset! {u128, u128_at, int_at,
110    "See the documentation for [`Segment::int_at`].\n\n",
111    "Note: Only available if the [`Segment`]'s I is `u8`."}
112
113    make_num_method_with_offset! {i8, i8_at, int_at,
114    "See the documentation for [`Segment::int_at`].\n\n",
115    "Note: Only available if the [`Segment`]'s I is `u8`."}
116
117    make_num_method_with_offset! {i16, i16_at, int_at,
118    "See the documentation for [`Segment::int_at`].\n\n",
119    "Note: Only available if the [`Segment`]'s I is `u8`."}
120
121    make_num_method_with_offset! {i32, i32_at, int_at,
122    "See the documentation for [`Segment::int_at`].\n\n",
123    "Note: Only available if the [`Segment`]'s I is `u8`."}
124
125    make_num_method_with_offset! {i64, i64_at, int_at,
126    "See the documentation for [`Segment::int_at`].\n\n",
127    "Note: Only available if the [`Segment`]'s I is `u8`."}
128
129    make_num_method_with_offset! {i128, i128_at, int_at,
130    "See the documentation for [`Segment::int_at`].\n\n",
131    "Note: Only available if the [`Segment`]'s I is `u8`."}
132
133    /// Gets an integer of the provided type (e.g. `u8`, `i8`, `u16`, `i16`, etcetera) starting at
134    /// the at the [`Segment::current_offset`] without altering it. In most cases, you should use
135    /// methods like [`Segment::current_u8`] instead.
136    ///
137    /// Note: Only available if the [`Segment`]'s I is `u8`.
138    #[inline]
139    pub fn current_int<N: Integer>(&self) -> Result<N> {
140        self.int_at(self.current_offset())
141    }
142
143    make_num_method! {u8, current_u8, current_int,
144    "See the documentation for [`Segment::current_int`].\n\n",
145    "Note: Only available if the [`Segment`]'s I is `u8`."}
146
147    make_num_method! {u16, current_u16, current_int,
148    "See the documentation for [`Segment::current_int`].\n\n",
149    "Note: Only available if the [`Segment`]'s I is `u8`."}
150
151    make_num_method! {u32, current_u32, current_int,
152    "See the documentation for [`Segment::current_int`].\n\n",
153    "Note: Only available if the [`Segment`]'s I is `u8`."}
154
155    make_num_method! {u64, current_u64, current_int,
156    "See the documentation for [`Segment::current_int`].\n\n",
157    "Note: Only available if the [`Segment`]'s I is `u8`."}
158
159    make_num_method! {u128, current_u128, current_int,
160    "See the documentation for [`Segment::current_int`].\n\n",
161    "Note: Only available if the [`Segment`]'s I is `u8`."}
162
163    make_num_method! {i8, current_i8, current_int,
164    "See the documentation for [`Segment::current_int`].\n\n",
165    "Note: Only available if the [`Segment`]'s I is `u8`."}
166
167    make_num_method! {i16, current_i16, current_int,
168    "See the documentation for [`Segment::current_int`].\n\n",
169    "Note: Only available if the [`Segment`]'s I is `u8`."}
170
171    make_num_method! {i32, current_i32, current_int,
172    "See the documentation for [`Segment::current_int`].\n\n",
173    "Note: Only available if the [`Segment`]'s I is `u8`."}
174
175    make_num_method! {i64, current_i64, current_int,
176    "See the documentation for [`Segment::current_int`].\n\n",
177    "Note: Only available if the [`Segment`]'s I is `u8`."}
178
179    make_num_method! {i128, current_i128, current_int,
180    "See the documentation for [`Segment::current_int`].\n\n",
181    "Note: Only available if the [`Segment`]'s I is `u8`."}
182
183    /// Gets an integer of the provided type (e.g. `u8`, `i8`, `u16`, `i16`, etcetera) starting at
184    /// the at the [`Segment::current_offset`] but without advancing the
185    /// [`Segment::current_offset`]. In most
186    /// cases, you should use methods like [`Segment::peek_u8`] instead.
187    ///
188    /// Note: Only available if the [`Segment`]'s I is `u8`.
189    pub fn peek_int<N: Integer>(&self) -> Result<N> {
190        let pos = self.adj_pos(N::WIDTH as i128)?;
191        self.int_at(self.pos_to_offset(pos))
192    }
193
194    make_num_method! {u8, peek_u8, peek_int,
195    "See the documentation for [`Segment::peek_int`].\n\n",
196    "Note: Only available if the [`Segment`]'s I is `u8`."}
197
198    make_num_method! {u16, peek_u16, peek_int,
199    "See the documentation for [`Segment::peek_int`].\n\n",
200    "Note: Only available if the [`Segment`]'s I is `u8`."}
201
202    make_num_method! {u32, peek_u32, peek_int,
203    "See the documentation for [`Segment::peek_int`].\n\n",
204    "Note: Only available if the [`Segment`]'s I is `u8`."}
205
206    make_num_method! {u64, peek_u64, peek_int,
207    "See the documentation for [`Segment::peek_int`].\n\n",
208    "Note: Only available if the [`Segment`]'s I is `u8`."}
209
210    make_num_method! {u128, peek_u128, peek_int,
211    "See the documentation for [`Segment::peek_int`].\n\n",
212    "Note: Only available if the [`Segment`]'s I is `u8`."}
213
214    make_num_method! {i8, peek_i8, peek_int,
215    "See the documentation for [`Segment::peek_int`].\n\n",
216    "Note: Only available if the [`Segment`]'s I is `u8`."}
217
218    make_num_method! {i16, peek_i16, peek_int,
219    "See the documentation for [`Segment::peek_int`].\n\n",
220    "Note: Only available if the [`Segment`]'s I is `u8`."}
221
222    make_num_method! {i32, peek_i32, peek_int,
223    "See the documentation for [`Segment::peek_int`].\n\n",
224    "Note: Only available if the [`Segment`]'s I is `u8`."}
225
226    make_num_method! {i64, peek_i64, peek_int,
227    "See the documentation for [`Segment::peek_int`].\n\n",
228    "Note: Only available if the [`Segment`]'s I is `u8`."}
229
230    make_num_method! {i128, peek_i128, peek_int,
231    "See the documentation for [`Segment::peek_int`].\n\n",
232    "Note: Only available if the [`Segment`]'s I is `u8`."}
233
234    /// Gets an integer of the provided type (e.g. `u8`, `i8`, `u16`, `i16`, etcetera) starting at
235    /// the at the [`Segment::current_offset`] and then advances the [`Segment::current_offset`] by
236    /// n, where n is the number of bytes required to create the requested integer type. In most
237    /// cases, you should use methods like [`Segment::next_u8`] instead.
238    ///
239    /// Note: Only available if the [`Segment`]'s I is `u8`.
240    pub fn next_int<N: Integer>(&self) -> Result<N> {
241        let pos = self.adj_pos(N::WIDTH as i128)?;
242        self.int_at(self.pos_to_offset(pos))
243    }
244
245    #[inline]
246    /// See the documentation for [`Segment::next_int`].
247    ///
248    /// Note: Only available if the [`Segment`]'s I is `u8`.
249    pub fn next_u8(&self) -> Result<u8> {
250        self.next_item()
251    }
252
253    make_num_method! {u16, next_u16, next_int,
254    "See the documentation for [`Segment::next_int`].\n\n",
255    "Note: Only available if the [`Segment`]'s I is `u8`."}
256
257    make_num_method! {u32, next_u32, next_int,
258    "See the documentation for [`Segment::next_int`].\n\n",
259    "Note: Only available if the [`Segment`]'s I is `u8`."}
260
261    make_num_method! {u64, next_u64, next_int,
262    "See the documentation for [`Segment::next_int`].\n\n",
263    "Note: Only available if the [`Segment`]'s I is `u8`."}
264
265    make_num_method! {u128, next_u128, next_int,
266    "See the documentation for [`Segment::next_int`].\n\n",
267    "Note: Only available if the [`Segment`]'s I is `u8`."}
268
269    make_num_method! {i8, next_i8, next_int,
270    "See the documentation for [`Segment::next_int`].\n\n",
271    "Note: Only available if the [`Segment`]'s I is `u8`."}
272
273    make_num_method! {i16, next_i16, next_int,
274    "See the documentation for [`Segment::next_int`].\n\n",
275    "Note: Only available if the [`Segment`]'s I is `u8`."}
276
277    make_num_method! {i32, next_i32, next_int,
278    "See the documentation for [`Segment::next_int`].\n\n",
279    "Note: Only available if the [`Segment`]'s I is `u8`."}
280
281    make_num_method! {i64, next_i64, next_int,
282    "See the documentation for [`Segment::next_int`].\n\n",
283    "Note: Only available if the [`Segment`]'s I is `u8`."}
284
285    make_num_method! {i128, next_i128, next_int,
286    "See the documentation for [`Segment::next_int`].\n\n",
287    "Note: Only available if the [`Segment`]'s I is `u8`."}
288}
289impl<'s> TryFrom<&DataSegment<'s>> for () {
290    type Error = Error;
291    fn try_from(_: &Segment<'s, u8>) -> Result<Self> {
292        Ok(())
293    }
294}
295impl<'s> TryFrom<&Segment<'s, u8>> for u8 {
296    type Error = Error;
297    fn try_from(segment: &Segment<'s, u8>) -> Result<Self> {
298        segment.next_item()
299    }
300}
301
302macro_rules! impl_try_from {
303    ($type:ty) => {
304        impl<'s> TryFrom<&Segment<'s, u8>> for $type {
305            type Error = Error;
306            fn try_from(segment: &Segment<'s, u8>) -> Result<Self> {
307                segment.next_int()
308            }
309        }
310        impl<'s, const N: usize> TryFrom<&Segment<'s, u8>> for [$type; N] {
311            type Error = Error;
312            fn try_from(segment: &Segment<'s, u8>) -> Result<Self> {
313                let pos = segment.adj_pos((<$type>::WIDTH * N) as i128)?;
314                let mut array = [0; N];
315                for i in 0..N {
316                    array[i] = segment.int_at_pos(pos + (i * <$type>::WIDTH))?
317                }
318                Ok(array)
319            }
320        }
321    };
322}
323
324impl_try_from! { u16 }
325impl_try_from! { u32 }
326impl_try_from! { u64 }
327impl_try_from! { u128 }
328
329impl_try_from! { i8 }
330impl_try_from! { i16 }
331impl_try_from! { i32 }
332impl_try_from! { i64 }
333impl_try_from! { i128 }