|
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) -> Option<U> { |
| 52 | + let n = core::mem::size_of::<U>(); |
| 53 | + // Boundary check then read array from ptr |
| 54 | + if self.len() >= n { |
| 55 | + let ptr = self.cursor as *const U; |
| 56 | + let x = unsafe { core::ptr::read_unaligned(ptr) }; |
| 57 | + Some(x) |
| 58 | + } else { |
| 59 | + None |
| 60 | + } |
39 | 61 | } |
40 | 62 |
|
41 | 63 | #[inline] |
42 | 64 | pub unsafe fn bump(&mut self) { |
43 | | - debug_assert!(self.pos < self.slice.len(), "overflow"); |
44 | | - self.pos += 1; |
| 65 | + self.advance(1) |
45 | 66 | } |
46 | 67 |
|
47 | | - #[allow(unused)] |
48 | 68 | #[inline] |
49 | 69 | pub unsafe fn advance(&mut self, n: usize) { |
50 | | - debug_assert!(self.pos + n <= self.slice.len(), "overflow"); |
51 | | - self.pos += n; |
| 70 | + self.cursor = self.cursor.add(n); |
| 71 | + debug_assert!(self.cursor <= self.end, "overflow"); |
52 | 72 | } |
53 | 73 |
|
54 | 74 | #[inline] |
55 | 75 | pub fn len(&self) -> usize { |
56 | | - self.slice.len() |
| 76 | + self.end as usize - self.cursor as usize |
57 | 77 | } |
58 | 78 |
|
59 | 79 | #[inline] |
60 | 80 | pub fn slice(&mut self) -> &'a [u8] { |
61 | 81 | // not moving position at all, so it's safe |
62 | | - unsafe { |
63 | | - self.slice_skip(0) |
64 | | - } |
| 82 | + let slice = unsafe { slice_from_ptr_range(self.start, self.cursor) }; |
| 83 | + self.commit(); |
| 84 | + slice |
65 | 85 | } |
66 | 86 |
|
| 87 | + // TODO: this is an anti-pattern, should be removed |
67 | 88 | #[inline] |
68 | 89 | 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; |
| 90 | + debug_assert!(self.cursor.sub(skip) >= self.start); |
| 91 | + let head = slice_from_ptr_range(self.start, self.cursor.sub(skip)); |
| 92 | + self.commit(); |
76 | 93 | head |
77 | 94 | } |
| 95 | + |
| 96 | + #[inline] |
| 97 | + pub fn commit(&mut self) { |
| 98 | + self.start = self.cursor |
| 99 | + } |
78 | 100 |
|
79 | 101 | #[inline] |
80 | 102 | 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; |
| 103 | + self.advance(n); |
| 104 | + self.commit(); |
| 105 | + } |
| 106 | + |
| 107 | + #[inline] |
| 108 | + pub fn as_ptr(&self) -> *const u8 { |
| 109 | + self.cursor |
| 110 | + } |
| 111 | + |
| 112 | + #[inline] |
| 113 | + pub fn start(&self) -> *const u8 { |
| 114 | + self.start |
| 115 | + } |
| 116 | + |
| 117 | + #[inline] |
| 118 | + pub fn end(&self) -> *const u8 { |
| 119 | + self.end |
| 120 | + } |
| 121 | + |
| 122 | + #[inline] |
| 123 | + pub unsafe fn set_cursor(&mut self, ptr: *const u8) { |
| 124 | + debug_assert!(ptr >= self.start); |
| 125 | + debug_assert!(ptr <= self.end); |
| 126 | + self.cursor = ptr; |
87 | 127 | } |
88 | 128 | } |
89 | 129 |
|
90 | 130 | impl<'a> AsRef<[u8]> for Bytes<'a> { |
91 | 131 | #[inline] |
92 | 132 | fn as_ref(&self) -> &[u8] { |
93 | | - &self.slice[self.pos..] |
| 133 | + unsafe { slice_from_ptr_range(self.cursor, self.end) } |
94 | 134 | } |
95 | 135 | } |
96 | 136 |
|
| 137 | +#[inline] |
| 138 | +unsafe fn slice_from_ptr_range<'a>(start: *const u8, end: *const u8) -> &'a [u8] { |
| 139 | + debug_assert!(start <= end); |
| 140 | + core::slice::from_raw_parts(start, end as usize - start as usize) |
| 141 | +} |
| 142 | + |
97 | 143 | impl<'a> Iterator for Bytes<'a> { |
98 | 144 | type Item = u8; |
99 | 145 |
|
100 | 146 | #[inline] |
101 | 147 | 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) |
| 148 | + if self.cursor < self.end { |
| 149 | + // SAFETY: bounds checked |
| 150 | + unsafe { |
| 151 | + let b = *self.cursor; |
| 152 | + self.bump(); |
| 153 | + Some(b) |
| 154 | + } |
106 | 155 | } else { |
107 | 156 | None |
108 | 157 | } |
|
0 commit comments