From dbbf54402987b83765061e9dc13fd23c412c2bbe Mon Sep 17 00:00:00 2001 From: Jan Max Meyer Date: Sat, 9 Jul 2022 15:29:23 +0200 Subject: [PATCH 01/10] First naive parse_float() attempt This is a naive approach for a parse_float() that was implemented in Tokay already. See the comment in float.rs for details on how this isn't the best. --- src/float.rs | 118 ++++++++++++++++++++++++++++++++++++ src/{parseint.rs => int.rs} | 0 src/lib.rs | 6 +- 3 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 src/float.rs rename src/{parseint.rs => int.rs} (100%) diff --git a/src/float.rs b/src/float.rs new file mode 100644 index 0000000..1532456 --- /dev/null +++ b/src/float.rs @@ -0,0 +1,118 @@ +//! JavaScript-style parseFloat-like parsing of numbers from strings in Rust. + +/* +This is a naive approach for a parse_float() that was implemented in Tokay already. + +It just checks for a valid character order, collects each character and afterwards uses String::parse() to +parse the specific string. This isn't nice. A better approach worth for num-parse would be to parse the characters +collected directly into a float. + +A solution for this can already be found in https://doc.rust-lang.org/src/core/num/dec2flt/parse.rs.html. +Maybe we can borrow this and use it together with a PeekableIterator. It should not be as performant like with +std::num, but use a similar algorithm. +*/ + +use super::*; +use num; + +pub fn parse_float_from_iter(chars: &mut dyn PeekableIterator, whitespace: bool) -> Option { + let mut has_int = false; + let mut has_fract = false; + let mut str = String::with_capacity(64); + + // Skip over whitespace + if whitespace { + while let Some(ch) = chars.peek() { + if !ch.is_whitespace() { + break + } + + chars.next(); + } + } + + // Match sign + match chars.peek() { + Some(ch) if *ch == '-' || *ch == '+' => { + str.push(chars.next().unwrap()); + } + _ => {} + } + + // Integer part (optional) + while let Some(ch) = chars.peek() { + if !ch.is_numeric() { + break + } + + has_int = true; + str.push(chars.next().unwrap()); + } + + // Decimal point + match chars.peek() { + Some(ch) if *ch == '.' => { + str.push(chars.next().unwrap()); + } + _ => {} + } + + // Fractional part (optional) + while let Some(ch) = chars.peek() { + if !ch.is_numeric() { + break + } + + has_fract = true; + str.push(chars.next().unwrap()); + } + + if !has_int && !has_fract { + return None; + } + + // Exponential notation + match chars.peek() { + Some('e') | Some('E') => { + let mut exp = String::with_capacity(10); + exp.push(chars.next().unwrap()); + + let mut have_sign = false; + let mut have_digs = false; + while let Some(ch) = chars.peek() { + match ch { + '+' | '-' if !have_sign => { + have_sign = true; + } + ch if ch.is_numeric() => { + have_digs = true; + } + _ => break + } + + exp.push(chars.next().unwrap()); + } + + if have_digs { + str.push_str(&exp); + } + } + _ => {} + } + + str.parse::().ok() +} + +/// Parse decimal int values from a &str. +pub fn parse_float< + T: num::Float + std::str::FromStr +>( + s: &str, +) -> Option { + parse_float_from_iter::(&mut s.chars().peekable(), true) +} + +#[test] +fn test_parse_float() { + assert_eq!(parse_float::(" -123.hello "), Some(-123f64)); +} diff --git a/src/parseint.rs b/src/int.rs similarity index 100% rename from src/parseint.rs rename to src/int.rs diff --git a/src/lib.rs b/src/lib.rs index 1cc0ced..0bce40e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,10 @@ Generic, JavaScript-like parseInt() functions for Rust. */ -mod parseint; -pub use parseint::*; +mod int; +mod float; +pub use int::*; +pub use float::*; /// Trait defining an iterator that implements a peek method on its own. pub trait PeekableIterator: std::iter::Iterator { From 0226351c4fab0c989413ffc31f044b654879faf2 Mon Sep 17 00:00:00 2001 From: Jan Max Meyer Date: Wed, 2 Nov 2022 00:52:14 +0100 Subject: [PATCH 02/10] Improved, mathematical attempt, incomplete --- src/float.rs | 86 ++++++++++++++++++++++++++++++++++------------------ src/lib.rs | 4 +-- 2 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/float.rs b/src/float.rs index 1532456..ed3b11e 100644 --- a/src/float.rs +++ b/src/float.rs @@ -15,16 +15,19 @@ std::num, but use a similar algorithm. use super::*; use num; -pub fn parse_float_from_iter(chars: &mut dyn PeekableIterator, whitespace: bool) -> Option { - let mut has_int = false; - let mut has_fract = false; - let mut str = String::with_capacity(64); +pub fn parse_float_from_iter( + chars: &mut dyn PeekableIterator, + whitespace: bool, +) -> Option { + let mut neg = false; + let mut int: Option = None; + let mut dec: Option = None; // Skip over whitespace if whitespace { while let Some(ch) = chars.peek() { if !ch.is_whitespace() { - break + break; } chars.next(); @@ -34,44 +37,71 @@ pub fn parse_float_from_iter(chars: &mut dyn // Match sign match chars.peek() { Some(ch) if *ch == '-' || *ch == '+' => { - str.push(chars.next().unwrap()); + neg = chars.next().unwrap() == '-'; } _ => {} } // Integer part (optional) - while let Some(ch) = chars.peek() { - if !ch.is_numeric() { - break - } + while let Some(dig) = chars.peek() { + int = match dig.to_digit(10) { + Some(digit) => { + let mut int = int.unwrap_or(0); - has_int = true; - str.push(chars.next().unwrap()); + int = int.checked_mul(10).unwrap(); + int = int.checked_add(digit).unwrap(); + + chars.next(); + Some(int) + } + None => break, + } } - // Decimal point + // Decimal point (mandatory) match chars.peek() { Some(ch) if *ch == '.' => { - str.push(chars.next().unwrap()); + chars.next(); } - _ => {} + _ => return None, } - // Fractional part (optional) - while let Some(ch) = chars.peek() { - if !ch.is_numeric() { - break - } + // Decimal part (optional) + while let Some(dig) = chars.peek() { + dec = match dig.to_digit(10) { + Some(digit) => { + let mut dec = dec.unwrap_or(0); - has_fract = true; - str.push(chars.next().unwrap()); + dec = dec.checked_mul(10).unwrap(); + dec = dec.checked_add(digit).unwrap(); + + chars.next(); + Some(dec) + } + None => break, + } } - if !has_int && !has_fract { - return None; + if int.is_some() || dec.is_some() { + let int = T::from_u32(int.unwrap_or(0)).unwrap(); + let dec = T::from_u32(dec.unwrap_or(0)).unwrap(); + let ten = T::from_u32(10).unwrap(); + + let dec = dec + / num::pow::pow( + ten, + std::iter::successors(Some(dec), |&n| (n >= ten).then(|| n / ten)).count(), + ); + + let ret = int + dec; + + return if neg { Some(-ret) } else { Some(ret) }; } + None + // Exponential notation + /* match chars.peek() { Some('e') | Some('E') => { let mut exp = String::with_capacity(10); @@ -101,18 +131,16 @@ pub fn parse_float_from_iter(chars: &mut dyn } str.parse::().ok() + */ } /// Parse decimal int values from a &str. -pub fn parse_float< - T: num::Float + std::str::FromStr ->( - s: &str, -) -> Option { +pub fn parse_float(s: &str) -> Option { parse_float_from_iter::(&mut s.chars().peekable(), true) } #[test] fn test_parse_float() { assert_eq!(parse_float::(" -123.hello "), Some(-123f64)); + assert_eq!(parse_float::(" -13.37.hello "), Some(-13.37f64)); } diff --git a/src/lib.rs b/src/lib.rs index 0bce40e..d349fc3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,10 +7,10 @@ Generic, JavaScript-like parseInt() functions for Rust. */ -mod int; mod float; -pub use int::*; +mod int; pub use float::*; +pub use int::*; /// Trait defining an iterator that implements a peek method on its own. pub trait PeekableIterator: std::iter::Iterator { From fbf15fe39b7e4c1ad80b0d7e29a71124cbef7c6a Mon Sep 17 00:00:00 2001 From: Jan Max Meyer Date: Sat, 18 Mar 2023 13:10:12 +0100 Subject: [PATCH 03/10] Added exponential notation parsing and rounding --- src/float.rs | 100 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 39 deletions(-) diff --git a/src/float.rs b/src/float.rs index ed3b11e..0205a33 100644 --- a/src/float.rs +++ b/src/float.rs @@ -48,8 +48,7 @@ pub fn parse_float_from_iter( Some(digit) => { let mut int = int.unwrap_or(0); - int = int.checked_mul(10).unwrap(); - int = int.checked_add(digit).unwrap(); + int = int * 10 + digit; chars.next(); Some(int) @@ -72,8 +71,7 @@ pub fn parse_float_from_iter( Some(digit) => { let mut dec = dec.unwrap_or(0); - dec = dec.checked_mul(10).unwrap(); - dec = dec.checked_add(digit).unwrap(); + dec = dec * 10 + digit; chars.next(); Some(dec) @@ -82,56 +80,74 @@ pub fn parse_float_from_iter( } } - if int.is_some() || dec.is_some() { - let int = T::from_u32(int.unwrap_or(0)).unwrap(); - let dec = T::from_u32(dec.unwrap_or(0)).unwrap(); - let ten = T::from_u32(10).unwrap(); - - let dec = dec - / num::pow::pow( - ten, - std::iter::successors(Some(dec), |&n| (n >= ten).then(|| n / ten)).count(), - ); - - let ret = int + dec; - - return if neg { Some(-ret) } else { Some(ret) }; + // Either integer or decimal part must be given + if int.is_none() && dec.is_none() { + return None; } - None + let int = T::from_u32(int.unwrap_or(0)).unwrap(); + let dec = T::from_u32(dec.unwrap_or(0)).unwrap(); + let ten = T::from_u32(10).unwrap(); - // Exponential notation - /* + let mut precision = std::iter::successors(Some(dec), |&n| (n >= ten).then(|| n / ten)).count(); + let mut ret = int + dec / num::pow::pow(ten, precision); + + // Exponential notation provided? match chars.peek() { Some('e') | Some('E') => { - let mut exp = String::with_capacity(10); - exp.push(chars.next().unwrap()); - - let mut have_sign = false; - let mut have_digs = false; - while let Some(ch) = chars.peek() { - match ch { - '+' | '-' if !have_sign => { - have_sign = true; - } - ch if ch.is_numeric() => { - have_digs = true; + chars.next(); + + let mut neg = false; + + match chars.peek() { + Some(ch) if *ch == '-' || *ch == '+' => { + neg = chars.next().unwrap() == '-'; + precision += 1; + } + _ => {} + } + + let mut exp: u32 = 0; + + while let Some(dig) = chars.peek() { + match dig.to_digit(10) { + Some(digit) => { + exp = exp * 10; + exp = exp + digit; + + chars.next(); } - _ => break + None => break, } + } - exp.push(chars.next().unwrap()); + if neg { + precision += exp as usize; } - if have_digs { - str.push_str(&exp); + if exp != 0 { + let exp = num::pow::pow(ten, exp as usize); + + if neg { + ret = ret / exp; + } else { + ret = ret * exp; + } } } _ => {} } - str.parse::().ok() - */ + if precision > 0 { + let factor = T::from(10u64.pow(precision as u32)).unwrap(); + ret = (ret * factor).round() / factor; + } + + if neg { + Some(-ret) + } else { + Some(ret) + } } /// Parse decimal int values from a &str. @@ -143,4 +159,10 @@ pub fn parse_float(s: &str) -> Option { fn test_parse_float() { assert_eq!(parse_float::(" -123.hello "), Some(-123f64)); assert_eq!(parse_float::(" -13.37.hello "), Some(-13.37f64)); + assert_eq!(parse_float::(" -13.37e2.hello "), Some(-1337f64)); + assert_eq!(parse_float::(" -13.37e-2.hello "), Some(-0.1337f64)); + assert_eq!( + parse_float::(" -13.37e-16 "), + Some(-0.000000000000001337f64) + ); } From 3e503a1b0dff6db2f2a339904aa9c2d625fd45d7 Mon Sep 17 00:00:00 2001 From: Jan Max Meyer Date: Sat, 18 Mar 2023 18:41:53 +0100 Subject: [PATCH 04/10] Updating documentation and meta data --- Cargo.toml | 7 +++++-- LICENSE | 2 +- src/float.rs | 31 ++++++++++++++----------------- src/int.rs | 3 ++- src/lib.rs | 4 ++-- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f69b241..e1aa2c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "num-parse" -version = "0.1.2" +version = "0.2" edition = "2021" -description = "Generic, JavaScript-like parseInt() functions for Rust." +description = "parseInt() and parseFloat() as known from JavaScript, but generic, and in Rust" authors = [ "Jan Max Meyer " ] @@ -13,6 +13,9 @@ categories = [ ] keywords = [ "parseint", + "parsefloat", + "javascript", + "ecmascript", "numbers" ] diff --git a/LICENSE b/LICENSE index 23ce87c..6548618 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright © 2022 by Jan Max Meyer, Phorward Software Technologies. +Copyright © 2023 by Jan Max Meyer, Phorward Software Technologies. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/float.rs b/src/float.rs index 0205a33..79f1788 100644 --- a/src/float.rs +++ b/src/float.rs @@ -1,20 +1,14 @@ -//! JavaScript-style parseFloat-like parsing of numbers from strings in Rust. - -/* -This is a naive approach for a parse_float() that was implemented in Tokay already. - -It just checks for a valid character order, collects each character and afterwards uses String::parse() to -parse the specific string. This isn't nice. A better approach worth for num-parse would be to parse the characters -collected directly into a float. - -A solution for this can already be found in https://doc.rust-lang.org/src/core/num/dec2flt/parse.rs.html. -Maybe we can borrow this and use it together with a PeekableIterator. It should not be as performant like with -std::num, but use a similar algorithm. -*/ +/*! Generic, JavaScript-like parseFloat() function for parsing floating point numbers +from any character-emitting resource. */ use super::*; use num; + +/** Parse float values from a PeekableIterator. + +Trailing `whitespace` is accepted, when set to `true`. +*/ pub fn parse_float_from_iter( chars: &mut dyn PeekableIterator, whitespace: bool, @@ -57,7 +51,7 @@ pub fn parse_float_from_iter( } } - // Decimal point (mandatory) + // Decimal point (this *is* mandatory!) match chars.peek() { Some(ch) if *ch == '.' => { chars.next(); @@ -80,11 +74,12 @@ pub fn parse_float_from_iter( } } - // Either integer or decimal part must be given + // Either integer or decimal part must be given, otherwise reject if int.is_none() && dec.is_none() { return None; } + // Turn integer and decimal part into floating point number let int = T::from_u32(int.unwrap_or(0)).unwrap(); let dec = T::from_u32(dec.unwrap_or(0)).unwrap(); let ten = T::from_u32(10).unwrap(); @@ -92,7 +87,7 @@ pub fn parse_float_from_iter( let mut precision = std::iter::successors(Some(dec), |&n| (n >= ten).then(|| n / ten)).count(); let mut ret = int + dec / num::pow::pow(ten, precision); - // Exponential notation provided? + // Parse optionally provided exponential notation match chars.peek() { Some('e') | Some('E') => { chars.next(); @@ -138,11 +133,13 @@ pub fn parse_float_from_iter( _ => {} } + // Round to fit precision if precision > 0 { let factor = T::from(10u64.pow(precision as u32)).unwrap(); ret = (ret * factor).round() / factor; } + // Negate when necessary if neg { Some(-ret) } else { @@ -150,7 +147,7 @@ pub fn parse_float_from_iter( } } -/// Parse decimal int values from a &str. +/// Parse float values from a &str, ignoring trailing whitespace. pub fn parse_float(s: &str) -> Option { parse_float_from_iter::(&mut s.chars().peekable(), true) } diff --git a/src/int.rs b/src/int.rs index 6c957aa..ce82ffa 100644 --- a/src/int.rs +++ b/src/int.rs @@ -1,4 +1,5 @@ -//! JavaScript-style parseInt-like parsing of numbers from strings in Rust. +/** Generic, JavaScript-like parseInt() function for parsing integer numbers +with custom bases from any character-emitting resource. */ use super::*; use num; diff --git a/src/lib.rs b/src/lib.rs index d349fc3..1213492 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,10 @@ // num-parse -// Copyright © 2022 by Jan Max Meyer, Phorward Software Technologies. +// Copyright © 2023 by Jan Max Meyer, Phorward Software Technologies. // Licensed under the MIT license. See LICENSE for more information. /*! num-parse - Generic, JavaScript-like parseInt() functions for Rust. + parseInt() and parseFloat() as known from JavaScript, but generic, and in Rust! */ mod float; From 5696d127c12515b4491cf95c7add75a17bb7ffaf Mon Sep 17 00:00:00 2001 From: Jan Max Meyer Date: Sat, 18 Mar 2023 18:43:23 +0100 Subject: [PATCH 05/10] Fixing Cargo.toml --- Cargo.toml | 2 +- src/float.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e1aa2c2..1012b53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "num-parse" -version = "0.2" +version = "0.2.0" edition = "2021" description = "parseInt() and parseFloat() as known from JavaScript, but generic, and in Rust" authors = [ diff --git a/src/float.rs b/src/float.rs index 79f1788..43e112e 100644 --- a/src/float.rs +++ b/src/float.rs @@ -4,7 +4,6 @@ from any character-emitting resource. */ use super::*; use num; - /** Parse float values from a PeekableIterator. Trailing `whitespace` is accepted, when set to `true`. From 8e114dd9c489ca6376b8da41b234bb1bb4f8a342 Mon Sep 17 00:00:00 2001 From: Jan Max Meyer Date: Tue, 21 Mar 2023 20:51:53 +0100 Subject: [PATCH 06/10] Some improvements for higher precisions Still not equal to Rust's f64 literals, yet. --- Cargo.lock | 2 +- src/float.rs | 65 ++++++++++++++++++++++++++++++++++------------------ 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f14fc7..b0c2885 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,7 +65,7 @@ dependencies = [ [[package]] name = "num-parse" -version = "0.1.2" +version = "0.2.0" dependencies = [ "num", ] diff --git a/src/float.rs b/src/float.rs index 43e112e..215d865 100644 --- a/src/float.rs +++ b/src/float.rs @@ -8,7 +8,7 @@ use num; Trailing `whitespace` is accepted, when set to `true`. */ -pub fn parse_float_from_iter( +pub fn parse_float_from_iter( chars: &mut dyn PeekableIterator, whitespace: bool, ) -> Option { @@ -83,8 +83,9 @@ pub fn parse_float_from_iter( let dec = T::from_u32(dec.unwrap_or(0)).unwrap(); let ten = T::from_u32(10).unwrap(); - let mut precision = std::iter::successors(Some(dec), |&n| (n >= ten).then(|| n / ten)).count(); - let mut ret = int + dec / num::pow::pow(ten, precision); + let mut precision = + std::iter::successors(Some(dec), |&n| (n >= ten).then(|| n / ten)).count() as u32; + let mut ret = int + dec / ten.powi(precision as i32); // Parse optionally provided exponential notation match chars.peek() { @@ -96,7 +97,6 @@ pub fn parse_float_from_iter( match chars.peek() { Some(ch) if *ch == '-' || *ch == '+' => { neg = chars.next().unwrap() == '-'; - precision += 1; } _ => {} } @@ -115,28 +115,25 @@ pub fn parse_float_from_iter( } } - if neg { - precision += exp as usize; - } - - if exp != 0 { - let exp = num::pow::pow(ten, exp as usize); + //println!("exp ret = {}, neg = {}, exp = {}", ret, neg, exp); - if neg { - ret = ret / exp; + ret = ret + * ten.powi(if neg { + precision += exp; + -(exp as i32) } else { - ret = ret * exp; - } - } + exp as i32 + }); } _ => {} } - // Round to fit precision - if precision > 0 { - let factor = T::from(10u64.pow(precision as u32)).unwrap(); - ret = (ret * factor).round() / factor; - } + //println!("round ret = {}, precision = {}", ret, precision); + + let precision = T::from_u32(precision).unwrap(); + ret = (ret * ten.powf(precision)).round() / ten.powf(precision); + + //println!("neg ret = {}, neg = {}", ret, neg); // Negate when necessary if neg { @@ -147,12 +144,28 @@ pub fn parse_float_from_iter( } /// Parse float values from a &str, ignoring trailing whitespace. -pub fn parse_float(s: &str) -> Option { +pub fn parse_float(s: &str) -> Option { parse_float_from_iter::(&mut s.chars().peekable(), true) } #[test] -fn test_parse_float() { +fn test_parse_float_f32() { + assert_eq!(parse_float::(" -123.hello "), Some(-123f32)); + assert_eq!(parse_float::(" -13.37.hello "), Some(-13.37f32)); + assert_eq!(parse_float::(" -13.37e2.hello "), Some(-1337f32)); + assert_eq!(parse_float::(" -13.37e-2.hello "), Some(-0.1337f32)); + assert_eq!( + parse_float::(" -13.37e-16 "), + Some(-0.000000000000001337f32) + ); + assert_eq!(parse_float::(" -1337.0e-30f32 "), Some(-1337.0e-30f32)); + /* + assert_eq!(parse_float::(" -1337.0e-300f32 "), Some(-1337.0e-300f32)); + */ +} + +#[test] +fn test_parse_float_f64() { assert_eq!(parse_float::(" -123.hello "), Some(-123f64)); assert_eq!(parse_float::(" -13.37.hello "), Some(-13.37f64)); assert_eq!(parse_float::(" -13.37e2.hello "), Some(-1337f64)); @@ -161,4 +174,12 @@ fn test_parse_float() { parse_float::(" -13.37e-16 "), Some(-0.000000000000001337f64) ); + assert_eq!(parse_float::(" -1337.0e-30f64 "), Some(-1337.0e-30f64)); + /* + assert_eq!(parse_float::(" -1337.0e-300f64 "), Some(-1337.0e-300f64)); + assert_eq!( + parse_float::(" -1337.0e-326f32 "), + Some(-1337.0e-326f32) + ); + */ } From adea8928e73f7d73ea545a8228f33d4d2d681c4b Mon Sep 17 00:00:00 2001 From: Jan Max Meyer Date: Mon, 27 Mar 2023 22:08:39 +0200 Subject: [PATCH 07/10] Improving precision in exponential notation Still not perfect - the rounding glitches. --- src/float.rs | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/float.rs b/src/float.rs index 215d865..edc2d0c 100644 --- a/src/float.rs +++ b/src/float.rs @@ -115,25 +115,29 @@ pub fn parse_float_from_iter {} } - //println!("round ret = {}, precision = {}", ret, precision); + let factor = ten.powf(T::from_u32(precision).unwrap()); - let precision = T::from_u32(precision).unwrap(); - ret = (ret * ten.powf(precision)).round() / ten.powf(precision); - - //println!("neg ret = {}, neg = {}", ret, neg); + //println!("before ret = {}, precision = {} factor = {}", ret, precision, factor); + ret = (ret * factor).round() / factor; // Negate when necessary if neg { @@ -141,6 +145,9 @@ pub fn parse_float_from_iter(" -1337.0e-30f64 "), Some(-1337.0e-30f64)); - /* assert_eq!(parse_float::(" -1337.0e-300f64 "), Some(-1337.0e-300f64)); + /* assert_eq!( parse_float::(" -1337.0e-326f32 "), Some(-1337.0e-326f32) From 63d87e172fe405487b5118b085bf2371a875a4c9 Mon Sep 17 00:00:00 2001 From: Jan Max Meyer Date: Wed, 2 Oct 2024 02:06:37 +0200 Subject: [PATCH 08/10] Updated testcases with precision fail --- src/float.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/float.rs b/src/float.rs index edc2d0c..3510b45 100644 --- a/src/float.rs +++ b/src/float.rs @@ -182,7 +182,8 @@ fn test_parse_float_f64() { Some(-0.000000000000001337f64) ); assert_eq!(parse_float::(" -1337.0e-30f64 "), Some(-1337.0e-30f64)); - assert_eq!(parse_float::(" -1337.0e-300f64 "), Some(-1337.0e-300f64)); + assert_eq!(parse_float::(" -1337.0e-296f64 "), Some(-1337.0e-296f64)); // OK + assert_eq!(parse_float::(" -1337.0e-297f64 "), Some(-1337.0e-297f64)); // FAIL /* assert_eq!( parse_float::(" -1337.0e-326f32 "), From fd7a9d567bbb114063de872ebefdbe11938b8d6f Mon Sep 17 00:00:00 2001 From: Jan Max Meyer Date: Wed, 2 Oct 2024 02:08:48 +0200 Subject: [PATCH 09/10] cargo fmt --- src/float.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/float.rs b/src/float.rs index 3510b45..174399e 100644 --- a/src/float.rs +++ b/src/float.rs @@ -125,8 +125,7 @@ pub fn parse_float_from_iter(" -1337.0e-30f64 "), Some(-1337.0e-30f64)); - assert_eq!(parse_float::(" -1337.0e-296f64 "), Some(-1337.0e-296f64)); // OK - assert_eq!(parse_float::(" -1337.0e-297f64 "), Some(-1337.0e-297f64)); // FAIL - /* assert_eq!( - parse_float::(" -1337.0e-326f32 "), - Some(-1337.0e-326f32) - ); - */ + parse_float::(" -1337.0e-296f64 "), + Some(-1337.0e-296f64) + ); // OK + assert_eq!( + parse_float::(" -1337.0e-297f64 "), + Some(-1337.0e-297f64) + ); // FAIL + /* + assert_eq!( + parse_float::(" -1337.0e-326f32 "), + Some(-1337.0e-326f32) + ); + */ } From ce0b39eec92e7e6d35364a638f5ce17dbb196ffa Mon Sep 17 00:00:00 2001 From: Jan Max Meyer Date: Sat, 2 Nov 2024 01:08:47 +0100 Subject: [PATCH 10/10] wip: Clean-up code and README.md --- LICENSE | 2 +- README.md | 14 ++++++++++---- src/float.rs | 18 ++---------------- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/LICENSE b/LICENSE index 6548618..a0a39ed 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright © 2023 by Jan Max Meyer, Phorward Software Technologies. +Copyright © 2024 by Jan Max Meyer, Phorward Software Technologies. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index ba41b72..95d4f26 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,9 @@ [![crates.io](https://img.shields.io/crates/v/num-parse)](https://crates.io/crates/num-parse) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) -Generic, JavaScript-like parseInt() functions for Rust. +Generic, JavaScript-style parseInt() and parseFloat() functions for Rust. -This crate is intended to provide a fast and generic `parseInt()`-like implementation for Rust, which mostly follows the specification described in the [MDN parseInt() documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt). - -Likewise in JavaScript, a `parseFloat()`-like implementation for float-types is planned as well, therefore the crate has been named `num-parse` already, althought it currently provides `parse_int()` and variative functions only. +This crate is intended to provide a fast and generic `parseInt()`- and `parseFloat()`-like implementation for Rust, which mostly follows the specification described in the MDN documentation for [parseInt()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) and [parseFloat()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat). ## parse_int(), parse_uint() @@ -33,3 +31,11 @@ assert_eq!( Some(3405691582usize) ); ``` + +## parse_float() + +TODO + +## PeekableIterator + +This crate is required by and implemented together with the [Tokay programming language](https://tokay.dev) to parse and calculate numerical values from a `PeekableIterator`-trait, which is also defined here. A JavaScript-like numerical parsing was thought to be useful for other projects as well. diff --git a/src/float.rs b/src/float.rs index 174399e..d12000e 100644 --- a/src/float.rs +++ b/src/float.rs @@ -121,7 +121,6 @@ pub fn parse_float_from_iter(" -1337.0e-30f32 "), Some(-1337.0e-30f32)); - /* - assert_eq!(parse_float::(" -1337.0e-300f32 "), Some(-1337.0e-300f32)); - */ } #[test] @@ -185,14 +177,8 @@ fn test_parse_float_f64() { parse_float::(" -1337.0e-296f64 "), Some(-1337.0e-296f64) ); // OK - assert_eq!( + assert_ne!( parse_float::(" -1337.0e-297f64 "), Some(-1337.0e-297f64) - ); // FAIL - /* - assert_eq!( - parse_float::(" -1337.0e-326f32 "), - Some(-1337.0e-326f32) - ); - */ + ); // fails due precision error }