@@ -181,11 +181,13 @@ impl ParsedNumber {
181181 } ;
182182 }
183183
184+ let trimmed_input = input. trim_ascii_start ( ) ;
185+
184186 // Initial minus sign
185- let ( negative, unsigned) = if let Some ( input) = input . strip_prefix ( '-' ) {
187+ let ( negative, unsigned) = if let Some ( input) = trimmed_input . strip_prefix ( '-' ) {
186188 ( true , input)
187189 } else {
188- ( false , input )
190+ ( false , trimmed_input )
189191 } ;
190192
191193 // Parse an optional base prefix ("0b" / "0B" / "0" / "0x" / "0X"). "0" is octal unless a
@@ -384,4 +386,24 @@ mod tests {
384386 assert_eq ! ( Ok ( 0b1011 ) , ParsedNumber :: parse_u64( "0b1011" ) ) ;
385387 assert_eq ! ( Ok ( 0b1011 ) , ParsedNumber :: parse_u64( "0B1011" ) ) ;
386388 }
389+
390+ #[ test]
391+ fn test_parsing_with_leading_whitespace ( ) {
392+ assert_eq ! ( Ok ( 1 ) , ParsedNumber :: parse_u64( " 0x1" ) ) ;
393+ assert_eq ! ( Ok ( -2 ) , ParsedNumber :: parse_i64( " -0x2" ) ) ;
394+ assert_eq ! ( Ok ( -3 ) , ParsedNumber :: parse_i64( " \t -0x3" ) ) ;
395+ assert_eq ! ( Ok ( -4 ) , ParsedNumber :: parse_i64( " \n -0x4" ) ) ;
396+ assert_eq ! ( Ok ( -5 ) , ParsedNumber :: parse_i64( " \n \t \u{000d} -0x5" ) ) ;
397+
398+ // Ensure that trailing whitespace is still a partial match
399+ assert_eq ! ( Err ( ParseError :: PartialMatch ( 6 , " " ) ) , ParsedNumber :: parse_u64( "0x6 " ) ) ;
400+ assert_eq ! ( Err ( ParseError :: PartialMatch ( 7 , "\t " ) ) , ParsedNumber :: parse_u64( "0x7\t " ) ) ;
401+ assert_eq ! ( Err ( ParseError :: PartialMatch ( 8 , "\n " ) ) , ParsedNumber :: parse_u64( "0x8\n " ) ) ;
402+
403+ // Ensure that unicode non-ascii whitespace is a partial match
404+ assert_eq ! ( Err ( ParseError :: NotNumeric ) , ParsedNumber :: parse_i64( "\u{2029} -0x9" ) ) ;
405+
406+ // Ensure that whitespace after the number has "started" is not allowed
407+ assert_eq ! ( Err ( ParseError :: NotNumeric ) , ParsedNumber :: parse_i64( "- 0x9" ) ) ;
408+ }
387409}
0 commit comments