|
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