@@ -18,116 +18,185 @@ impl<'a> AsciiStr<'a> {
18
18
}
19
19
}
20
20
21
+ pub fn len ( & self ) -> usize {
22
+ self . end as usize - self . ptr as usize
23
+ }
24
+
25
+ /// # Safety
26
+ ///
27
+ /// Safe if `n <= self.len()`
21
28
#[ inline]
22
- pub fn step_by ( & mut self , n : usize ) -> & mut Self {
29
+ pub unsafe fn step_by ( & mut self , n : usize ) -> & mut Self {
30
+ debug_assert ! ( n <= self . len( ) , "buffer overflow: stepping by greater than our buffer length." ) ;
31
+ // SAFETY: Safe if `n <= self.len()`
23
32
unsafe { self . ptr = self . ptr . add ( n) } ;
24
33
self
25
34
}
26
35
36
+ /// # Safety
37
+ ///
38
+ /// Safe if `!self.is_empty()`
39
+ #[ inline]
40
+ pub unsafe fn step ( & mut self ) -> & mut Self {
41
+ debug_assert ! ( !self . is_empty( ) , "buffer overflow: buffer is empty." ) ;
42
+ // SAFETY: Safe if the buffer is not empty, that is, `self.len() >= 1`
43
+ unsafe { self . step_by ( 1 ) }
44
+ }
45
+
27
46
#[ inline]
28
- pub fn step ( & mut self ) -> & mut Self {
29
- self . step_by ( 1 )
47
+ pub fn step_if ( & mut self , c : u8 ) -> bool {
48
+ let stepped = self . first_is ( c) ;
49
+ if stepped {
50
+ // SAFETY: safe since we have at least 1 character in the buffer
51
+ unsafe { self . step ( ) } ;
52
+ }
53
+ stepped
54
+ }
55
+
56
+ // TODO: Remove this...
57
+ /// # Safety
58
+ ///
59
+ /// Safe if `!self.is_empty()`
60
+ // TODO: Unsafe, remove this
61
+ #[ inline]
62
+ pub fn step_unsafe ( & mut self ) -> & mut Self {
63
+ unsafe { self . step ( ) }
30
64
}
31
65
32
66
#[ inline]
33
67
pub fn is_empty ( & self ) -> bool {
34
68
self . ptr == self . end
35
69
}
36
70
71
+ /// # Safety
72
+ ///
73
+ /// Safe if `!self.is_empty()`
37
74
#[ inline]
38
- pub fn first ( & self ) -> u8 {
75
+ pub unsafe fn first_unchecked ( & self ) -> u8 {
76
+ debug_assert ! ( !self . is_empty( ) , "attempting to get first value of empty buffer." ) ;
39
77
unsafe { * self . ptr }
40
78
}
41
79
42
80
#[ inline]
43
- pub fn first_is ( & self , c : u8 ) -> bool {
44
- self . first ( ) == c
81
+ pub fn first ( & self ) -> Option < u8 > {
82
+ if !self . is_empty ( ) {
83
+ // SAFETY: safe since `!self.is_empty()`
84
+ Some ( unsafe { self . first_unchecked ( ) } )
85
+ } else {
86
+ None
87
+ }
45
88
}
46
89
47
90
#[ inline]
48
- pub fn first_either ( & self , c1 : u8 , c2 : u8 ) -> bool {
49
- let c = self . first ( ) ;
50
- c == c1 || c == c2
91
+ pub fn first_is ( & self , c : u8 ) -> bool {
92
+ self . first ( ) == Some ( c)
51
93
}
52
94
53
95
#[ inline]
54
- pub fn check_first ( & self , c : u8 ) -> bool {
55
- !self . is_empty ( ) && self . first ( ) == c
96
+ pub fn first_is2 ( & self , c1 : u8 , c2 : u8 ) -> bool {
97
+ if let Some ( c) = self . first ( ) {
98
+ c == c1 || c == c2
99
+ } else {
100
+ false
101
+ }
56
102
}
57
103
58
104
#[ inline]
59
- pub fn check_first_either ( & self , c1 : u8 , c2 : u8 ) -> bool {
60
- !self . is_empty ( ) && ( self . first ( ) == c1 || self . first ( ) == c2)
105
+ pub fn first_is_digit ( & self ) -> bool {
106
+ if let Some ( c) = self . first ( ) {
107
+ c. is_ascii_digit ( )
108
+ } else {
109
+ false
110
+ }
61
111
}
62
112
63
113
#[ inline]
64
- pub fn check_first_digit ( & self ) -> bool {
65
- !self . is_empty ( ) && self . first ( ) . is_ascii_digit ( )
114
+ pub fn first_digit ( & self ) -> Option < u8 > {
115
+ self . first ( ) . and_then ( |x| if x. is_ascii_digit ( ) {
116
+ Some ( x - b'0' )
117
+ } else {
118
+ None
119
+ } )
66
120
}
67
121
68
122
#[ inline]
69
- pub fn parse_digits ( & mut self , mut func : impl FnMut ( u8 ) ) {
70
- while !self . is_empty ( ) && self . first ( ) . is_ascii_digit ( ) {
71
- func ( self . first ( ) - b'0' ) ;
72
- self . step ( ) ;
123
+ pub fn try_read_digit ( & mut self ) -> Option < u8 > {
124
+ if let Some ( digit) = self . first_digit ( ) {
125
+ // SAFETY: Safe since `first_digit` means the buffer is not empty
126
+ unsafe { self . step ( ) } ;
127
+ Some ( digit)
128
+ } else {
129
+ None
73
130
}
74
131
}
75
132
76
133
#[ inline]
77
- pub fn check_len ( & self , n : usize ) -> bool {
78
- let len = self . end as usize - self . ptr as usize ;
79
- n <= len
134
+ pub fn parse_digits ( & mut self , mut func : impl FnMut ( u8 ) ) {
135
+ while let Some ( digit) = self . try_read_digit ( ) {
136
+ func ( digit) ;
137
+ }
80
138
}
81
139
82
140
#[ inline]
83
141
pub fn try_read_u64 ( & self ) -> Option < u64 > {
84
- if self . check_len ( 8 ) {
85
- Some ( self . read_u64 ( ) )
142
+ if self . len ( ) >= 8 {
143
+ Some ( unsafe { self . read_u64_unchecked ( ) } )
86
144
} else {
87
145
None
88
146
}
89
147
}
90
148
149
+ /// # Safety
150
+ ///
151
+ /// Safe if `self.len() >= 8`
91
152
#[ inline]
92
- pub fn read_u64 ( & self ) -> u64 {
93
- debug_assert ! ( self . check_len ( 8 ) ) ;
153
+ pub unsafe fn read_u64_unchecked ( & self ) -> u64 {
154
+ debug_assert ! ( self . len ( ) >= 8 , "overflowing buffer: buffer is not 8 bytes long" ) ;
94
155
let src = self . ptr as * const u64 ;
156
+ // SAFETY: Safe if `self.len() >= 8`
95
157
u64:: from_le ( unsafe { ptr:: read_unaligned ( src) } )
96
158
}
97
159
98
160
#[ inline]
99
161
pub fn offset_from ( & self , other : & Self ) -> isize {
100
- isize:: wrapping_sub ( self . ptr as _ , other. ptr as _ ) // assuming the same end
162
+ isize:: wrapping_sub ( self . ptr as isize , other. ptr as isize ) // assuming the same end
101
163
}
102
164
}
103
165
104
166
// Most of these are inherently unsafe; we assume we know what we're calling and when.
105
167
pub trait ByteSlice : AsRef < [ u8 ] > + AsMut < [ u8 ] > {
168
+ /// # Safety
169
+ ///
170
+ /// Safe if `!self.is_empty()`.
106
171
#[ inline]
107
- fn get_at ( & self , i : usize ) -> u8 {
108
- unsafe { * self . as_ref ( ) . get_unchecked ( i) }
109
- }
110
-
111
- #[ inline]
112
- fn get_first ( & self ) -> u8 {
113
- debug_assert ! ( !self . as_ref( ) . is_empty( ) ) ;
114
- self . get_at ( 0 )
172
+ unsafe fn get_first_unchecked ( & self ) -> u8 {
173
+ let s = self . as_ref ( ) ;
174
+ debug_assert ! ( !s. is_empty( ) ) ;
175
+ // SAFETY: safe if `s.is_empty()`
176
+ unsafe { * s. get_unchecked ( 0 ) }
115
177
}
116
178
117
179
#[ inline]
118
180
fn check_first ( & self , c : u8 ) -> bool {
119
- ! self . as_ref ( ) . is_empty ( ) && self . get_first ( ) == c
181
+ self . as_ref ( ) . first ( ) == Some ( & c )
120
182
}
121
183
122
184
#[ inline]
123
185
fn check_first2 ( & self , c1 : u8 , c2 : u8 ) -> bool {
124
- !self . as_ref ( ) . is_empty ( ) && ( self . get_first ( ) == c1 || self . get_first ( ) == c2)
186
+ if let Some ( & c) = self . as_ref ( ) . first ( ) {
187
+ c == c1 || c == c2
188
+ } else {
189
+ false
190
+ }
125
191
}
126
192
127
193
#[ inline]
128
194
fn eq_ignore_case ( & self , u : & [ u8 ] ) -> bool {
129
- debug_assert ! ( self . as_ref( ) . len( ) >= u. len( ) ) ;
130
- let d = ( 0 ..u. len ( ) ) . fold ( 0 , |d, i| d | self . get_at ( i) ^ u. get_at ( i) ) ;
195
+ let s = self . as_ref ( ) ;
196
+ if s. len ( ) < u. len ( ) {
197
+ return false ;
198
+ }
199
+ let d = ( 0 ..u. len ( ) ) . fold ( 0 , |d, i| d | s[ i] ^ u[ i] ) ;
131
200
d == 0 || d == 32
132
201
}
133
202
@@ -145,26 +214,25 @@ pub trait ByteSlice: AsRef<[u8]> + AsMut<[u8]> {
145
214
s
146
215
}
147
216
217
+ /// # Safety
218
+ ///
219
+ /// Safe if `self.len() >= 8`.
148
220
#[ inline]
149
- fn skip_chars2 ( & self , c1 : u8 , c2 : u8 ) -> & [ u8 ] {
150
- let mut s = self . as_ref ( ) ;
151
- while !s. is_empty ( ) && ( s. get_first ( ) == c1 || s. get_first ( ) == c2) {
152
- s = s. advance ( 1 ) ;
153
- }
154
- s
155
- }
156
-
157
- #[ inline]
158
- fn read_u64 ( & self ) -> u64 {
221
+ unsafe fn read_u64 ( & self ) -> u64 {
159
222
debug_assert ! ( self . as_ref( ) . len( ) >= 8 ) ;
160
223
let src = self . as_ref ( ) . as_ptr ( ) as * const u64 ;
224
+ // SAFETY: safe if `self.len() >= 8`.
161
225
u64:: from_le ( unsafe { ptr:: read_unaligned ( src) } )
162
226
}
163
227
228
+ /// # Safety
229
+ ///
230
+ /// Safe if `self.len() >= 8`.
164
231
#[ inline]
165
- fn write_u64 ( & mut self , value : u64 ) {
232
+ unsafe fn write_u64 ( & mut self , value : u64 ) {
166
233
debug_assert ! ( self . as_ref( ) . len( ) >= 8 ) ;
167
234
let dst = self . as_mut ( ) . as_mut_ptr ( ) as * mut u64 ;
235
+ // SAFETY: safe if `self.len() >= 8`.
168
236
unsafe { ptr:: write_unaligned ( dst, u64:: to_le ( value) ) } ;
169
237
}
170
238
}
@@ -180,8 +248,8 @@ pub fn is_8digits(v: u64) -> bool {
180
248
181
249
#[ inline]
182
250
pub fn parse_digits ( s : & mut & [ u8 ] , mut f : impl FnMut ( u8 ) ) {
183
- while !s . is_empty ( ) {
184
- let c = s . get_first ( ) . wrapping_sub ( b'0' ) ;
251
+ while let Some ( & ch ) = s . first ( ) {
252
+ let c = ch . wrapping_sub ( b'0' ) ;
185
253
if c < 10 {
186
254
f ( c) ;
187
255
* s = s. advance ( 1 ) ;
@@ -215,14 +283,14 @@ mod tests {
215
283
fn test_read_write_u64 ( ) {
216
284
let bytes = b"01234567" ;
217
285
let string = AsciiStr :: new ( bytes) ;
218
- let int = string. read_u64 ( ) ;
219
- assert_eq ! ( int, 0x3736353433323130 ) ;
286
+ let int = string. try_read_u64 ( ) ;
287
+ assert_eq ! ( int, Some ( 0x3736353433323130 ) ) ;
220
288
221
- let int = bytes. read_u64 ( ) ;
289
+ let int = unsafe { bytes. read_u64 ( ) } ;
222
290
assert_eq ! ( int, 0x3736353433323130 ) ;
223
291
224
292
let mut slc = [ 0u8 ; 8 ] ;
225
- slc. write_u64 ( 0x3736353433323130 ) ;
293
+ unsafe { slc. write_u64 ( 0x3736353433323130 ) } ;
226
294
assert_eq ! ( & slc, bytes) ;
227
295
}
228
296
}
0 commit comments