|
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