use super::errors::Error; use crate::wchar::IntoCharIter; use fast_float::parse_partial_iter; /// Parses a 64-bit floating point number. /// /// Leading whitespace and trailing characters are ignored. If the input /// string does not contain a valid floating point number (where e.g. /// `"."` is seen as a valid floating point number), `None` is returned. /// Otherwise the parsed floating point number is returned. /// /// The `decimal_sep` parameter is used to specify the decimal separator. /// '.' is a normal default. /// /// The `consumed` parameter is used to return the number of characters /// consumed, similar to the "end" parameter to strtod. /// This is only meaningful if parsing succeeds. /// /// Error::Overflow is returned if the value is too large in magnitude. pub fn wcstod(input: Chars, decimal_sep: char, consumed: &mut usize) -> Result where Chars: IntoCharIter, { let chars = input.chars(); if chars.clone().next().is_none() { *consumed = 0; return Err(Error::Empty); } let ret = parse_partial_iter(chars.clone().fuse(), decimal_sep); if ret.is_err() { *consumed = 0; return Err(Error::InvalidChar); } let (val, n): (f64, usize) = ret.unwrap(); // Fast-float does not return overflow errors; instead it just returns +/- infinity. // Check to see if the first character is a digit or the decimal; if so that indicates overflow. if val.is_infinite() { for c in chars { if c.is_whitespace() { continue; } else if c.is_ascii_digit() || c == decimal_sep { return Err(Error::Overflow); } else { break; } } } *consumed = n; Ok(val) } #[cfg(test)] mod test { #![allow(overflowing_literals)] use super::{wcstod, Error}; use std::f64; #[test] #[allow(clippy::all)] pub fn tests() { test("12.345", Ok(12.345)); test("12.345e19", Ok(12.345e19)); test("-.1e+9", Ok(-0.1e+9)); test(".125", Ok(0.125)); test("1e20", Ok(1e20)); test("0e-19", Ok(0.0)); test_consumed("4\00012", Ok(4.0), 1); test("5.9e-76", Ok(5.9e-76)); test("", Err(Error::Empty)); test("Inf", Ok(f64::INFINITY)); test("-Inf", Ok(f64::NEG_INFINITY)); test("+InFiNiTy", Ok(f64::INFINITY)); test("1e-324", Ok(0.0)); test( "+1.000000000116415321826934814453125", Ok(1.000000000116415321826934814453125), ); test("42.0000000000000000001", Ok(42.0000000000000000001)); test("42.00000000000000000001", Ok(42.00000000000000000001)); test("42.000000000000000000001", Ok(42.000000000000000000001)); test("179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368", Ok(179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000)); test_consumed("1y", Ok(1.0), 1); test_consumed("0.y", Ok(0.0), 2); test_consumed(".0y", Ok(0.0), 2); test_consumed("000,,,e1", Ok(0.0), 3); test("000e1", Ok(0.0)); test_consumed("000,1e1", Ok(0.0), 3); test("0", Ok(0.0)); test("000", Ok(0.0)); test("-0", Ok(-0.0)); test("-000", Ok(-0.0)); test_consumed("0,", Ok(0.0), 1); test_consumed("-0,", Ok(-0.0), 2); test_consumed("0,0", Ok(0.0), 1); test_consumed("-0,0", Ok(-0.0), 2); test("0e-10", Ok(0.0)); test("-0e-10", Ok(-0.0)); test_consumed("0,e-10", Ok(0.0), 1); test_consumed("-0,e-10", Ok(-0.0), 2); test_consumed("0,0e-10", Ok(0.0), 1); test_consumed("-0,0e-10", Ok(-0.0), 2); test("0e-1000000", Ok(0.0)); test("-0e-1000000", Ok(-0.0)); test_consumed("0,0e-1000000", Ok(0.0), 1); test_consumed("-0,0e-1000000", Ok(-0.0), 2); test("0", Ok(0.0)); test("000", Ok(0.0)); test("-0", Ok(-0.0)); test("-000", Ok(-0.0)); test("0e-10", Ok(0.0)); test("-0e-10", Ok(-0.0)); test("0e-1000000", Ok(0.0)); test("-0e-1000000", Ok(-0.0)); test("1", Ok(1_f64)); test("1.1", Ok(1.1)); test("1.1e1", Ok(1.1e1)); test("1234.1234", Ok(1234.1234)); test("1234.12345678", Ok(1234.12345678)); test("1234.123456789012", Ok(1234.123456789012)); test( "1.797693134862315708145274237317e+10", Ok(1.797693134862315708145274237317e+10), ); test( "1.797693134862315708145274237317e+308", Ok(1.797693134862315708145274237317e+308_f64), ); test("000000000e123", Ok(0.0)); test("0000000010000e-329", Ok(0.0)); test("000000001e-325", Ok(0.0)); test("0000000020000e-328", Ok(0.0)); test("0000000090000e-329", Ok(0.0)); test("0e+999", Ok(0.0)); test("0e1", Ok(0.0)); test("0e12345", Ok(0.0)); test("0e2", Ok(0.0)); test("0e-2", Ok(0.0)); test("0e-999", Ok(0.0)); test("10000e-329", Ok(0.0)); test("1e-325", Ok(0.0)); test("20000e-328", Ok(0.0)); test("2e-324", Ok(0.0)); test("90000e-329", Ok(0.0)); test_consumed("e1324", Err(Error::InvalidChar), 0); test("1e0", Ok(1.0)); test("17976931348623157e292", Ok(1.7976931348623157E+308)); test("17976931348623158e292", Ok(1.7976931348623158E+308)); test("1e1", Ok(10.0)); test("1e2", Ok(100.0)); test( "10141204801825834086073718800384e0", Ok(10141204801825834086073718800384.0), ); test( "1014120480182583464902367222169599999e-5", Ok(10141204801825834086073718800384.0), ); test( "1014120480182583464902367222169600001e-5", Ok(10141204801825835211973625643008.0), ); test( "10141204801825834649023672221696e0", Ok(10141204801825835211973625643008.0), ); test( "10141204801825835211973625643008e0", Ok(10141204801825835211973625643008.0), ); test("104110013277974872254e-225", Ok(104110013277974872254e-225)); test("12345e0", Ok(12345.0)); test("12345e1", Ok(123450.0)); test("12345e2", Ok(1234500.0)); test("12345678901234e0", Ok(12345678901234.0)); test("12345678901234e1", Ok(123456789012340.0)); test("12345678901234e2", Ok(1234567890123400.0)); test("123456789012345e0", Ok(123456789012345.0)); test("123456789012345e1", Ok(1234567890123450.0)); test("123456789012345e2", Ok(12345678901234500.0)); test( "1234567890123456789012345e108", Ok(1234567890123456789012345e108), ); test( "1234567890123456789012345e109", Ok(1234567890123456789012345e109), ); test( "1234567890123456789012345e110", Ok(1234567890123456789012345e110), ); test( "1234567890123456789012345e111", Ok(1234567890123456789012345e111), ); test( "1234567890123456789012345e112", Ok(1234567890123456789012345e112), ); test( "1234567890123456789012345e113", Ok(1234567890123456789012345e113), ); test( "1234567890123456789012345e114", Ok(1234567890123456789012345e114), ); test( "1234567890123456789012345e115", Ok(1234567890123456789012345e115), ); test( "1234567890123456789052345e108", Ok(1234567890123456789052345e108), ); test( "1234567890123456789052345e109", Ok(1234567890123456789052345e109), ); test( "1234567890123456789052345e110", Ok(1234567890123456789052345e110), ); test( "1234567890123456789052345e111", Ok(1234567890123456789052345e111), ); test( "1234567890123456789052345e112", Ok(1234567890123456789052345e112), ); test( "1234567890123456789052345e113", Ok(1234567890123456789052345e113), ); test( "1234567890123456789052345e114", Ok(1234567890123456789052345e114), ); test( "1234567890123456789052345e115", Ok(1234567890123456789052345e115), ); test("123456789012345e-1", Ok(123456789012345e-1)); test("123456789012345e-2", Ok(123456789012345e-2)); test("123456789012345e20", Ok(123456789012345e20)); test("123456789012345e-20", Ok(123456789012345e-20)); test("123456789012345e22", Ok(123456789012345e22)); test("123456789012345e-22", Ok(123456789012345e-22)); test("123456789012345e23", Ok(123456789012345e23)); test("123456789012345e-23", Ok(123456789012345e-23)); test("123456789012345e-25", Ok(123456789012345e-25)); test("123456789012345e35", Ok(123456789012345e35)); test("123456789012345e36", Ok(123456789012345e36)); test("123456789012345e37", Ok(123456789012345e37)); test("123456789012345e39", Ok(123456789012345e39)); test("123456789012345e-39", Ok(123456789012345e-39)); test("123456789012345e-5", Ok(123456789012345e-5)); test("12345678901234e-1", Ok(12345678901234e-1)); test("12345678901234e-2", Ok(12345678901234e-2)); test("12345678901234e20", Ok(12345678901234e20)); test("12345678901234e-20", Ok(12345678901234e-20)); test("12345678901234e22", Ok(12345678901234e22)); test("12345678901234e-22", Ok(12345678901234e-22)); test("12345678901234e23", Ok(12345678901234e23)); test("12345678901234e-23", Ok(12345678901234e-23)); test("12345678901234e-25", Ok(12345678901234e-25)); test("12345678901234e30", Ok(12345678901234e30)); test("12345678901234e31", Ok(12345678901234e31)); test("12345678901234e32", Ok(12345678901234e32)); test("12345678901234e35", Ok(12345678901234e35)); test("12345678901234e36", Ok(12345678901234e36)); test("12345678901234e37", Ok(12345678901234e37)); test("12345678901234e-39", Ok(12345678901234e-39)); test("12345678901234e-5", Ok(12345678901234e-5)); test("123456789e108", Ok(123456789e108)); test("123456789e109", Ok(123456789e109)); test("123456789e110", Ok(123456789e110)); test("123456789e111", Ok(123456789e111)); test("123456789e112", Ok(123456789e112)); test("123456789e113", Ok(123456789e113)); test("123456789e114", Ok(123456789e114)); test("123456789e115", Ok(123456789e115)); test("12345e-1", Ok(12345e-1)); test("12345e-2", Ok(12345e-2)); test("12345e20", Ok(12345e20)); test("12345e-20", Ok(12345e-20)); test("12345e22", Ok(12345e22)); test("12345e-22", Ok(12345e-22)); test("12345e23", Ok(12345e23)); test("12345e-23", Ok(12345e-23)); test("12345e-25", Ok(12345e-25)); test("12345e30", Ok(12345e30)); test("12345e31", Ok(12345e31)); test("12345e32", Ok(12345e32)); test("12345e35", Ok(12345e35)); test("12345e36", Ok(12345e36)); test("12345e37", Ok(12345e37)); test("12345e-39", Ok(12345e-39)); test("12345e-5", Ok(12345e-5)); test("000000001234e304", Ok(1234e304)); test("0000000123400000e299", Ok(1234e304)); test("123400000e299", Ok(1234e304)); test("1234e304", Ok(1234e304)); test("00000000123400000e300", Ok(1234e305)); test("00000001234e305", Ok(1234e305)); test("123400000e300", Ok(1234e305)); test("1234e305", Ok(1234e305)); test("00000000170000000e300", Ok(17e307)); test("0000000017e307", Ok(17e307)); test("170000000e300", Ok(17e307)); test("17e307", Ok(17e307)); test("1e-1", Ok(1e-1)); test("1e-2", Ok(1e-2)); test("1e20", Ok(1e20)); test("1e-20", Ok(1e-20)); test("1e22", Ok(1e22)); test("1e-22", Ok(1e-22)); test("1e23", Ok(1e23)); test("1e-23", Ok(1e-23)); test("1e-25", Ok(1e-25)); test("000000000000100000e303", Ok(1e308)); test("00000001e308", Ok(1e308)); test("100000e303", Ok(1e308)); test("1e308", Ok(1e308)); test("1e35", Ok(1e35)); test("1e36", Ok(1e36)); test("1e37", Ok(1e37)); test("1e-39", Ok(1e-39)); test("1e-5", Ok(1e-5)); test("2e0", Ok(2.0)); test("22250738585072011e-324", Ok(2.225073858507201e-308)); test("2e1", Ok(20.0)); test("2e2", Ok(200.0)); test("2e-1", Ok(2e-1)); test("2e-2", Ok(2e-2)); test("2e20", Ok(2e20)); test("2e-20", Ok(2e-20)); test("2e22", Ok(2e22)); test("2e-22", Ok(2e-22)); test("2e23", Ok(2e23)); test("2e-23", Ok(2e-23)); test("2e-25", Ok(2e-25)); test("2e35", Ok(2e35)); test("2e36", Ok(2e36)); test("2e37", Ok(2e37)); test("2e-39", Ok(2e-39)); test("2e-5", Ok(2e-5)); test("358416272e-33", Ok(358416272e-33)); test("00000030000e-328", Ok(40000e-328)); test("30000e-328", Ok(40000e-328)); test("3e-324", Ok(4e-324)); test("5445618932859895362967233318697132813618813095743952975439298223406969961560047552942717636670910728746893019786283454139917900193169748259349067524939840552682198095012176093045431437495773903922425632551857520884625114624126588173520906670968542074438852601438992904761759703022688483745081090292688986958251711580854575674815074162979705098246243690189880319928315307816832576838178256307401454285988871020923752587330172447966674453785790265533466496640456213871241930958703059911787722565044368663670643970181259143319016472430928902201239474588139233890135329130660705762320235358869874608541509790266400643191187286648422874774910682648288516244021893172769161449825765517353755844373640588822904791244190695299838293263075467057383813882521706545084301049855505888186560731e-1035", Ok(5.445618932859895e-255)); test( "5708990770823838890407843763683279797179383808e0", Ok(5708990770823838890407843763683279797179383808.0), ); test( "5708990770823839207320493820740630171355185151999e-3", Ok(5708990770823838890407843763683279797179383808.0), ); test( "5708990770823839207320493820740630171355185152001e-3", Ok(5708990770823839524233143877797980545530986496.0), ); test( "5708990770823839207320493820740630171355185152e0", Ok(5708990770823839524233143877797980545530986496.0), ); test( "5708990770823839524233143877797980545530986496e0", Ok(5708990770823839524233143877797980545530986496.0), ); test("72057594037927928e0", Ok(72057594037927928.0)); test("7205759403792793199999e-5", Ok(72057594037927928.0)); test("7205759403792793200001e-5", Ok(72057594037927936.0)); test("72057594037927932e0", Ok(72057594037927936.0)); test("72057594037927936e0", Ok(72057594037927936.0)); test("89255e-22", Ok(89255e-22)); test("9e0", Ok(9.0)); test("9e1", Ok(90.0)); test("9e2", Ok(900.0)); test("9223372036854774784e0", Ok(9223372036854774784.0)); test("922337203685477529599999e-5", Ok(9223372036854774784.0)); test("922337203685477529600001e-5", Ok(9223372036854775808.0)); test("9223372036854775296e0", Ok(9223372036854775808.0)); test("9223372036854775808e0", Ok(9223372036854775808.0)); test("9e-1", Ok(9e-1)); test("9e-2", Ok(9e-2)); test("9e20", Ok(9e20)); test("9e-20", Ok(9e-20)); test("9e22", Ok(9e22)); test("9e-22", Ok(9e-22)); test("9e23", Ok(9e23)); test("9e-23", Ok(9e-23)); test("9e-25", Ok(9e-25)); test("9e35", Ok(9e35)); test("9e36", Ok(9e36)); test("9e37", Ok(9e37)); test("9e-39", Ok(9e-39)); test("9e-5", Ok(9e-5)); test("00000000180000000e300", Err(Error::Overflow)); test("0000000018e307", Err(Error::Overflow)); test("00000001000000e303", Err(Error::Overflow)); test("0000001e309", Err(Error::Overflow)); test("1000000e303", Err(Error::Overflow)); test("17976931348623159e292", Err(Error::Overflow)); test("180000000e300", Err(Error::Overflow)); test("18e307", Err(Error::Overflow)); test("1e309", Err(Error::Overflow)); test("1e-409", Ok(0.0)); test_sep("1,1e1", Ok(1.1e1), ','); test_consumed("12345e37randomstuff", Ok(12345e37), 8); } fn test(input: &str, val: Result) { test_sep(input, val, '.') } fn test_sep(input: &str, val: Result, decimalsep: char) { let mut consumed = 0; let result = wcstod(input, decimalsep, &mut consumed); assert_eq!(result, val); if result.is_ok() { assert_eq!(consumed, input.chars().count()); assert_eq!( result.unwrap().is_sign_positive(), val.unwrap().is_sign_positive() ); } } fn test_consumed(input: &str, val: Result, exp_consumed: usize) { let mut consumed = 0; let result = wcstod(input, '.', &mut consumed); assert_eq!(result, val); assert_eq!(consumed, exp_consumed); } }