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 ] ,
@@ -21,10 +44,6 @@ impl<'a> Parser<'a> {
21
44
Parser { state : input. as_bytes ( ) }
22
45
}
23
46
24
- fn is_eof ( & self ) -> bool {
25
- self . state . is_empty ( )
26
- }
27
-
28
47
/// Run a parser, and restore the pre-parse state if it fails
29
48
fn read_atomically < T , F > ( & mut self , inner : F ) -> Option < T >
30
49
where
@@ -40,26 +59,19 @@ impl<'a> Parser<'a> {
40
59
41
60
/// Run a parser, but fail if the entire input wasn't consumed.
42
61
/// Doesn't run atomically.
43
- fn read_till_eof < T , F > ( & mut self , inner : F ) -> Option < T >
44
- where
45
- F : FnOnce ( & mut Parser < ' _ > ) -> Option < T > ,
46
- {
47
- inner ( self ) . filter ( |_| self . is_eof ( ) )
48
- }
49
-
50
- /// Same as read_till_eof, but returns a Result<AddrParseError> on failure
51
62
fn parse_with < T , F > ( & mut self , inner : F ) -> Result < T , AddrParseError >
52
63
where
53
64
F : FnOnce ( & mut Parser < ' _ > ) -> Option < T > ,
54
65
{
55
- self . read_till_eof ( inner) . ok_or ( AddrParseError ( ( ) ) )
66
+ let result = inner ( self ) ;
67
+ if self . state . is_empty ( ) { result } else { None } . ok_or ( AddrParseError ( ( ) ) )
56
68
}
57
69
58
70
/// Read the next character from the input
59
71
fn read_char ( & mut self ) -> Option < char > {
60
72
self . state . split_first ( ) . map ( |( & b, tail) | {
61
73
self . state = tail;
62
- b as char
74
+ char:: from ( b )
63
75
} )
64
76
}
65
77
@@ -84,25 +96,26 @@ impl<'a> Parser<'a> {
84
96
} )
85
97
}
86
98
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
99
// Read a number off the front of the input in the given radix, stopping
94
100
// 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 > {
101
+ // digits than max_digits or if there is no number.
102
+ fn read_number < T : ReadNumberHelper > (
103
+ & mut self ,
104
+ radix : u32 ,
105
+ max_digits : Option < usize > ,
106
+ ) -> Option < T > {
97
107
self . read_atomically ( move |p| {
98
- let mut result = 0 ;
108
+ let mut result = T :: ZERO ;
99
109
let mut digit_count = 0 ;
100
110
101
- while let Some ( digit) = p. read_digit ( radix) {
102
- result = ( result * radix) + digit;
111
+ while let Some ( digit) = p. read_atomically ( |p| p. read_char ( ) ?. to_digit ( radix) ) {
112
+ result = result. checked_mul ( radix) ?;
113
+ result = result. checked_add ( digit) ?;
103
114
digit_count += 1 ;
104
- if digit_count > max_digits || result >= upto {
105
- return None ;
115
+ if let Some ( max_digits) = max_digits {
116
+ if digit_count > max_digits {
117
+ return None ;
118
+ }
106
119
}
107
120
}
108
121
@@ -116,7 +129,7 @@ impl<'a> Parser<'a> {
116
129
let mut groups = [ 0 ; 4 ] ;
117
130
118
131
for ( i, slot) in groups. iter_mut ( ) . enumerate ( ) {
119
- * slot = p. read_separator ( '.' , i, |p| p. read_number ( 10 , 3 , 0x100 ) ) ? as u8 ;
132
+ * slot = p. read_separator ( '.' , i, |p| p. read_number ( 10 , None ) ) ?;
120
133
}
121
134
122
135
Some ( groups. into ( ) )
@@ -140,17 +153,17 @@ impl<'a> Parser<'a> {
140
153
let ipv4 = p. read_separator ( ':' , i, |p| p. read_ipv4_addr ( ) ) ;
141
154
142
155
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 ) ;
156
+ let [ one , two , three , four ] = v4_addr. octets ( ) ;
157
+ groups[ i + 0 ] = u16:: from_be_bytes ( [ one , two ] ) ;
158
+ groups[ i + 1 ] = u16:: from_be_bytes ( [ three , four ] ) ;
146
159
return ( i + 2 , true ) ;
147
160
}
148
161
}
149
162
150
- let group = p. read_separator ( ':' , i, |p| p. read_number ( 16 , 4 , 0x10000 ) ) ;
163
+ let group = p. read_separator ( ':' , i, |p| p. read_number ( 16 , Some ( 4 ) ) ) ;
151
164
152
165
match group {
153
- Some ( g) => * slot = g as u16 ,
166
+ Some ( g) => * slot = g,
154
167
None => return ( i, false ) ,
155
168
}
156
169
}
@@ -195,12 +208,11 @@ impl<'a> Parser<'a> {
195
208
self . read_ipv4_addr ( ) . map ( IpAddr :: V4 ) . or_else ( move || self . read_ipv6_addr ( ) . map ( IpAddr :: V6 ) )
196
209
}
197
210
198
- /// Read a : followed by a port in base 10
211
+ /// Read a : followed by a port in base 10.
199
212
fn read_port ( & mut self ) -> Option < u16 > {
200
213
self . read_atomically ( |p| {
201
214
let _ = p. read_given_char ( ':' ) ?;
202
- let port = p. read_number ( 10 , 5 , 0x10000 ) ?;
203
- Some ( port as u16 )
215
+ p. read_number ( 10 , None )
204
216
} )
205
217
}
206
218
0 commit comments