|
1 | | -use core::slice; |
2 | | -use core::convert::TryInto; |
3 | | -use core::convert::TryFrom; |
4 | | - |
5 | 1 | #[allow(missing_docs)] |
6 | 2 | pub struct Bytes<'a> { |
7 | | - slice: &'a [u8], |
8 | | - pos: usize |
| 3 | + start: *const u8, |
| 4 | + end: *const u8, |
| 5 | + cursor: *const u8, |
| 6 | + phantom: core::marker::PhantomData<&'a ()>, |
9 | 7 | } |
10 | 8 |
|
11 | 9 | #[allow(missing_docs)] |
12 | 10 | impl<'a> Bytes<'a> { |
13 | 11 | #[inline] |
14 | 12 | pub fn new(slice: &'a [u8]) -> Bytes<'a> { |
| 13 | + let start = slice.as_ptr(); |
| 14 | + let end = unsafe { start.add(slice.len()) }; |
| 15 | + let cursor = start; |
15 | 16 | Bytes { |
16 | | - slice, |
17 | | - pos: 0 |
| 17 | + start, |
| 18 | + end, |
| 19 | + cursor, |
| 20 | + phantom: core::marker::PhantomData, |
18 | 21 | } |
19 | 22 | } |
20 | 23 |
|
21 | 24 | #[inline] |
22 | 25 | pub fn pos(&self) -> usize { |
23 | | - self.pos |
| 26 | + self.cursor as usize - self.start as usize |
24 | 27 | } |
25 | 28 |
|
26 | 29 | #[inline] |
27 | 30 | pub fn peek(&self) -> Option<u8> { |
28 | | - self.peek_ahead(0) |
| 31 | + if self.cursor < self.end { |
| 32 | + // SAFETY: bounds checked |
| 33 | + Some(unsafe { *self.cursor }) |
| 34 | + } else { |
| 35 | + None |
| 36 | + } |
29 | 37 | } |
30 | 38 |
|
31 | 39 | #[inline] |
32 | 40 | pub fn peek_ahead(&self, n: usize) -> Option<u8> { |
33 | | - self.slice.get(self.pos + n).copied() |
| 41 | + let ptr = unsafe { self.cursor.add(n) }; |
| 42 | + if ptr < self.end { |
| 43 | + // SAFETY: bounds checked |
| 44 | + Some(unsafe { *ptr }) |
| 45 | + } else { |
| 46 | + None |
| 47 | + } |
34 | 48 | } |
35 | | - |
| 49 | + |
36 | 50 | #[inline] |
37 | | - pub fn peek_n<U: TryFrom<&'a[u8]>>(&self, n: usize) -> Option<U> { |
38 | | - self.slice.get(self.pos..self.pos + n)?.try_into().ok() |
| 51 | + pub fn peek_n<U>(&self, n: usize) -> Option<U> { |
| 52 | + // TODO: drop `n` arg in favour of const |
| 53 | + // let n = core::mem::size_of::<U>(); |
| 54 | + // Boundary check then read array from ptr |
| 55 | + if self.len() >= n { |
| 56 | + let ptr = self.cursor as *const U; |
| 57 | + let x = unsafe { core::ptr::read_unaligned(ptr) }; |
| 58 | + Some(x) |
| 59 | + } else { |
| 60 | + None |
| 61 | + } |
39 | 62 | } |
40 | 63 |
|
41 | 64 | #[inline] |
42 | 65 | pub unsafe fn bump(&mut self) { |
43 | | - debug_assert!(self.pos < self.slice.len(), "overflow"); |
44 | | - self.pos += 1; |
| 66 | + self.advance(1) |
45 | 67 | } |
46 | 68 |
|
47 | | - #[allow(unused)] |
48 | 69 | #[inline] |
49 | 70 | pub unsafe fn advance(&mut self, n: usize) { |
50 | | - debug_assert!(self.pos + n <= self.slice.len(), "overflow"); |
51 | | - self.pos += n; |
| 71 | + self.cursor = self.cursor.add(n); |
| 72 | + debug_assert!(self.cursor <= self.end, "overflow"); |
52 | 73 | } |
53 | 74 |
|
54 | 75 | #[inline] |
55 | 76 | pub fn len(&self) -> usize { |
56 | | - self.slice.len() |
| 77 | + self.end as usize - self.cursor as usize |
57 | 78 | } |
58 | 79 |
|
59 | 80 | #[inline] |
60 | 81 | pub fn slice(&mut self) -> &'a [u8] { |
61 | 82 | // not moving position at all, so it's safe |
62 | | - unsafe { |
63 | | - self.slice_skip(0) |
64 | | - } |
| 83 | + let slice = unsafe { slice_from_ptr_range(self.start, self.cursor) }; |
| 84 | + self.commit(); |
| 85 | + slice |
65 | 86 | } |
66 | 87 |
|
| 88 | + // TODO: this is an anti-pattern, should be removed |
67 | 89 | #[inline] |
68 | 90 | pub unsafe fn slice_skip(&mut self, skip: usize) -> &'a [u8] { |
69 | | - debug_assert!(self.pos >= skip); |
70 | | - let head_pos = self.pos - skip; |
71 | | - let ptr = self.slice.as_ptr(); |
72 | | - let head = slice::from_raw_parts(ptr, head_pos); |
73 | | - let tail = slice::from_raw_parts(ptr.add(self.pos), self.slice.len() - self.pos); |
74 | | - self.pos = 0; |
75 | | - self.slice = tail; |
| 91 | + debug_assert!(self.cursor.sub(skip) >= self.start); |
| 92 | + let head = slice_from_ptr_range(self.start, self.cursor.sub(skip)); |
| 93 | + self.commit(); |
76 | 94 | head |
77 | 95 | } |
| 96 | + |
| 97 | + #[inline] |
| 98 | + pub fn commit(&mut self) { |
| 99 | + self.start = self.cursor |
| 100 | + } |
78 | 101 |
|
79 | 102 | #[inline] |
80 | 103 | pub unsafe fn advance_and_commit(&mut self, n: usize) { |
81 | | - debug_assert!(self.pos + n <= self.slice.len(), "overflow"); |
82 | | - self.pos += n; |
83 | | - let ptr = self.slice.as_ptr(); |
84 | | - let tail = slice::from_raw_parts(ptr.add(n), self.slice.len() - n); |
85 | | - self.pos = 0; |
86 | | - self.slice = tail; |
| 104 | + self.advance(n); |
| 105 | + self.commit(); |
| 106 | + } |
| 107 | + |
| 108 | + #[inline] |
| 109 | + pub fn as_ptr(&self) -> *const u8 { |
| 110 | + self.cursor |
| 111 | + } |
| 112 | + |
| 113 | + #[inline] |
| 114 | + pub fn start(&self) -> *const u8 { |
| 115 | + self.start |
| 116 | + } |
| 117 | + |
| 118 | + #[inline] |
| 119 | + pub fn end(&self) -> *const u8 { |
| 120 | + self.end |
| 121 | + } |
| 122 | + |
| 123 | + #[inline] |
| 124 | + pub unsafe fn set_cursor(&mut self, ptr: *const u8) { |
| 125 | + debug_assert!(ptr >= self.start); |
| 126 | + debug_assert!(ptr <= self.end); |
| 127 | + self.cursor = ptr; |
87 | 128 | } |
88 | 129 | } |
89 | 130 |
|
90 | 131 | impl<'a> AsRef<[u8]> for Bytes<'a> { |
91 | 132 | #[inline] |
92 | | - fn as_ref(&self) -> &[u8] { |
93 | | - &self.slice[self.pos..] |
| 133 | + fn as_ref(&self) -> &'a [u8] { |
| 134 | + unsafe { slice_from_ptr_range(self.cursor, self.end) } |
94 | 135 | } |
95 | 136 | } |
96 | 137 |
|
| 138 | +#[inline] |
| 139 | +unsafe fn slice_from_ptr_range<'a>(start: *const u8, end: *const u8) -> &'a [u8] { |
| 140 | + debug_assert!(start <= end); |
| 141 | + core::slice::from_raw_parts(start, end as usize - start as usize) |
| 142 | +} |
| 143 | + |
97 | 144 | impl<'a> Iterator for Bytes<'a> { |
98 | 145 | type Item = u8; |
99 | 146 |
|
100 | 147 | #[inline] |
101 | 148 | fn next(&mut self) -> Option<u8> { |
102 | | - if self.slice.len() > self.pos { |
103 | | - let b = unsafe { *self.slice.get_unchecked(self.pos) }; |
104 | | - self.pos += 1; |
105 | | - Some(b) |
| 149 | + if self.cursor < self.end { |
| 150 | + // SAFETY: bounds checked |
| 151 | + unsafe { |
| 152 | + let b = *self.cursor; |
| 153 | + self.bump(); |
| 154 | + Some(b) |
| 155 | + } |
106 | 156 | } else { |
107 | 157 | None |
108 | 158 | } |
|
0 commit comments