1 //! Low-level API generator. 2 //! 3 //! Uses either the imprecise or the precise algorithm. 4 5 use crate::lib::slice; 6 use crate::util::*; 7 8 // Select the back-end 9 cfg_if! { 10 if #[cfg(feature = "correct")] { 11 use super::algorithm::correct as algorithm; 12 } else { 13 use super::algorithm::incorrect as algorithm; 14 }} // cfg_if 15 16 // TRAITS 17 18 /// Trait to define parsing of a string to float. 19 trait StringToFloat: Float { 20 /// Serialize string to float, favoring correctness. default(bytes: &[u8], radix: u32, lossy: bool, sign: Sign, format: NumberFormat) -> ParseResult<(Self, *const u8)>21 fn default(bytes: &[u8], radix: u32, lossy: bool, sign: Sign, format: NumberFormat) -> ParseResult<(Self, *const u8)>; 22 } 23 24 impl StringToFloat for f32 { 25 perftools_inline_always!{ 26 fn default(bytes: &[u8], radix: u32, lossy: bool, sign: Sign, format: NumberFormat) 27 -> ParseResult<(f32, *const u8)> 28 { 29 algorithm::atof(bytes, radix, lossy, sign, format) 30 }} 31 } 32 33 impl StringToFloat for f64 { 34 perftools_inline_always!{ 35 fn default(bytes: &[u8], radix: u32, lossy: bool, sign: Sign, format: NumberFormat) 36 -> ParseResult<(f64, *const u8)> 37 { 38 algorithm::atod(bytes, radix, lossy, sign, format) 39 }} 40 } 41 42 // SPECIAL 43 // Utilities to filter special values. 44 45 // Convert slice to iterator without digit separators. 46 perftools_inline!{ 47 fn to_iter<'a>(bytes: &'a [u8], _: u8) -> slice::Iter<'a, u8> { 48 bytes.iter() 49 }} 50 51 // Convert slice to iterator with digit separators. 52 perftools_inline!{ 53 #[cfg(feature = "format")] 54 fn to_iter_s<'a>(bytes: &'a [u8], digit_separator: u8) -> SkipValueIterator<'a, u8> { 55 SkipValueIterator::new(bytes, digit_separator) 56 }} 57 58 // PARSER 59 60 // Parse infinity from string. 61 perftools_inline!{ 62 fn parse_infinity<'a, ToIter, StartsWith, Iter, F>( 63 bytes: &'a [u8], 64 radix: u32, 65 lossy: bool, 66 sign: Sign, 67 format: NumberFormat, 68 to_iter: ToIter, 69 starts_with: StartsWith 70 ) 71 -> ParseResult<(F, *const u8)> 72 where F: StringToFloat, 73 ToIter: Fn(&'a [u8], u8) -> Iter, 74 Iter: AsPtrIterator<'a, u8>, 75 StartsWith: Fn(Iter, slice::Iter<'a, u8>) -> (bool, Iter) 76 { 77 let infinity = get_infinity_string(); 78 let inf = get_inf_string(); 79 if let (true, iter) = starts_with(to_iter(bytes, format.digit_separator()), infinity.iter()) { 80 Ok((F::INFINITY, iter.as_ptr())) 81 } else if let (true, iter) = starts_with(to_iter(bytes, format.digit_separator()), inf.iter()) { 82 Ok((F::INFINITY, iter.as_ptr())) 83 } else { 84 // Not infinity, may be valid with a different radix. 85 if cfg!(feature = "radix"){ 86 F::default(bytes, radix, lossy, sign, format) 87 } else { 88 Err((ErrorCode::InvalidDigit, bytes.as_ptr())) 89 } 90 } 91 }} 92 93 // Parse NaN from string. 94 perftools_inline!{ 95 fn parse_nan<'a, ToIter, StartsWith, Iter, F>( 96 bytes: &'a [u8], 97 radix: u32, 98 lossy: bool, 99 sign: Sign, 100 format: NumberFormat, 101 to_iter: ToIter, 102 starts_with: StartsWith 103 ) 104 -> ParseResult<(F, *const u8)> 105 where F: StringToFloat, 106 ToIter: Fn(&'a [u8], u8) -> Iter, 107 Iter: AsPtrIterator<'a, u8>, 108 StartsWith: Fn(Iter, slice::Iter<'a, u8>) -> (bool, Iter) 109 { 110 let nan = get_nan_string(); 111 if let (true, iter) = starts_with(to_iter(bytes, format.digit_separator()), nan.iter()) { 112 Ok((F::NAN, iter.as_ptr())) 113 } else { 114 // Not NaN, may be valid with a different radix. 115 if cfg!(feature = "radix"){ 116 F::default(bytes, radix, lossy, sign, format) 117 } else { 118 Err((ErrorCode::InvalidDigit, bytes.as_ptr())) 119 } 120 } 121 }} 122 123 // ATOF/ATOD 124 125 // Parse special or float values with the standard format. 126 // Special values are allowed, the match is case-insensitive, 127 // and no digit separators are allowed. 128 perftools_inline!{ 129 fn parse_float_standard<F: StringToFloat>(bytes: &[u8], radix: u32, lossy: bool, sign: Sign, format: NumberFormat) 130 -> ParseResult<(F, *const u8)> 131 { 132 // Use predictive parsing to filter special cases. This leads to 133 // dramatic performance gains. 134 let starts_with = case_insensitive_starts_with_iter; 135 match index!(bytes[0]) { 136 b'i' | b'I' => parse_infinity(bytes, radix, lossy, sign, format, to_iter, starts_with), 137 b'N' | b'n' => parse_nan(bytes, radix, lossy, sign, format, to_iter, starts_with), 138 _ => F::default(bytes, radix, lossy, sign, format), 139 } 140 }} 141 142 // Parse special or float values. 143 // Special values are allowed, the match is case-sensitive, 144 // and digit separators are allowed. 145 perftools_inline!{ 146 #[cfg(feature = "format")] 147 fn parse_float_cs<F: StringToFloat>(bytes: &[u8], radix: u32, lossy: bool, sign: Sign, format: NumberFormat) 148 -> ParseResult<(F, *const u8)> 149 { 150 let digit_separator = format.digit_separator(); 151 let starts_with = starts_with_iter; 152 match SkipValueIterator::new(bytes, digit_separator).next() { 153 Some(&b'i') | Some(&b'I') => parse_infinity(bytes, radix, lossy, sign, format, to_iter_s, starts_with), 154 Some(&b'n') | Some(&b'N') => parse_nan(bytes, radix, lossy, sign, format, to_iter_s, starts_with), 155 _ => F::default(bytes, radix, lossy, sign, format), 156 } 157 }} 158 159 // Parse special or float values. 160 // Special values are allowed, the match is case-sensitive, 161 // and no digit separators are allowed. 162 perftools_inline!{ 163 #[cfg(feature = "format")] 164 fn parse_float_c<F: StringToFloat>(bytes: &[u8], radix: u32, lossy: bool, sign: Sign, format: NumberFormat) 165 -> ParseResult<(F, *const u8)> 166 { 167 // Use predictive parsing to filter special cases. This leads to 168 // dramatic performance gains. 169 let starts_with = starts_with_iter; 170 match index!(bytes[0]) { 171 b'i' | b'I' => parse_infinity(bytes, radix, lossy, sign, format, to_iter, starts_with), 172 b'N' | b'n' => parse_nan(bytes, radix, lossy, sign, format, to_iter, starts_with), 173 _ => F::default(bytes, radix, lossy, sign, format), 174 } 175 }} 176 177 // Parse special or float values. 178 // Special values are allowed, the match is case-insensitive, 179 // and digit separators are allowed. 180 perftools_inline!{ 181 #[cfg(feature = "format")] 182 fn parse_float_s<F: StringToFloat>(bytes: &[u8], radix: u32, lossy: bool, sign: Sign, format: NumberFormat) 183 -> ParseResult<(F, *const u8)> 184 { 185 let digit_separator = format.digit_separator(); 186 let starts_with = case_insensitive_starts_with_iter; 187 match SkipValueIterator::new(bytes, digit_separator).next() { 188 Some(&b'i') | Some(&b'I') => parse_infinity(bytes, radix, lossy, sign, format, to_iter_s, starts_with), 189 Some(&b'n') | Some(&b'N') => parse_nan(bytes, radix, lossy, sign, format, to_iter_s, starts_with), 190 _ => F::default(bytes, radix, lossy, sign, format), 191 } 192 }} 193 194 // Parse special or float values with the default formatter. 195 perftools_inline!{ 196 #[cfg(not(feature = "format"))] 197 fn parse_float<F: StringToFloat>(bytes: &[u8], radix: u32, lossy: bool, sign: Sign, format: NumberFormat) 198 -> ParseResult<(F, *const u8)> 199 { 200 parse_float_standard(bytes, radix, lossy, sign, format) 201 }} 202 203 // Parse special or float values with the default formatter. 204 perftools_inline!{ 205 #[cfg(feature = "format")] 206 fn parse_float<F: StringToFloat>(bytes: &[u8], radix: u32, lossy: bool, sign: Sign, format: NumberFormat) 207 -> ParseResult<(F, *const u8)> 208 { 209 // Need to consider 3 possibilities: 210 // 1). No special values are allowed. 211 // 2). Special values are case-sensitive. 212 // 3). Digit separators are allowed in the special. 213 let no_special = format.no_special(); 214 let case = format.case_sensitive_special(); 215 let has_sep = format.special_digit_separator(); 216 match (no_special, case, has_sep) { 217 (true, _, _) => F::default(bytes, radix, lossy, sign, format), 218 (false, true, true) => parse_float_cs(bytes, radix, lossy, sign, format), 219 (false, false, true) => parse_float_s(bytes, radix, lossy, sign, format), 220 (false, true, false) => parse_float_c(bytes, radix, lossy, sign, format), 221 (false, false, false) => parse_float_standard(bytes, radix, lossy, sign, format), 222 } 223 }} 224 225 // Validate sign byte is valid. 226 perftools_inline!{ 227 #[cfg(not(feature = "format"))] 228 fn validate_sign(_: &[u8], _: &[u8], _: Sign, _: NumberFormat) 229 -> ParseResult<()> 230 { 231 Ok(()) 232 }} 233 234 // Validate sign byte is valid. 235 perftools_inline!{ 236 #[cfg(feature = "format")] 237 fn validate_sign(bytes: &[u8], digits: &[u8], sign: Sign, format: NumberFormat) 238 -> ParseResult<()> 239 { 240 let has_sign = bytes.as_ptr() != digits.as_ptr(); 241 if format.no_positive_mantissa_sign() && has_sign && sign == Sign::Positive { 242 Err((ErrorCode::InvalidPositiveMantissaSign, bytes.as_ptr())) 243 } else if format.required_mantissa_sign() && !has_sign { 244 Err((ErrorCode::MissingMantissaSign, bytes.as_ptr())) 245 } else { 246 Ok(()) 247 } 248 }} 249 250 // Convert float to signed representation. 251 perftools_inline!{ 252 fn to_signed<F: StringToFloat>(float: F, sign: Sign) -> F 253 { 254 match sign { 255 Sign::Positive => float, 256 Sign::Negative => -float 257 } 258 }} 259 260 // Standalone atof processor. 261 perftools_inline!{ 262 fn atof<F: StringToFloat>(bytes: &[u8], radix: u32, lossy: bool, format: NumberFormat) 263 -> ParseResult<(F, *const u8)> 264 { 265 let (sign, digits) = parse_sign::<F>(bytes, format); 266 if digits.is_empty() { 267 return Err((ErrorCode::Empty, digits.as_ptr())); 268 } 269 let (float, ptr): (F, *const u8) = parse_float(digits, radix, lossy, sign, format)?; 270 validate_sign(bytes, digits, sign, format)?; 271 272 Ok((to_signed(float, sign), ptr)) 273 }} 274 275 perftools_inline!{ 276 fn atof_lossy<F: StringToFloat>(bytes: &[u8], radix: u32) 277 -> Result<(F, usize)> 278 { 279 let index = | ptr | distance(bytes.as_ptr(), ptr); 280 match atof::<F>(bytes, radix, true, NumberFormat::standard().unwrap()) { 281 Ok((value, ptr)) => Ok((value, index(ptr))), 282 Err((code, ptr)) => Err((code, index(ptr)).into()), 283 } 284 }} 285 286 perftools_inline!{ 287 fn atof_nonlossy<F: StringToFloat>(bytes: &[u8], radix: u32) 288 -> Result<(F, usize)> 289 { 290 let index = | ptr | distance(bytes.as_ptr(), ptr); 291 match atof::<F>(bytes, radix, false, NumberFormat::standard().unwrap()) { 292 Ok((value, ptr)) => Ok((value, index(ptr))), 293 Err((code, ptr)) => Err((code, index(ptr)).into()), 294 } 295 }} 296 297 perftools_inline!{ 298 #[cfg(feature = "format")] 299 fn atof_format<F: StringToFloat>(bytes: &[u8], radix: u32, format: NumberFormat) 300 -> Result<(F, usize)> 301 { 302 let index = | ptr | distance(bytes.as_ptr(), ptr); 303 match atof::<F>(bytes, radix, false, format) { 304 Ok((value, ptr)) => Ok((value, index(ptr))), 305 Err((code, ptr)) => Err((code, index(ptr)).into()), 306 } 307 }} 308 309 perftools_inline!{ 310 #[cfg(feature = "format")] 311 fn atof_lossy_format<F: StringToFloat>(bytes: &[u8], radix: u32, format: NumberFormat) 312 -> Result<(F, usize)> 313 { 314 let index = | ptr | distance(bytes.as_ptr(), ptr); 315 match atof::<F>(bytes, radix, true, format) { 316 Ok((value, ptr)) => Ok((value, index(ptr))), 317 Err((code, ptr)) => Err((code, index(ptr)).into()), 318 } 319 }} 320 321 // FROM LEXICAL 322 // ------------ 323 324 from_lexical!(atof_nonlossy, f32); 325 from_lexical!(atof_nonlossy, f64); 326 from_lexical_lossy!(atof_lossy, f32); 327 from_lexical_lossy!(atof_lossy, f64); 328 329 cfg_if!{ 330 if #[cfg(feature = "format")] { 331 from_lexical_format!(atof_format, f32); 332 from_lexical_format!(atof_format, f64); 333 from_lexical_lossy_format!(atof_lossy_format, f32); 334 from_lexical_lossy_format!(atof_lossy_format, f64); 335 }} 336 337 // TESTS 338 // ----- 339 340 #[cfg(test)] 341 mod tests { 342 use crate::util::*; 343 344 use approx::assert_relative_eq; 345 #[cfg(all(feature = "std", feature = "property_tests"))] 346 use proptest::{proptest, prop_assert_eq, prop_assert}; 347 348 #[test] f32_decimal_test()349 fn f32_decimal_test() { 350 // integer test 351 assert_f32_eq!(0.0, f32::from_lexical(b"0").unwrap()); 352 assert_f32_eq!(1.0, f32::from_lexical(b"1").unwrap()); 353 assert_f32_eq!(12.0, f32::from_lexical(b"12").unwrap()); 354 assert_f32_eq!(123.0, f32::from_lexical(b"123").unwrap()); 355 assert_f32_eq!(1234.0, f32::from_lexical(b"1234").unwrap()); 356 assert_f32_eq!(12345.0, f32::from_lexical(b"12345").unwrap()); 357 assert_f32_eq!(123456.0, f32::from_lexical(b"123456").unwrap()); 358 assert_f32_eq!(1234567.0, f32::from_lexical(b"1234567").unwrap()); 359 assert_f32_eq!(12345678.0, f32::from_lexical(b"12345678").unwrap()); 360 361 // No fraction after decimal point test 362 assert_f32_eq!(1.0, f32::from_lexical(b"1.").unwrap()); 363 assert_f32_eq!(12.0, f32::from_lexical(b"12.").unwrap()); 364 assert_f32_eq!(1234567.0, f32::from_lexical(b"1234567.").unwrap()); 365 366 // No integer before decimal point test 367 assert_f32_eq!(0.1, f32::from_lexical(b".1").unwrap()); 368 assert_f32_eq!(0.12, f32::from_lexical(b".12").unwrap()); 369 assert_f32_eq!(0.1234567, f32::from_lexical(b".1234567").unwrap()); 370 371 // decimal test 372 assert_f32_eq!(123.1, f32::from_lexical(b"123.1").unwrap()); 373 assert_f32_eq!(123.12, f32::from_lexical(b"123.12").unwrap()); 374 assert_f32_eq!(123.123, f32::from_lexical(b"123.123").unwrap()); 375 assert_f32_eq!(123.1234, f32::from_lexical(b"123.1234").unwrap()); 376 assert_f32_eq!(123.12345, f32::from_lexical(b"123.12345").unwrap()); 377 378 // rounding test 379 assert_f32_eq!(123456790.0, f32::from_lexical(b"123456789").unwrap()); 380 assert_f32_eq!(123456790.0, f32::from_lexical(b"123456789.1").unwrap()); 381 assert_f32_eq!(123456790.0, f32::from_lexical(b"123456789.12").unwrap()); 382 assert_f32_eq!(123456790.0, f32::from_lexical(b"123456789.123").unwrap()); 383 assert_f32_eq!(123456790.0, f32::from_lexical(b"123456789.1234").unwrap()); 384 assert_f32_eq!(123456790.0, f32::from_lexical(b"123456789.12345").unwrap()); 385 386 // exponent test 387 assert_f32_eq!(123456789.12345, f32::from_lexical(b"1.2345678912345e8").unwrap()); 388 assert_f32_eq!(123450000.0, f32::from_lexical(b"1.2345e+8").unwrap()); 389 assert_f32_eq!(1.2345e+11, f32::from_lexical(b"1.2345e+11").unwrap()); 390 assert_f32_eq!(1.2345e+11, f32::from_lexical(b"123450000000").unwrap()); 391 assert_f32_eq!(1.2345e+38, f32::from_lexical(b"1.2345e+38").unwrap()); 392 assert_f32_eq!(1.2345e+38, f32::from_lexical(b"123450000000000000000000000000000000000").unwrap()); 393 assert_f32_eq!(1.2345e-8, f32::from_lexical(b"1.2345e-8").unwrap()); 394 assert_f32_eq!(1.2345e-8, f32::from_lexical(b"0.000000012345").unwrap()); 395 assert_f32_eq!(1.2345e-38, f32::from_lexical(b"1.2345e-38").unwrap()); 396 assert_f32_eq!(1.2345e-38, f32::from_lexical(b"0.000000000000000000000000000000000000012345").unwrap()); 397 398 assert!(f32::from_lexical(b"NaN").unwrap().is_nan()); 399 assert!(f32::from_lexical(b"nan").unwrap().is_nan()); 400 assert!(f32::from_lexical(b"NAN").unwrap().is_nan()); 401 assert!(f32::from_lexical(b"inf").unwrap().is_infinite()); 402 assert!(f32::from_lexical(b"INF").unwrap().is_infinite()); 403 assert!(f32::from_lexical(b"+inf").unwrap().is_infinite()); 404 assert!(f32::from_lexical(b"-inf").unwrap().is_infinite()); 405 406 // Check various expected failures. 407 assert_eq!(Err(ErrorCode::Empty.into()), f32::from_lexical(b"")); 408 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f32::from_lexical(b"e")); 409 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f32::from_lexical(b"E")); 410 assert_eq!(Err(ErrorCode::EmptyMantissa.into()), f32::from_lexical(b".e1")); 411 assert_eq!(Err(ErrorCode::EmptyMantissa.into()), f32::from_lexical(b".e-1")); 412 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f32::from_lexical(b"e1")); 413 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f32::from_lexical(b"e-1")); 414 assert_eq!(Err((ErrorCode::Empty, 1).into()), f32::from_lexical(b"+")); 415 assert_eq!(Err((ErrorCode::Empty, 1).into()), f32::from_lexical(b"-")); 416 417 // Bug fix for Issue #8 418 assert_eq!(Ok(5.002868148396374), f32::from_lexical(b"5.002868148396374")); 419 } 420 421 #[cfg(feature = "radix")] 422 #[test] f32_radix_test()423 fn f32_radix_test() { 424 assert_f32_eq!(1234.0, f32::from_lexical_radix(b"YA", 36).unwrap()); 425 assert_f32_eq!(1234.0, f32::from_lexical_lossy_radix(b"YA", 36).unwrap()); 426 } 427 428 #[test] f64_decimal_test()429 fn f64_decimal_test() { 430 // integer test 431 assert_f64_eq!(0.0, f64::from_lexical(b"0").unwrap()); 432 assert_f64_eq!(1.0, f64::from_lexical(b"1").unwrap()); 433 assert_f64_eq!(12.0, f64::from_lexical(b"12").unwrap()); 434 assert_f64_eq!(123.0, f64::from_lexical(b"123").unwrap()); 435 assert_f64_eq!(1234.0, f64::from_lexical(b"1234").unwrap()); 436 assert_f64_eq!(12345.0, f64::from_lexical(b"12345").unwrap()); 437 assert_f64_eq!(123456.0, f64::from_lexical(b"123456").unwrap()); 438 assert_f64_eq!(1234567.0, f64::from_lexical(b"1234567").unwrap()); 439 assert_f64_eq!(12345678.0, f64::from_lexical(b"12345678").unwrap()); 440 441 // No fraction after decimal point test 442 assert_f64_eq!(1.0, f64::from_lexical(b"1.").unwrap()); 443 assert_f64_eq!(12.0, f64::from_lexical(b"12.").unwrap()); 444 assert_f64_eq!(1234567.0, f64::from_lexical(b"1234567.").unwrap()); 445 446 // No integer before decimal point test 447 assert_f64_eq!(0.1, f64::from_lexical(b".1").unwrap()); 448 assert_f64_eq!(0.12, f64::from_lexical(b".12").unwrap()); 449 assert_f64_eq!(0.1234567, f64::from_lexical(b".1234567").unwrap()); 450 451 // decimal test 452 assert_f64_eq!(123456789.0, f64::from_lexical(b"123456789").unwrap()); 453 assert_f64_eq!(123456789.1, f64::from_lexical(b"123456789.1").unwrap()); 454 assert_f64_eq!(123456789.12, f64::from_lexical(b"123456789.12").unwrap()); 455 assert_f64_eq!(123456789.123, f64::from_lexical(b"123456789.123").unwrap()); 456 assert_f64_eq!(123456789.1234, f64::from_lexical(b"123456789.1234").unwrap()); 457 assert_f64_eq!(123456789.12345, f64::from_lexical(b"123456789.12345").unwrap()); 458 assert_f64_eq!(123456789.123456, f64::from_lexical(b"123456789.123456").unwrap()); 459 assert_f64_eq!(123456789.1234567, f64::from_lexical(b"123456789.1234567").unwrap()); 460 assert_f64_eq!(123456789.12345678, f64::from_lexical(b"123456789.12345678").unwrap()); 461 462 // rounding test 463 assert_f64_eq!(123456789.12345679, f64::from_lexical(b"123456789.123456789").unwrap()); 464 assert_f64_eq!(123456789.12345679, f64::from_lexical(b"123456789.1234567890").unwrap()); 465 assert_f64_eq!(123456789.12345679, f64::from_lexical(b"123456789.123456789012").unwrap()); 466 assert_f64_eq!(123456789.12345679, f64::from_lexical(b"123456789.1234567890123").unwrap()); 467 assert_f64_eq!(123456789.12345679, f64::from_lexical(b"123456789.12345678901234").unwrap()); 468 469 // exponent test 470 assert_f64_eq!(123456789.12345, f64::from_lexical(b"1.2345678912345e8").unwrap()); 471 assert_f64_eq!(123450000.0, f64::from_lexical(b"1.2345e+8").unwrap()); 472 assert_f64_eq!(1.2345e+11, f64::from_lexical(b"123450000000").unwrap()); 473 assert_f64_eq!(1.2345e+11, f64::from_lexical(b"1.2345e+11").unwrap()); 474 assert_f64_eq!(1.2345e+38, f64::from_lexical(b"1.2345e+38").unwrap()); 475 assert_f64_eq!(1.2345e+38, f64::from_lexical(b"123450000000000000000000000000000000000").unwrap()); 476 assert_f64_eq!(1.2345e+308, f64::from_lexical(b"1.2345e+308").unwrap()); 477 assert_f64_eq!(1.2345e+308, f64::from_lexical(b"123450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()); 478 assert_f64_eq!(0.000000012345, f64::from_lexical(b"1.2345e-8").unwrap()); 479 assert_f64_eq!(1.2345e-8, f64::from_lexical(b"0.000000012345").unwrap()); 480 assert_f64_eq!(1.2345e-38, f64::from_lexical(b"1.2345e-38").unwrap()); 481 assert_f64_eq!(1.2345e-38, f64::from_lexical(b"0.000000000000000000000000000000000000012345").unwrap()); 482 483 // denormalized (try extremely low values) 484 assert_f64_eq!(1.2345e-308, f64::from_lexical(b"1.2345e-308").unwrap()); 485 // These next 3 tests fail on arm-unknown-linux-gnueabi with the 486 // incorrect parser. 487 #[cfg(all(not(feature = "correct"), not(target_arch = "arm")))] 488 assert_eq!(Ok(5e-322), f64::from_lexical(b"5e-322")); 489 #[cfg(all(not(feature = "correct"), not(target_arch = "arm")))] 490 assert_eq!(Ok(5e-323), f64::from_lexical(b"5e-323")); 491 #[cfg(all(not(feature = "correct"), not(target_arch = "arm")))] 492 assert_eq!(Ok(5e-324), f64::from_lexical(b"5e-324")); 493 // due to issues in how the data is parsed, manually extracting 494 // non-exponents of 1.<e-299 is prone to error 495 // test the limit of our ability 496 // We tend to get relative errors of 1e-16, even at super low values. 497 assert_f64_eq!(1.2345e-299, f64::from_lexical(b"0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345").unwrap(), epsilon=1e-314); 498 499 // Keep pushing from -300 to -324 500 assert_f64_eq!(1.2345e-300, f64::from_lexical(b"0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345").unwrap(), epsilon=1e-315); 501 502 // These next 3 tests fail on arm-unknown-linux-gnueabi with the 503 // incorrect parser. 504 #[cfg(all(not(feature = "correct"), not(target_arch = "arm")))] 505 assert_f64_eq!(1.2345e-310, f64::from_lexical(b"0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345").unwrap(), epsilon=5e-324); 506 #[cfg(all(not(feature = "correct"), not(target_arch = "arm")))] 507 assert_f64_eq!(1.2345e-320, f64::from_lexical(b"0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345").unwrap(), epsilon=5e-324); 508 #[cfg(all(not(feature = "correct"), not(target_arch = "arm")))] 509 assert_f64_eq!(1.2345e-321, f64::from_lexical(b"0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345").unwrap(), epsilon=5e-324); 510 #[cfg(all(not(feature = "correct"), not(target_arch = "arm")))] 511 assert_f64_eq!(1.24e-322, f64::from_lexical(b"0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000124").unwrap(), epsilon=5e-324); 512 #[cfg(all(not(feature = "correct"), not(target_arch = "arm")))] 513 assert_eq!(Ok(1e-323), f64::from_lexical(b"0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001")); 514 #[cfg(all(not(feature = "correct"), not(target_arch = "arm")))] 515 assert_eq!(Ok(5e-324), f64::from_lexical(b"0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005")); 516 517 assert!(f64::from_lexical(b"NaN").unwrap().is_nan()); 518 assert!(f64::from_lexical(b"nan").unwrap().is_nan()); 519 assert!(f64::from_lexical(b"NAN").unwrap().is_nan()); 520 assert!(f64::from_lexical(b"inf").unwrap().is_infinite()); 521 assert!(f64::from_lexical(b"INF").unwrap().is_infinite()); 522 assert!(f64::from_lexical(b"+inf").unwrap().is_infinite()); 523 assert!(f64::from_lexical(b"-inf").unwrap().is_infinite()); 524 525 // Check various expected failures. 526 assert_eq!(Err(ErrorCode::Empty.into()), f64::from_lexical(b"")); 527 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f64::from_lexical(b"e")); 528 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f64::from_lexical(b"E")); 529 assert_eq!(Err(ErrorCode::EmptyMantissa.into()), f64::from_lexical(b".e1")); 530 assert_eq!(Err(ErrorCode::EmptyMantissa.into()), f64::from_lexical(b".e-1")); 531 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f64::from_lexical(b"e1")); 532 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f64::from_lexical(b"e-1")); 533 534 // Check various reports from a fuzzer. 535 assert_eq!(Err((ErrorCode::EmptyExponent, 2).into()), f64::from_lexical(b"0e")); 536 assert_eq!(Err((ErrorCode::EmptyExponent, 4).into()), f64::from_lexical(b"0.0e")); 537 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f64::from_lexical(b".E")); 538 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f64::from_lexical(b".e")); 539 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f64::from_lexical(b"E2252525225")); 540 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f64::from_lexical(b"e2252525225")); 541 assert_eq!(Ok(f64::INFINITY), f64::from_lexical(b"2E200000000000")); 542 543 // Add various unittests from proptests. 544 assert_eq!(Err((ErrorCode::EmptyExponent, 2).into()), f64::from_lexical(b"0e")); 545 assert_eq!(Err((ErrorCode::EmptyMantissa, 0).into()), f64::from_lexical(b".")); 546 assert_eq!(Err((ErrorCode::EmptyMantissa, 1).into()), f64::from_lexical(b"+.")); 547 assert_eq!(Err((ErrorCode::EmptyMantissa, 1).into()), f64::from_lexical(b"-.")); 548 assert_eq!(Err((ErrorCode::Empty, 1).into()), f64::from_lexical(b"+")); 549 assert_eq!(Err((ErrorCode::Empty, 1).into()), f64::from_lexical(b"-")); 550 551 // Bug fix for Issue #8 552 assert_eq!(Ok(5.002868148396374), f64::from_lexical(b"5.002868148396374")); 553 } 554 555 #[test] 556 #[should_panic] limit_test()557 fn limit_test() { 558 assert_relative_eq!(1.2345e-320, 0.0, epsilon=5e-324); 559 } 560 561 #[cfg(feature = "radix")] 562 #[test] f64_radix_test()563 fn f64_radix_test() { 564 assert_f64_eq!(1234.0, f64::from_lexical_radix(b"YA", 36).unwrap()); 565 assert_f64_eq!(1234.0, f64::from_lexical_lossy_radix(b"YA", 36).unwrap()); 566 } 567 568 #[test] f32_lossy_decimal_test()569 fn f32_lossy_decimal_test() { 570 assert_eq!(Err(ErrorCode::EmptyMantissa.into()), f32::from_lexical_lossy(b".")); 571 assert_eq!(Err(ErrorCode::Empty.into()), f32::from_lexical_lossy(b"")); 572 assert_eq!(Ok(0.0), f32::from_lexical_lossy(b"0.0")); 573 assert_eq!(Err((ErrorCode::InvalidDigit, 1).into()), f32::from_lexical_lossy(b"1a")); 574 575 // Bug fix for Issue #8 576 assert_eq!(Ok(5.002868148396374), f32::from_lexical_lossy(b"5.002868148396374")); 577 } 578 579 #[test] f64_lossy_decimal_test()580 fn f64_lossy_decimal_test() { 581 assert_eq!(Err(ErrorCode::EmptyMantissa.into()), f64::from_lexical_lossy(b".")); 582 assert_eq!(Err(ErrorCode::Empty.into()), f64::from_lexical_lossy(b"")); 583 assert_eq!(Ok(0.0), f64::from_lexical_lossy(b"0.0")); 584 assert_eq!(Err((ErrorCode::InvalidDigit, 1).into()), f64::from_lexical_lossy(b"1a")); 585 586 // Bug fix for Issue #8 587 assert_eq!(Ok(5.002868148396374), f64::from_lexical_lossy(b"5.002868148396374")); 588 } 589 590 #[test] 591 #[cfg(feature = "format")] f64_special_test()592 fn f64_special_test() { 593 // Comments match (no_special, case_sensitive, has_sep) 594 let f1 = NumberFormat::standard().unwrap(); // false, false, false 595 let f2 = NumberFormat::ignore(b'_').unwrap(); // false, false, true 596 let f3 = f1 | NumberFormat::NO_SPECIAL; // true, _, _ 597 let f4 = f1 | NumberFormat::CASE_SENSITIVE_SPECIAL; // false, true, false 598 let f5 = f2 | NumberFormat::CASE_SENSITIVE_SPECIAL; // false, true, true 599 600 // Easy NaN 601 assert!(f64::from_lexical_format(b"NaN", f1).unwrap().is_nan()); 602 assert!(f64::from_lexical_format(b"NaN", f2).unwrap().is_nan()); 603 assert!(f64::from_lexical_format(b"NaN", f3).is_err()); 604 assert!(f64::from_lexical_format(b"NaN", f4).unwrap().is_nan()); 605 assert!(f64::from_lexical_format(b"NaN", f5).unwrap().is_nan()); 606 607 // Case-sensitive NaN. 608 assert!(f64::from_lexical_format(b"nan", f1).unwrap().is_nan()); 609 assert!(f64::from_lexical_format(b"nan", f2).unwrap().is_nan()); 610 assert!(f64::from_lexical_format(b"nan", f3).is_err()); 611 assert!(f64::from_lexical_format(b"nan", f4).is_err()); 612 assert!(f64::from_lexical_format(b"nan", f5).is_err()); 613 614 // Digit-separator NaN. 615 assert!(f64::from_lexical_format(b"N_aN", f1).is_err()); 616 assert!(f64::from_lexical_format(b"N_aN", f2).unwrap().is_nan()); 617 assert!(f64::from_lexical_format(b"N_aN", f3).is_err()); 618 assert!(f64::from_lexical_format(b"N_aN", f4).is_err()); 619 assert!(f64::from_lexical_format(b"N_aN", f5).unwrap().is_nan()); 620 621 // Digit-separator + case-sensitive NaN. 622 assert!(f64::from_lexical_format(b"n_an", f1).is_err()); 623 assert!(f64::from_lexical_format(b"n_an", f2).unwrap().is_nan()); 624 assert!(f64::from_lexical_format(b"n_an", f3).is_err()); 625 assert!(f64::from_lexical_format(b"n_an", f4).is_err()); 626 assert!(f64::from_lexical_format(b"n_an", f5).is_err()); 627 } 628 629 #[test] 630 #[cfg(feature = "format")] f64_required_integer_digits_test()631 fn f64_required_integer_digits_test() { 632 let format = NumberFormat::REQUIRED_INTEGER_DIGITS; 633 assert!(f64::from_lexical_format(b"+3.0", format).is_ok()); 634 assert!(f64::from_lexical_format(b"3.0", format).is_ok()); 635 assert!(f64::from_lexical_format(b".0", format).is_err()); 636 } 637 638 #[test] 639 #[cfg(feature = "format")] f64_required_fraction_digits_test()640 fn f64_required_fraction_digits_test() { 641 let format = NumberFormat::REQUIRED_FRACTION_DIGITS; 642 assert!(f64::from_lexical_format(b"+3.0", format).is_ok()); 643 assert!(f64::from_lexical_format(b"3.0", format).is_ok()); 644 assert!(f64::from_lexical_format(b"3.", format).is_err()); 645 assert!(f64::from_lexical_format(b"3", format).is_ok()); 646 } 647 648 #[test] 649 #[cfg(feature = "format")] f64_required_digits_test()650 fn f64_required_digits_test() { 651 let format = NumberFormat::REQUIRED_DIGITS; 652 assert!(f64::from_lexical_format(b"+3.0", format).is_ok()); 653 assert!(f64::from_lexical_format(b"3.0", format).is_ok()); 654 assert!(f64::from_lexical_format(b"3.", format).is_err()); 655 assert!(f64::from_lexical_format(b"3", format).is_ok()); 656 assert!(f64::from_lexical_format(b".0", format).is_err()); 657 } 658 659 #[test] 660 #[cfg(feature = "format")] f64_no_positive_mantissa_sign_test()661 fn f64_no_positive_mantissa_sign_test() { 662 let format = NumberFormat::NO_POSITIVE_MANTISSA_SIGN; 663 assert!(f64::from_lexical_format(b"+3.0", format).is_err()); 664 assert!(f64::from_lexical_format(b"-3.0", format).is_ok()); 665 assert!(f64::from_lexical_format(b"3.0", format).is_ok()); 666 } 667 668 #[test] 669 #[cfg(feature = "format")] f64_required_mantissa_sign_test()670 fn f64_required_mantissa_sign_test() { 671 let format = NumberFormat::REQUIRED_MANTISSA_SIGN; 672 assert!(f64::from_lexical_format(b"+3.0", format).is_ok()); 673 assert!(f64::from_lexical_format(b"-3.0", format).is_ok()); 674 assert!(f64::from_lexical_format(b"3.0", format).is_err()); 675 } 676 677 #[test] 678 #[cfg(feature = "format")] f64_no_exponent_notation_test()679 fn f64_no_exponent_notation_test() { 680 let format = NumberFormat::NO_EXPONENT_NOTATION; 681 assert!(f64::from_lexical_format(b"+3.0e7", format).is_err()); 682 assert!(f64::from_lexical_format(b"+3.0e-7", format).is_err()); 683 assert!(f64::from_lexical_format(b"+3e", format).is_err()); 684 assert!(f64::from_lexical_format(b"+3e-", format).is_err()); 685 assert!(f64::from_lexical_format(b"+3.0", format).is_ok()); 686 assert!(f64::from_lexical_format(b"+3", format).is_ok()); 687 } 688 689 #[test] 690 #[cfg(feature = "format")] f64_optional_exponent_test()691 fn f64_optional_exponent_test() { 692 let format = NumberFormat::permissive().unwrap(); 693 assert!(f64::from_lexical_format(b"+3.0e7", format).is_ok()); 694 assert!(f64::from_lexical_format(b"+3.0e-7", format).is_ok()); 695 assert!(f64::from_lexical_format(b"+3.0e", format).is_ok()); 696 assert!(f64::from_lexical_format(b"+3.0e-", format).is_ok()); 697 assert!(f64::from_lexical_format(b"+3.0", format).is_ok()); 698 } 699 700 #[test] 701 #[cfg(feature = "format")] f64_required_exponent_test()702 fn f64_required_exponent_test() { 703 let format = NumberFormat::REQUIRED_EXPONENT_DIGITS; 704 assert!(f64::from_lexical_format(b"+3.0e7", format).is_ok()); 705 assert!(f64::from_lexical_format(b"+3.0e-7", format).is_ok()); 706 assert!(f64::from_lexical_format(b"+3.0e", format).is_err()); 707 assert!(f64::from_lexical_format(b"+3.0e-", format).is_err()); 708 assert!(f64::from_lexical_format(b"+3.0", format).is_ok()); 709 } 710 711 #[test] 712 #[cfg(feature = "format")] f64_no_positive_exponent_sign_test()713 fn f64_no_positive_exponent_sign_test() { 714 let format = NumberFormat::NO_POSITIVE_EXPONENT_SIGN; 715 assert!(f64::from_lexical_format(b"3.0e7", format).is_ok()); 716 assert!(f64::from_lexical_format(b"3.0e+7", format).is_err()); 717 assert!(f64::from_lexical_format(b"3.0e-7", format).is_ok()); 718 } 719 720 #[test] 721 #[cfg(feature = "format")] f64_required_exponent_sign_test()722 fn f64_required_exponent_sign_test() { 723 let format = NumberFormat::REQUIRED_EXPONENT_SIGN; 724 assert!(f64::from_lexical_format(b"3.0e7", format).is_err()); 725 assert!(f64::from_lexical_format(b"3.0e+7", format).is_ok()); 726 assert!(f64::from_lexical_format(b"3.0e-7", format).is_ok()); 727 } 728 729 #[test] 730 #[cfg(feature = "format")] f64_no_exponent_without_fraction_test()731 fn f64_no_exponent_without_fraction_test() { 732 let format = NumberFormat::NO_EXPONENT_WITHOUT_FRACTION; 733 assert!(f64::from_lexical_format(b"3.0e7", format).is_ok()); 734 assert!(f64::from_lexical_format(b"3.e7", format).is_ok()); 735 assert!(f64::from_lexical_format(b"3e7", format).is_err()); 736 737 let format = format | NumberFormat::REQUIRED_FRACTION_DIGITS; 738 assert!(f64::from_lexical_format(b"3.0e7", format).is_ok()); 739 assert!(f64::from_lexical_format(b"3.e7", format).is_err()); 740 assert!(f64::from_lexical_format(b"3e7", format).is_err()); 741 } 742 743 #[test] 744 #[cfg(feature = "format")] f64_no_leading_zeros_test()745 fn f64_no_leading_zeros_test() { 746 let format = NumberFormat::NO_FLOAT_LEADING_ZEROS; 747 assert!(f64::from_lexical_format(b"1.0", format).is_ok()); 748 assert!(f64::from_lexical_format(b"0.0", format).is_ok()); 749 assert!(f64::from_lexical_format(b"01.0", format).is_err()); 750 assert!(f64::from_lexical_format(b"10.0", format).is_ok()); 751 assert!(f64::from_lexical_format(b"010.0", format).is_err()); 752 } 753 754 #[test] 755 #[cfg(feature = "format")] f64_integer_internal_digit_separator_test()756 fn f64_integer_internal_digit_separator_test() { 757 let format = NumberFormat::from_separator(b'_') | NumberFormat::INTEGER_INTERNAL_DIGIT_SEPARATOR; 758 assert!(f64::from_lexical_format(b"3_1.0e7", format).is_ok()); 759 assert!(f64::from_lexical_format(b"_31.0e7", format).is_err()); 760 assert!(f64::from_lexical_format(b"31_.0e7", format).is_err()); 761 } 762 763 #[test] 764 #[cfg(feature = "format")] f64_fraction_internal_digit_separator_test()765 fn f64_fraction_internal_digit_separator_test() { 766 let format = NumberFormat::from_separator(b'_') | NumberFormat::FRACTION_INTERNAL_DIGIT_SEPARATOR; 767 assert!(f64::from_lexical_format(b"31.0_1e7", format).is_ok()); 768 assert!(f64::from_lexical_format(b"31._01e7", format).is_err()); 769 assert!(f64::from_lexical_format(b"31.01_e7", format).is_err()); 770 } 771 772 #[test] 773 #[cfg(feature = "format")] f64_exponent_internal_digit_separator_test()774 fn f64_exponent_internal_digit_separator_test() { 775 let format = NumberFormat::from_separator(b'_') | NumberFormat::EXPONENT_INTERNAL_DIGIT_SEPARATOR; 776 assert!(f64::from_lexical_format(b"31.01e7_1", format).is_ok()); 777 assert!(f64::from_lexical_format(b"31.01e_71", format).is_err()); 778 assert!(f64::from_lexical_format(b"31.01e71_", format).is_err()); 779 } 780 781 #[test] 782 #[cfg(feature = "format")] f64_integer_leading_digit_separator_test()783 fn f64_integer_leading_digit_separator_test() { 784 let format = NumberFormat::from_separator(b'_') | NumberFormat::INTEGER_LEADING_DIGIT_SEPARATOR; 785 assert!(f64::from_lexical_format(b"3_1.0e7", format).is_err()); 786 assert!(f64::from_lexical_format(b"_31.0e7", format).is_ok()); 787 assert!(f64::from_lexical_format(b"31_.0e7", format).is_err()); 788 } 789 790 #[test] 791 #[cfg(feature = "format")] f64_fraction_leading_digit_separator_test()792 fn f64_fraction_leading_digit_separator_test() { 793 let format = NumberFormat::from_separator(b'_') | NumberFormat::FRACTION_LEADING_DIGIT_SEPARATOR; 794 assert!(f64::from_lexical_format(b"31.0_1e7", format).is_err()); 795 assert!(f64::from_lexical_format(b"31._01e7", format).is_ok()); 796 assert!(f64::from_lexical_format(b"31.01_e7", format).is_err()); 797 } 798 799 #[test] 800 #[cfg(feature = "format")] f64_exponent_leading_digit_separator_test()801 fn f64_exponent_leading_digit_separator_test() { 802 let format = NumberFormat::from_separator(b'_') | NumberFormat::EXPONENT_LEADING_DIGIT_SEPARATOR; 803 assert!(f64::from_lexical_format(b"31.01e7_1", format).is_err()); 804 assert!(f64::from_lexical_format(b"31.01e_71", format).is_ok()); 805 assert!(f64::from_lexical_format(b"31.01e71_", format).is_err()); 806 } 807 808 #[test] 809 #[cfg(feature = "format")] f64_integer_trailing_digit_separator_test()810 fn f64_integer_trailing_digit_separator_test() { 811 let format = NumberFormat::from_separator(b'_') | NumberFormat::INTEGER_TRAILING_DIGIT_SEPARATOR; 812 assert!(f64::from_lexical_format(b"3_1.0e7", format).is_err()); 813 assert!(f64::from_lexical_format(b"_31.0e7", format).is_err()); 814 assert!(f64::from_lexical_format(b"31_.0e7", format).is_ok()); 815 } 816 817 #[test] 818 #[cfg(feature = "format")] f64_fraction_trailing_digit_separator_test()819 fn f64_fraction_trailing_digit_separator_test() { 820 let format = NumberFormat::from_separator(b'_') | NumberFormat::FRACTION_TRAILING_DIGIT_SEPARATOR; 821 assert!(f64::from_lexical_format(b"31.0_1e7", format).is_err()); 822 assert!(f64::from_lexical_format(b"31._01e7", format).is_err()); 823 assert!(f64::from_lexical_format(b"31.01_e7", format).is_ok()); 824 } 825 826 #[test] 827 #[cfg(feature = "format")] f64_exponent_trailing_digit_separator_test()828 fn f64_exponent_trailing_digit_separator_test() { 829 let format = NumberFormat::from_separator(b'_') | NumberFormat::EXPONENT_TRAILING_DIGIT_SEPARATOR; 830 assert!(f64::from_lexical_format(b"31.01e7_1", format).is_err()); 831 assert!(f64::from_lexical_format(b"31.01e_71", format).is_err()); 832 assert!(f64::from_lexical_format(b"31.01e71_", format).is_ok()); 833 } 834 835 #[test] 836 #[cfg(feature = "format")] f64_integer_consecutive_digit_separator_test()837 fn f64_integer_consecutive_digit_separator_test() { 838 let format = NumberFormat::from_separator(b'_') 839 | NumberFormat::INTEGER_INTERNAL_DIGIT_SEPARATOR 840 | NumberFormat::INTEGER_CONSECUTIVE_DIGIT_SEPARATOR; 841 assert!(f64::from_lexical_format(b"3__1.0e7", format).is_ok()); 842 assert!(f64::from_lexical_format(b"_31.0e7", format).is_err()); 843 assert!(f64::from_lexical_format(b"31_.0e7", format).is_err()); 844 } 845 846 #[test] 847 #[cfg(feature = "format")] f64_fraction_consecutive_digit_separator_test()848 fn f64_fraction_consecutive_digit_separator_test() { 849 let format = NumberFormat::from_separator(b'_') 850 | NumberFormat::FRACTION_INTERNAL_DIGIT_SEPARATOR 851 | NumberFormat::FRACTION_CONSECUTIVE_DIGIT_SEPARATOR; 852 assert!(f64::from_lexical_format(b"31.0__1e7", format).is_ok()); 853 assert!(f64::from_lexical_format(b"31._01e7", format).is_err()); 854 assert!(f64::from_lexical_format(b"31.01_e7", format).is_err()); 855 } 856 857 #[test] 858 #[cfg(feature = "format")] f64_exponent_consecutive_digit_separator_test()859 fn f64_exponent_consecutive_digit_separator_test() { 860 let format = NumberFormat::from_separator(b'_') 861 | NumberFormat::EXPONENT_INTERNAL_DIGIT_SEPARATOR 862 | NumberFormat::EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR; 863 assert!(f64::from_lexical_format(b"31.01e7__1", format).is_ok()); 864 assert!(f64::from_lexical_format(b"31.01e_71", format).is_err()); 865 assert!(f64::from_lexical_format(b"31.01e71_", format).is_err()); 866 } 867 868 #[test] 869 #[cfg(feature = "format")] f64_json_exponent_without_dot()870 fn f64_json_exponent_without_dot() { 871 // Tests courtesy of @ijl: 872 // https://github.com/Alexhuszagh/rust-lexical/issues/24#issuecomment-578153783 873 let format = NumberFormat::JSON; 874 // JSONTestSuite/test_parsing/y_number_0e1.json 875 assert!(f64::from_lexical_format(b"0e1", format).is_ok()); 876 // JSONTestSuite/test_parsing/y_number_int_with_exp.json 877 assert!(f64::from_lexical_format(b"20e1", format).is_ok()); 878 // JSONTestSuite/test_parsing/y_number_real_capital_e_pos_exp.json 879 assert!(f64::from_lexical_format(b"1E+2", format).is_ok()); 880 // JSONTestSuite/test_transform/number_1e-999.json 881 assert!(f64::from_lexical_format(b"1E-999", format).is_ok()); 882 // nativejson-benchmark/data/jsonchecker/pass01.json 883 assert!(f64::from_lexical_format(b"23456789012E66", format).is_ok()); 884 } 885 #[test] 886 #[cfg(feature = "format")] f64_json_exponent_requires_digit()887 fn f64_json_exponent_requires_digit() { 888 // Tests courtesy of @ijl: 889 // https://github.com/Alexhuszagh/rust-lexical/issues/24#issuecomment-578153783 890 let format = NumberFormat::JSON; 891 assert!(f64::from_lexical_format(b"1e", format).is_err()); 892 // JSONTestSuite/test_parsing/n_number_9.e+.json 893 assert!(f64::from_lexical_format(b"9.e+", format).is_err()); 894 // JSONTestSuite/test_parsing/n_number_2.e-3.json 895 assert!(f64::from_lexical_format(b"2.e-3", format).is_err()); 896 // JSONTestSuite/test_parsing/n_number_real_without_fractional_part.json 897 assert!(f64::from_lexical_format(b"1.", format).is_err()); 898 } 899 900 #[test] 901 #[cfg(feature = "format")] f64_json_no_leading_zero()902 fn f64_json_no_leading_zero() { 903 let format = NumberFormat::JSON; 904 assert!(f64::from_lexical_format(b"12.0", format).is_ok()); 905 assert!(f64::from_lexical_format(b"-12.0", format).is_ok()); 906 assert!(f64::from_lexical_format(b"012.0", format).is_err()); 907 assert!(f64::from_lexical_format(b"-012.0", format).is_err()); 908 } 909 910 #[cfg(all(feature = "std", feature = "property_tests"))] 911 proptest! { 912 #[test] 913 fn f32_invalid_proptest(i in r"[+-]?[0-9]{2}[^\deE]?\.[^\deE]?[0-9]{2}[^\deE]?e[+-]?[0-9]+[^\deE]") { 914 let res = f32::from_lexical(i.as_bytes()); 915 prop_assert!(res.is_err()); 916 let err = res.err().unwrap(); 917 prop_assert_eq!(err.code, ErrorCode::InvalidDigit); 918 } 919 920 #[test] 921 fn f32_double_sign_proptest(i in r"[+-]{2}[0-9]{2}\.[0-9]{2}e[+-]?[0-9]+") { 922 let res = f32::from_lexical(i.as_bytes()); 923 prop_assert!(res.is_err()); 924 let err = res.err().unwrap(); 925 prop_assert!(err.code == ErrorCode::InvalidDigit || err.code == ErrorCode::EmptyMantissa); 926 prop_assert!(err.index == 0 || err.index == 1); 927 } 928 929 #[test] 930 fn f32_sign_or_dot_only_proptest(i in r"[+-]?\.?") { 931 let res = f32::from_lexical(i.as_bytes()); 932 prop_assert!(res.is_err()); 933 let err = res.err().unwrap(); 934 prop_assert!(err.code == ErrorCode::Empty || err.code == ErrorCode::EmptyMantissa); 935 prop_assert!(err.index == 0 || err.index == 1); 936 } 937 938 #[test] 939 fn f32_double_exponent_sign_proptest(i in r"[+-]?[0-9]{2}\.[0-9]{2}e[+-]{2}[0-9]+") { 940 let res = f32::from_lexical(i.as_bytes()); 941 prop_assert!(res.is_err()); 942 let err = res.err().unwrap(); 943 prop_assert_eq!(err.code, ErrorCode::EmptyExponent); 944 } 945 946 #[test] 947 fn f32_missing_exponent_proptest(i in r"[+-]?[0-9]{2}\.[0-9]{2}e[+-]?") { 948 let res = f32::from_lexical(i.as_bytes()); 949 prop_assert!(res.is_err()); 950 let err = res.err().unwrap(); 951 prop_assert_eq!(err.code, ErrorCode::EmptyExponent); 952 } 953 954 #[cfg(feature = "correct")] 955 #[test] 956 fn f32_roundtrip_display_proptest(i in f32::MIN..f32::MAX) { 957 let input: String = format!("{}", i); 958 prop_assert_eq!(i, f32::from_lexical(input.as_bytes()).unwrap()); 959 } 960 961 #[cfg(feature = "correct")] 962 #[test] 963 fn f32_roundtrip_debug_proptest(i in f32::MIN..f32::MAX) { 964 let input: String = format!("{:?}", i); 965 prop_assert_eq!(i, f32::from_lexical(input.as_bytes()).unwrap()); 966 } 967 968 #[cfg(feature = "correct")] 969 #[test] 970 fn f32_roundtrip_scientific_proptest(i in f32::MIN..f32::MAX) { 971 let input: String = format!("{:e}", i); 972 prop_assert_eq!(i, f32::from_lexical(input.as_bytes()).unwrap()); 973 } 974 975 #[test] 976 fn f64_invalid_proptest(i in r"[+-]?[0-9]{2}[^\deE]?\.[^\deE]?[0-9]{2}[^\deE]?e[+-]?[0-9]+[^\deE]") { 977 let res = f64::from_lexical(i.as_bytes()); 978 prop_assert!(res.is_err()); 979 let err = res.err().unwrap(); 980 prop_assert_eq!(err.code, ErrorCode::InvalidDigit); 981 } 982 983 #[test] 984 fn f64_double_sign_proptest(i in r"[+-]{2}[0-9]{2}\.[0-9]{2}e[+-]?[0-9]+") { 985 let res = f64::from_lexical(i.as_bytes()); 986 prop_assert!(res.is_err()); 987 let err = res.err().unwrap(); 988 prop_assert!(err.code == ErrorCode::InvalidDigit || err.code == ErrorCode::EmptyMantissa); 989 prop_assert!(err.index == 0 || err.index == 1); 990 } 991 992 #[test] 993 fn f64_sign_or_dot_only_proptest(i in r"[+-]?\.?") { 994 let res = f64::from_lexical(i.as_bytes()); 995 prop_assert!(res.is_err()); 996 let err = res.err().unwrap(); 997 prop_assert!(err.code == ErrorCode::Empty || err.code == ErrorCode::EmptyMantissa); 998 prop_assert!(err.index == 0 || err.index == 1); 999 } 1000 1001 #[test] 1002 fn f64_double_exponent_sign_proptest(i in r"[+-]?[0-9]{2}\.[0-9]{2}e[+-]{2}[0-9]+") { 1003 let res = f64::from_lexical(i.as_bytes()); 1004 prop_assert!(res.is_err()); 1005 let err = res.err().unwrap(); 1006 prop_assert_eq!(err.code, ErrorCode::EmptyExponent); 1007 } 1008 1009 #[test] 1010 fn f64_missing_exponent_proptest(i in r"[+-]?[0-9]{2}\.[0-9]{2}e[+-]?") { 1011 let res = f64::from_lexical(i.as_bytes()); 1012 prop_assert!(res.is_err()); 1013 let err = res.err().unwrap(); 1014 prop_assert_eq!(err.code, ErrorCode::EmptyExponent); 1015 } 1016 1017 #[cfg(feature = "correct")] 1018 #[test] 1019 fn f64_roundtrip_display_proptest(i in f64::MIN..f64::MAX) { 1020 let input: String = format!("{}", i); 1021 prop_assert_eq!(i, f64::from_lexical(input.as_bytes()).unwrap()); 1022 } 1023 1024 #[cfg(feature = "correct")] 1025 #[test] 1026 fn f64_roundtrip_debug_proptest(i in f64::MIN..f64::MAX) { 1027 let input: String = format!("{:?}", i); 1028 prop_assert_eq!(i, f64::from_lexical(input.as_bytes()).unwrap()); 1029 } 1030 1031 #[cfg(feature = "correct")] 1032 #[test] 1033 fn f64_roundtrip_scientific_proptest(i in f64::MIN..f64::MAX) { 1034 let input: String = format!("{:e}", i); 1035 prop_assert_eq!(i, f64::from_lexical(input.as_bytes()).unwrap()); 1036 } 1037 } 1038 } 1039