6
6
#[ cfg( test) ]
7
7
mod tests;
8
8
9
+ use crate :: convert:: TryInto as _;
9
10
use crate :: error:: Error ;
10
11
use crate :: fmt;
11
12
use crate :: net:: { IpAddr , Ipv4Addr , Ipv6Addr , SocketAddr , SocketAddrV4 , SocketAddrV6 } ;
12
13
use crate :: str:: FromStr ;
13
14
15
+ trait ReadNumberHelper : crate :: marker:: Sized {
16
+ const ZERO : Self ;
17
+ fn checked_mul ( & self , other : u32 ) -> Option < Self > ;
18
+ fn checked_add ( & self , other : u32 ) -> Option < Self > ;
19
+ }
20
+
21
+ macro_rules! impl_helper {
22
+ ( $( $t: ty) * ) => ( $( impl ReadNumberHelper for $t {
23
+ const ZERO : Self = 0 ;
24
+ #[ inline]
25
+ fn checked_mul( & self , other: u32 ) -> Option <Self > {
26
+ Self :: checked_mul( * self , other. try_into( ) . ok( ) ?)
27
+ }
28
+ #[ inline]
29
+ fn checked_add( & self , other: u32 ) -> Option <Self > {
30
+ Self :: checked_add( * self , other. try_into( ) . ok( ) ?)
31
+ }
32
+ } ) * )
33
+ }
34
+
35
+ impl_helper ! { u8 u16 }
36
+
14
37
struct Parser < ' a > {
15
38
// parsing as ASCII, so can use byte array
16
39
state : & ' a [ u8 ] ,
@@ -59,7 +82,7 @@ impl<'a> Parser<'a> {
59
82
fn read_char ( & mut self ) -> Option < char > {
60
83
self . state . split_first ( ) . map ( |( & b, tail) | {
61
84
self . state = tail;
62
- b as char
85
+ char:: from ( b )
63
86
} )
64
87
}
65
88
@@ -84,25 +107,26 @@ impl<'a> Parser<'a> {
84
107
} )
85
108
}
86
109
87
- // Read a single digit in the given radix. For instance, 0-9 in radix 10;
88
- // 0-9A-F in radix 16.
89
- fn read_digit ( & mut self , radix : u32 ) -> Option < u32 > {
90
- self . read_atomically ( move |p| p. read_char ( ) ?. to_digit ( radix) )
91
- }
92
-
93
110
// Read a number off the front of the input in the given radix, stopping
94
111
// at the first non-digit character or eof. Fails if the number has more
95
- // digits than max_digits, or the value is >= upto, or if there is no number.
96
- fn read_number ( & mut self , radix : u32 , max_digits : u32 , upto : u32 ) -> Option < u32 > {
112
+ // digits than max_digits or if there is no number.
113
+ fn read_number < T : ReadNumberHelper > (
114
+ & mut self ,
115
+ radix : u32 ,
116
+ max_digits : Option < usize > ,
117
+ ) -> Option < T > {
97
118
self . read_atomically ( move |p| {
98
- let mut result = 0 ;
119
+ let mut result = T :: ZERO ;
99
120
let mut digit_count = 0 ;
100
121
101
- while let Some ( digit) = p. read_digit ( radix) {
102
- result = ( result * radix) + digit;
122
+ while let Some ( digit) = p. read_atomically ( |p| p. read_char ( ) ?. to_digit ( radix) ) {
123
+ result = result. checked_mul ( radix) ?;
124
+ result = result. checked_add ( digit) ?;
103
125
digit_count += 1 ;
104
- if digit_count > max_digits || result >= upto {
105
- return None ;
126
+ if let Some ( max_digits) = max_digits {
127
+ if digit_count > max_digits {
128
+ return None ;
129
+ }
106
130
}
107
131
}
108
132
@@ -116,7 +140,7 @@ impl<'a> Parser<'a> {
116
140
let mut groups = [ 0 ; 4 ] ;
117
141
118
142
for ( i, slot) in groups. iter_mut ( ) . enumerate ( ) {
119
- * slot = p. read_separator ( '.' , i, |p| p. read_number ( 10 , 3 , 0x100 ) ) ? as u8 ;
143
+ * slot = p. read_separator ( '.' , i, |p| p. read_number ( 10 , None ) ) ?;
120
144
}
121
145
122
146
Some ( groups. into ( ) )
@@ -140,17 +164,17 @@ impl<'a> Parser<'a> {
140
164
let ipv4 = p. read_separator ( ':' , i, |p| p. read_ipv4_addr ( ) ) ;
141
165
142
166
if let Some ( v4_addr) = ipv4 {
143
- let octets = v4_addr. octets ( ) ;
144
- groups[ i + 0 ] = ( ( octets [ 0 ] as u16 ) << 8 ) | ( octets [ 1 ] as u16 ) ;
145
- groups[ i + 1 ] = ( ( octets [ 2 ] as u16 ) << 8 ) | ( octets [ 3 ] as u16 ) ;
167
+ let [ one , two , three , four ] = v4_addr. octets ( ) ;
168
+ groups[ i + 0 ] = u16:: from_be_bytes ( [ one , two ] ) ;
169
+ groups[ i + 1 ] = u16:: from_be_bytes ( [ three , four ] ) ;
146
170
return ( i + 2 , true ) ;
147
171
}
148
172
}
149
173
150
- let group = p. read_separator ( ':' , i, |p| p. read_number ( 16 , 4 , 0x10000 ) ) ;
174
+ let group = p. read_separator ( ':' , i, |p| p. read_number ( 16 , Some ( 4 ) ) ) ;
151
175
152
176
match group {
153
- Some ( g) => * slot = g as u16 ,
177
+ Some ( g) => * slot = g,
154
178
None => return ( i, false ) ,
155
179
}
156
180
}
@@ -195,12 +219,11 @@ impl<'a> Parser<'a> {
195
219
self . read_ipv4_addr ( ) . map ( IpAddr :: V4 ) . or_else ( move || self . read_ipv6_addr ( ) . map ( IpAddr :: V6 ) )
196
220
}
197
221
198
- /// Read a : followed by a port in base 10
222
+ /// Read a : followed by a port in base 10.
199
223
fn read_port ( & mut self ) -> Option < u16 > {
200
224
self . read_atomically ( |p| {
201
225
let _ = p. read_given_char ( ':' ) ?;
202
- let port = p. read_number ( 10 , 5 , 0x10000 ) ?;
203
- Some ( port as u16 )
226
+ p. read_number ( 10 , None )
204
227
} )
205
228
}
206
229
0 commit comments