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