@@ -18,116 +18,164 @@ 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
30
54
}
31
55
32
56
#[ inline]
33
57
pub fn is_empty ( & self ) -> bool {
34
58
self . ptr == self . end
35
59
}
36
60
61
+ /// # Safety
62
+ ///
63
+ /// Safe if `!self.is_empty()`
37
64
#[ inline]
38
- pub fn first ( & self ) -> u8 {
65
+ pub unsafe fn first_unchecked ( & self ) -> u8 {
66
+ debug_assert ! ( !self . is_empty( ) , "attempting to get first value of empty buffer." ) ;
39
67
unsafe { * self . ptr }
40
68
}
41
69
42
70
#[ inline]
43
- pub fn first_is ( & self , c : u8 ) -> bool {
44
- self . first ( ) == c
71
+ pub fn first ( & self ) -> Option < u8 > {
72
+ if !self . is_empty ( ) {
73
+ // SAFETY: safe since `!self.is_empty()`
74
+ Some ( unsafe { self . first_unchecked ( ) } )
75
+ } else {
76
+ None
77
+ }
45
78
}
46
79
47
80
#[ inline]
48
- pub fn first_either ( & self , c1 : u8 , c2 : u8 ) -> bool {
49
- let c = self . first ( ) ;
50
- c == c1 || c == c2
81
+ pub fn first_is ( & self , c : u8 ) -> bool {
82
+ self . first ( ) == Some ( c)
51
83
}
52
84
53
85
#[ inline]
54
- pub fn check_first ( & self , c : u8 ) -> bool {
55
- !self . is_empty ( ) && self . first ( ) == c
86
+ pub fn first_is2 ( & self , c1 : u8 , c2 : u8 ) -> bool {
87
+ if let Some ( c) = self . first ( ) {
88
+ c == c1 || c == c2
89
+ } else {
90
+ false
91
+ }
56
92
}
57
93
58
94
#[ inline]
59
- pub fn check_first_either ( & self , c1 : u8 , c2 : u8 ) -> bool {
60
- !self . is_empty ( ) && ( self . first ( ) == c1 || self . first ( ) == c2)
95
+ pub fn first_is_digit ( & self ) -> bool {
96
+ if let Some ( c) = self . first ( ) {
97
+ c. is_ascii_digit ( )
98
+ } else {
99
+ false
100
+ }
61
101
}
62
102
63
103
#[ inline]
64
- pub fn check_first_digit ( & self ) -> bool {
65
- !self . is_empty ( ) && self . first ( ) . is_ascii_digit ( )
104
+ pub fn first_digit ( & self ) -> Option < u8 > {
105
+ self . first ( ) . and_then ( |x| if x. is_ascii_digit ( ) {
106
+ Some ( x - b'0' )
107
+ } else {
108
+ None
109
+ } )
66
110
}
67
111
68
112
#[ 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 ( ) ;
113
+ pub fn try_read_digit ( & mut self ) -> Option < u8 > {
114
+ if let Some ( digit) = self . first_digit ( ) {
115
+ // SAFETY: Safe since `first_digit` means the buffer is not empty
116
+ unsafe { self . step ( ) } ;
117
+ Some ( digit)
118
+ } else {
119
+ None
73
120
}
74
121
}
75
122
76
123
#[ inline]
77
- pub fn check_len ( & self , n : usize ) -> bool {
78
- let len = self . end as usize - self . ptr as usize ;
79
- n <= len
124
+ pub fn parse_digits ( & mut self , mut func : impl FnMut ( u8 ) ) {
125
+ while let Some ( digit) = self . try_read_digit ( ) {
126
+ func ( digit) ;
127
+ }
80
128
}
81
129
82
130
#[ inline]
83
131
pub fn try_read_u64 ( & self ) -> Option < u64 > {
84
- if self . check_len ( 8 ) {
85
- Some ( self . read_u64 ( ) )
132
+ if self . len ( ) >= 8 {
133
+ Some ( unsafe { self . read_u64_unchecked ( ) } )
86
134
} else {
87
135
None
88
136
}
89
137
}
90
138
139
+ /// # Safety
140
+ ///
141
+ /// Safe if `self.len() >= 8`
91
142
#[ inline]
92
- pub fn read_u64 ( & self ) -> u64 {
93
- debug_assert ! ( self . check_len ( 8 ) ) ;
143
+ pub unsafe fn read_u64_unchecked ( & self ) -> u64 {
144
+ debug_assert ! ( self . len ( ) >= 8 , "overflowing buffer: buffer is not 8 bytes long" ) ;
94
145
let src = self . ptr as * const u64 ;
146
+ // SAFETY: Safe if `self.len() >= 8`
95
147
u64:: from_le ( unsafe { ptr:: read_unaligned ( src) } )
96
148
}
97
149
98
150
#[ inline]
99
151
pub fn offset_from ( & self , other : & Self ) -> isize {
100
- isize:: wrapping_sub ( self . ptr as _ , other. ptr as _ ) // assuming the same end
152
+ isize:: wrapping_sub ( self . ptr as isize , other. ptr as isize ) // assuming the same end
101
153
}
102
154
}
103
155
104
156
// Most of these are inherently unsafe; we assume we know what we're calling and when.
105
157
pub trait ByteSlice : AsRef < [ u8 ] > + AsMut < [ u8 ] > {
106
- #[ 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 )
115
- }
116
-
117
158
#[ inline]
118
159
fn check_first ( & self , c : u8 ) -> bool {
119
- ! self . as_ref ( ) . is_empty ( ) && self . get_first ( ) == c
160
+ self . as_ref ( ) . first ( ) == Some ( & c )
120
161
}
121
162
122
163
#[ inline]
123
164
fn check_first2 ( & self , c1 : u8 , c2 : u8 ) -> bool {
124
- !self . as_ref ( ) . is_empty ( ) && ( self . get_first ( ) == c1 || self . get_first ( ) == c2)
165
+ if let Some ( & c) = self . as_ref ( ) . first ( ) {
166
+ c == c1 || c == c2
167
+ } else {
168
+ false
169
+ }
125
170
}
126
171
127
172
#[ inline]
128
173
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) ) ;
174
+ let s = self . as_ref ( ) ;
175
+ if s. len ( ) < u. len ( ) {
176
+ return false ;
177
+ }
178
+ let d = ( 0 ..u. len ( ) ) . fold ( 0 , |d, i| d | s[ i] ^ u[ i] ) ;
131
179
d == 0 || d == 32
132
180
}
133
181
@@ -145,26 +193,25 @@ pub trait ByteSlice: AsRef<[u8]> + AsMut<[u8]> {
145
193
s
146
194
}
147
195
196
+ /// # Safety
197
+ ///
198
+ /// Safe if `self.len() >= 8`.
148
199
#[ 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 {
200
+ unsafe fn read_u64 ( & self ) -> u64 {
159
201
debug_assert ! ( self . as_ref( ) . len( ) >= 8 ) ;
160
202
let src = self . as_ref ( ) . as_ptr ( ) as * const u64 ;
203
+ // SAFETY: safe if `self.len() >= 8`.
161
204
u64:: from_le ( unsafe { ptr:: read_unaligned ( src) } )
162
205
}
163
206
207
+ /// # Safety
208
+ ///
209
+ /// Safe if `self.len() >= 8`.
164
210
#[ inline]
165
- fn write_u64 ( & mut self , value : u64 ) {
211
+ unsafe fn write_u64 ( & mut self , value : u64 ) {
166
212
debug_assert ! ( self . as_ref( ) . len( ) >= 8 ) ;
167
213
let dst = self . as_mut ( ) . as_mut_ptr ( ) as * mut u64 ;
214
+ // SAFETY: safe if `self.len() >= 8`.
168
215
unsafe { ptr:: write_unaligned ( dst, u64:: to_le ( value) ) } ;
169
216
}
170
217
}
@@ -180,8 +227,8 @@ pub fn is_8digits(v: u64) -> bool {
180
227
181
228
#[ inline]
182
229
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' ) ;
230
+ while let Some ( & ch ) = s . first ( ) {
231
+ let c = ch . wrapping_sub ( b'0' ) ;
185
232
if c < 10 {
186
233
f ( c) ;
187
234
* s = s. advance ( 1 ) ;
@@ -215,14 +262,14 @@ mod tests {
215
262
fn test_read_write_u64 ( ) {
216
263
let bytes = b"01234567" ;
217
264
let string = AsciiStr :: new ( bytes) ;
218
- let int = string. read_u64 ( ) ;
219
- assert_eq ! ( int, 0x3736353433323130 ) ;
265
+ let int = string. try_read_u64 ( ) ;
266
+ assert_eq ! ( int, Some ( 0x3736353433323130 ) ) ;
220
267
221
- let int = bytes. read_u64 ( ) ;
268
+ let int = unsafe { bytes. read_u64 ( ) } ;
222
269
assert_eq ! ( int, 0x3736353433323130 ) ;
223
270
224
271
let mut slc = [ 0u8 ; 8 ] ;
225
- slc. write_u64 ( 0x3736353433323130 ) ;
272
+ unsafe { slc. write_u64 ( 0x3736353433323130 ) } ;
226
273
assert_eq ! ( & slc, bytes) ;
227
274
}
228
275
}
0 commit comments