11use crate :: errors:: { ParsingError , Result } ;
2+ use core:: convert:: TryFrom ;
23
34/// Try to parse the given array of bytes into an f64, by first converting
45/// it to the corresponding ASCII (or even here, UTF-8) values.
@@ -8,20 +9,50 @@ pub fn parse_f64(value: &[u8]) -> Result<f64> {
89 Ok ( res_f64)
910}
1011
11- /// Try to parse the given array of bytes into an i64, by first converting
12- /// it to the corresponding ASCII (or even here, UTF-8) values.
12+ /// Try to parse the given array of ASCII bytes into an i64.
1313pub fn parse_i64 ( value : & [ u8 ] ) -> Result < i64 > {
14- let res = std:: str:: from_utf8 ( value) ?;
15- let res_u64 = res. parse :: < i64 > ( ) ?;
16- Ok ( res_u64)
14+ let ( is_negative, digits) = match value. first ( ) {
15+ Some ( b'-' ) => ( true , & value[ 1 ..] ) ,
16+ Some ( b'+' ) => ( false , & value[ 1 ..] ) ,
17+ _ => ( false , value) ,
18+ } ;
19+ let magnitude = parse_unsigned_digits ( digits) ?;
20+ if is_negative {
21+ if magnitude == ( i64:: MAX as u64 ) + 1 {
22+ Ok ( i64:: MIN )
23+ } else {
24+ let value = i64:: try_from ( magnitude) . map_err ( |_| invalid_integer ( ) ) ?;
25+ Ok ( -value)
26+ }
27+ } else {
28+ i64:: try_from ( magnitude) . map_err ( |_| invalid_integer ( ) )
29+ }
1730}
1831
19- /// Try to parse the given array of bytes into an u64, by first converting
20- /// it to the corresponding ASCII (or even here, UTF-8) values.
32+ /// Try to parse the given array of ASCII bytes into a u64.
2133pub fn parse_u64 ( value : & [ u8 ] ) -> Result < u64 > {
22- let res = std:: str:: from_utf8 ( value) ?;
23- let res_u64 = res. parse :: < u64 > ( ) ?;
24- Ok ( res_u64)
34+ let digits = value. strip_prefix ( b"+" ) . unwrap_or ( value) ;
35+ parse_unsigned_digits ( digits)
36+ }
37+
38+ fn parse_unsigned_digits ( value : & [ u8 ] ) -> Result < u64 > {
39+ if value. is_empty ( ) {
40+ return Err ( invalid_integer ( ) ) ;
41+ }
42+ let mut result = 0u64 ;
43+ for byte in value {
44+ let digit = byte. checked_sub ( b'0' ) . filter ( |digit| * digit <= 9 ) ;
45+ let digit = digit. ok_or_else ( invalid_integer) ?;
46+ result = result
47+ . checked_mul ( 10 )
48+ . and_then ( |number| number. checked_add ( u64:: from ( digit) ) )
49+ . ok_or_else ( invalid_integer) ?;
50+ }
51+ Ok ( result)
52+ }
53+
54+ fn invalid_integer ( ) -> ParsingError {
55+ ParsingError ( "Invalid integer found in the MPD." . to_owned ( ) )
2556}
2657
2758/// Try to parse the given array of bytes into an f64:
@@ -219,6 +250,30 @@ pub fn u32_to_u8_slice_be(x: u32) -> [u8; 4] {
219250mod tests {
220251 use super :: * ;
221252
253+ #[ test]
254+ fn test_parse_integers ( ) {
255+ assert_eq ! ( parse_u64( b"0" ) . unwrap( ) , 0 ) ;
256+ assert_eq ! ( parse_u64( b"+42" ) . unwrap( ) , 42 ) ;
257+ assert_eq ! ( parse_u64( b"18446744073709551615" ) . unwrap( ) , u64 :: MAX ) ;
258+ assert_eq ! ( parse_i64( b"+42" ) . unwrap( ) , 42 ) ;
259+ assert_eq ! ( parse_i64( b"-42" ) . unwrap( ) , -42 ) ;
260+ assert_eq ! ( parse_i64( b"9223372036854775807" ) . unwrap( ) , i64 :: MAX ) ;
261+ assert_eq ! ( parse_i64( b"-9223372036854775808" ) . unwrap( ) , i64 :: MIN ) ;
262+
263+ for invalid in [
264+ b"" . as_slice ( ) ,
265+ b"+" ,
266+ b"-" ,
267+ b"12a" ,
268+ b" 12" ,
269+ b"18446744073709551616" ,
270+ ] {
271+ assert ! ( parse_u64( invalid) . is_err( ) ) ;
272+ }
273+ assert ! ( parse_i64( b"9223372036854775808" ) . is_err( ) ) ;
274+ assert ! ( parse_i64( b"-9223372036854775809" ) . is_err( ) ) ;
275+ }
276+
222277 #[ test]
223278 fn test_parse_maybe_division ( ) {
224279 assert_eq ! ( parse_maybe_division( b" 100 / 50 " ) . unwrap( ) , 100. / 50. ) ;
0 commit comments