lazy_bytes_cast/
read.rs

1use crate::Pod;
2
3use core::{mem, marker};
4
5//To avoid unaligned read, wait until `ptr::read_unaligned` is stable to remove it
6#[repr(packed(1))]
7pub(crate) struct Out<T>(pub T);
8
9#[derive(Copy, Clone)]
10///Byte slice reader.
11///
12///## Usage
13///
14///```
15///use lazy_bytes_cast::Read;
16///
17///const DATA: &[u8] = &[0u8, 255, 255, 255, 1];
18///const OUT: u32 = match Read::<u32>::new(DATA).read() {
19///   Some(out) => out,
20///   None => unreachable!()
21///};
22///const OUT2: u32 = match Read::<u32>::new(DATA).advance(4).read() {
23///   Some(_) => unreachable!(),
24///   None => 0,
25///};
26///
27///assert_eq!(OUT, u32::from_ne_bytes([0u8, 255, 255, 255]));
28///assert_eq!(OUT2, 0);
29///```
30pub struct Read<'a, OUT> {
31    bytes: &'a [u8],
32    cursor: usize,
33    _out: marker::PhantomData<OUT>
34}
35
36impl<'a, OUT: Pod> Read<'a, OUT> {
37    ///Creates new instance
38    pub const fn new(bytes: &'a [u8]) -> Self {
39        Self {
40            bytes,
41            cursor: 0,
42            _out: marker::PhantomData,
43        }
44    }
45
46    const fn internal_read_unchecked(&self) -> &Out<OUT> {
47        unsafe {
48            let ptr = self.bytes.as_ptr().add(self.cursor) as *const _;
49            &*ptr
50        }
51    }
52
53    #[inline(always)]
54    ///Read from current position without bounds checks
55    pub const unsafe fn read_unchecked(&self) -> OUT {
56        self.internal_read_unchecked().0
57    }
58
59    #[inline(always)]
60    ///Read from current position without bounds checks
61    pub const fn read(&self) -> Option<OUT> {
62        if self.bytes.len().saturating_sub(self.cursor) >= mem::size_of::<OUT>() {
63            unsafe {
64                Some(self.read_unchecked())
65            }
66        } else {
67            None
68        }
69    }
70
71    #[inline(always)]
72    ///Moves cursor position forward.
73    pub const fn advance(mut self, add: usize) -> Self {
74        self.cursor = self.cursor.saturating_add(add);
75        self
76    }
77
78    #[inline(always)]
79    ///Returns number of elements available for `read`
80    pub const fn remaining(&self) -> usize {
81        let remain = self.bytes.len().saturating_sub(self.cursor);
82        remain / mem::size_of::<OUT>()
83    }
84}
85
86impl<'a, OUT: Pod> Iterator for Read<'a, OUT> {
87    type Item = OUT;
88
89    #[inline(always)]
90    fn next(&mut self) -> Option<Self::Item> {
91        match self.read() {
92            Some(res) => {
93                *self = self.advance(mem::size_of::<OUT>());
94                Some(res)
95            },
96            None => None
97        }
98    }
99
100    #[inline(always)]
101    fn size_hint(&self) -> (usize, Option<usize>) {
102        let len = self.remaining();
103        (len, Some(len))
104    }
105}