use crate::errors::syntax_error;
use crate::errors::ParseResult;
use crate::numbers::Radix;
use crate::parse_from_string;
use crate::ParserCore;
use std::fmt::Debug;
use super::binary_float::parse_binary_float;
use super::decimal_float::parse_decimal_float;
use super::hexadecimal_float::parse_hexadecimal_float;
use super::octal_float::parse_octal_float;
#[derive(Debug, Clone)]
pub enum Sign {
Negative,
None,
Positive,
}
#[derive(Debug, Clone)]
pub struct NumberParts {
pub radix: Radix,
pub sign: Sign,
pub is_nan: bool,
pub is_inf: bool,
pub whole: String,
pub fraction: Option<String>,
pub exponent_sign: Option<Sign>,
pub exponent: Option<String>,
}
impl NumberParts {
pub fn is_apparent_float(&self) -> bool {
self.fraction.is_some() || self.exponent.is_some() || self.is_inf || self.is_nan
}
pub fn as_string(&self, include_radix: bool) -> String {
let mut result = String::new();
if let Sign::Negative = self.sign {
result.push('-')
}
if self.is_nan {
result.push_str("nan");
return result;
}
if self.is_inf {
result.push_str("inf");
return result;
}
if include_radix {
result.push_str(&self.radix.as_prefix());
}
result.push_str(&self.whole);
if let Some(ref digits) = self.fraction {
result.push('.');
result.push_str(digits);
}
if let Some(ref digits) = self.exponent {
if self.radix == Radix::Hexadecimal {
result.push('p');
} else {
result.push('e');
}
if let Some(Sign::Negative) = self.exponent_sign {
result.push('-');
}
result.push_str(digits);
}
result
}
}
impl From<u128> for NumberParts {
fn from(value: u128) -> Self {
Self {
radix: Radix::Decimal,
sign: Sign::None,
is_nan: false,
is_inf: false,
whole: value.to_string(),
fraction: None,
exponent_sign: None,
exponent: None,
}
}
}
impl From<i128> for NumberParts {
fn from(value: i128) -> Self {
let (sign, value) = if value < 0 {
(Sign::Negative, -value)
} else {
(Sign::None, value)
};
Self {
radix: Radix::Decimal,
sign,
is_nan: false,
is_inf: false,
whole: value.to_string(),
fraction: None,
exponent_sign: None,
exponent: None,
}
}
}
impl From<u64> for NumberParts {
fn from(value: u64) -> Self {
Self {
radix: Radix::Decimal,
sign: Sign::None,
is_nan: false,
is_inf: false,
whole: value.to_string(),
fraction: None,
exponent_sign: None,
exponent: None,
}
}
}
impl From<i64> for NumberParts {
fn from(value: i64) -> Self {
let (sign, value) = if value < 0 {
(Sign::Negative, -value)
} else {
(Sign::None, value)
};
Self {
radix: Radix::Decimal,
sign,
is_nan: false,
is_inf: false,
whole: value.to_string(),
fraction: None,
exponent_sign: None,
exponent: None,
}
}
}
impl From<f64> for NumberParts {
fn from(value: f64) -> Self {
if f64::is_nan(value) {
return Self {
radix: Radix::Decimal,
sign: Sign::None,
is_nan: true,
is_inf: false,
whole: "".into(),
fraction: None,
exponent_sign: None,
exponent: None,
};
}
let (sign, value) = if value < 0.0 {
(Sign::Negative, -value)
} else {
(Sign::None, value)
};
if value == f64::INFINITY {
return Self {
radix: Radix::Decimal,
sign,
is_nan: false,
is_inf: true,
whole: "".into(),
fraction: None,
exponent_sign: None,
exponent: None,
};
}
let sci = format!("{:e}", value);
let parts: Vec<&str> = sci.split('e').collect();
let mantissa = parts[0];
let exponent = parts[1];
let (exponent_sign, exponent) = if let Some(body) = exponent.strip_prefix('-') {
(Sign::Negative, body)
} else {
(Sign::None, exponent)
};
let mantissa_parts: Vec<&str> = mantissa.split('.').collect();
let whole = mantissa_parts[0].to_string();
let fraction = mantissa_parts.get(1).unwrap_or(&"0").to_string();
Self {
radix: Radix::Decimal,
sign,
is_nan: false,
is_inf: false,
whole,
fraction: if fraction.is_empty() {
None
} else {
Some(fraction)
},
exponent_sign: Some(exponent_sign),
exponent: Some(exponent.into()),
}
}
}
impl From<NumberParts> for i64 {
fn from(np: NumberParts) -> Self {
if np.whole.is_empty() {
0
} else {
let value = i64::from_str_radix(&np.whole, np.radix.value()).unwrap_or(0);
if let Sign::Negative = np.sign {
-value
} else {
value
}
}
}
}
impl From<NumberParts> for i128 {
fn from(np: NumberParts) -> Self {
if np.whole.is_empty() {
0
} else {
let value = i128::from_str_radix(&np.whole, np.radix.value()).unwrap_or(0);
if let Sign::Negative = np.sign {
-value
} else {
value
}
}
}
}
impl From<NumberParts> for f64 {
fn from(np: NumberParts) -> Self {
if np.is_nan {
return f64::NAN;
}
let mut np = np;
let negative = matches!(np.sign, Sign::Negative);
np.sign = Sign::None;
if np.is_inf {
if negative {
return f64::NEG_INFINITY;
} else {
return f64::INFINITY;
}
}
let text = np.as_string(false);
println!("{}", text);
let mut parser = parse_from_string(&text);
let core = parser.borrow_core();
let settings = &NumberParserSettings::default();
let result = match np.radix {
Radix::Binary => parse_binary_float(core, negative, settings),
Radix::Octal => parse_octal_float(core, negative, settings),
Radix::Decimal => parse_decimal_float(core, negative, settings),
Radix::Hexadecimal => parse_hexadecimal_float(core, negative, settings),
};
println!("{:?}", result);
match result {
Ok(value) => value,
Err(_) => f64::NAN,
}
}
}
#[derive(Debug, Clone)]
pub struct NumberParserSettings {
pub permit_underscores: bool,
pub permit_hexadecimal: bool,
pub permit_octal: bool,
pub permit_binary: bool,
pub permit_plus: bool,
pub hexadecimal_indicator: Vec<char>,
pub octal_indicator: Vec<char>,
pub binary_indicator: Vec<char>,
pub decimal_only_floats: bool,
pub permit_empty_whole: bool,
pub permit_empty_fraction: bool,
pub permit_leading_zero: bool,
}
impl Default for NumberParserSettings {
fn default() -> Self {
Self {
permit_binary: true,
permit_octal: true,
permit_hexadecimal: true,
binary_indicator: vec!['0', 'b'],
octal_indicator: vec!['0', 'o'],
hexadecimal_indicator: vec!['0', 'x'],
permit_plus: true,
permit_leading_zero: true,
permit_empty_whole: true,
permit_empty_fraction: true,
permit_underscores: true,
decimal_only_floats: false,
}
}
}
impl NumberParserSettings {
pub fn new() -> Self {
Self::default()
}
}
#[derive(Debug, Clone)]
pub struct NumberParser {
pub settings: NumberParserSettings,
}
impl Default for NumberParser {
fn default() -> Self {
Self::new()
}
}
impl NumberParser {
pub fn new() -> Self {
NumberParser {
settings: NumberParserSettings::new(),
}
}
pub fn get_text(&self, parser: &mut ParserCore) -> (Radix, String, bool) {
let parts = self.get_parts(parser);
(
parts.radix,
parts.as_string(false),
parts.is_apparent_float(),
)
}
pub fn get_parts(&self, parser: &mut ParserCore) -> NumberParts {
let mut text = String::new();
let sign = if parser.peek_and_consume('-') {
Sign::Negative
} else if parser.peek_and_consume('+') {
Sign::Positive
} else {
Sign::None
};
if parser.peek_and_consume_chars(&['n', 'a', 'n']) {
return NumberParts {
radix: Radix::Decimal,
sign: Sign::None,
is_inf: false,
is_nan: true,
whole: String::from(""),
fraction: None,
exponent_sign: None,
exponent: None,
};
}
if parser.peek_and_consume_chars(&['i', 'n', 'f']) {
let _ = parser.peek_and_consume_chars(&['i', 'n', 'i', 't', 'y']);
return NumberParts {
radix: Radix::Decimal,
sign,
is_inf: true,
is_nan: false,
whole: String::from(""),
fraction: None,
exponent_sign: None,
exponent: None,
};
}
let radix = self.get_radix(parser);
let exponent_marker = if radix == Radix::Hexadecimal {
vec!['p', 'P']
} else if self.settings.permit_hexadecimal {
vec!['e', 'E', 'p', 'P']
} else {
vec!['e', 'E']
};
let (whole_vec, mut last) = if self.settings.permit_underscores {
parser.take(
|ch| ch == '_',
|ch| exponent_marker.contains(&ch) || !ch.is_alphanumeric(),
)
} else {
parser.take(
|_| false,
|ch| exponent_marker.contains(&ch) || !ch.is_alphanumeric(),
)
};
let whole = String::from_iter(whole_vec);
let mut fraction = None;
if Some('.') == last {
parser.consume();
text.push('.');
let (frac_vec, newlast) = if self.settings.permit_underscores {
parser.take(
|ch| ch == '_',
|ch| exponent_marker.contains(&ch) || !ch.is_alphanumeric(),
)
} else {
parser.take(
|_| false,
|ch| exponent_marker.contains(&ch) || !ch.is_alphanumeric(),
)
};
last = newlast;
fraction = Some(String::from_iter(frac_vec));
}
let mut exponent_sign = None;
let mut exponent = None;
if let Some(ch) = last {
if exponent_marker.contains(&ch) {
parser.consume();
text.push(exponent_marker[0]);
exponent_sign = if parser.peek_and_consume('-') {
Some(Sign::Negative)
} else if parser.peek_and_consume('+') {
Some(Sign::Positive)
} else {
Some(Sign::None)
};
exponent = Some(if self.settings.permit_underscores {
parser.take_while_unless(|ch| ch.is_alphanumeric(), |ch| ch == '_')
} else {
parser.take_while(|ch| ch.is_alphanumeric())
});
}
}
NumberParts {
radix,
sign,
is_inf: false,
is_nan: false,
whole,
fraction,
exponent_sign,
exponent,
}
}
fn get_radix(&self, parser: &mut ParserCore) -> Radix {
if self.settings.permit_hexadecimal
&& parser.peek_and_consume_chars(&self.settings.hexadecimal_indicator)
{
Radix::Hexadecimal
} else if self.settings.permit_octal
&& parser.peek_and_consume_chars(&self.settings.octal_indicator)
{
Radix::Octal
} else if self.settings.permit_binary
&& parser.peek_and_consume_chars(&self.settings.binary_indicator)
{
Radix::Binary
} else {
Radix::Decimal
}
}
pub fn parse_f64(&self, parser: &mut ParserCore) -> ParseResult<f64> {
let negative = parser.peek_and_consume('-');
if !negative {
parser.peek_and_consume('+');
}
if parser.peek_and_consume_chars(&['i', 'n', 'f']) {
let _ = parser.peek_and_consume_chars(&['i', 'n', 'i', 't', 'y']);
if negative {
return Ok(f64::NEG_INFINITY);
}
return Ok(f64::INFINITY);
}
if parser.peek_and_consume_chars(&['n', 'a', 'n']) {
return Ok(f64::NAN);
}
let radix = self.get_radix(parser);
match radix {
Radix::Binary => parse_binary_float(parser, negative, &self.settings),
Radix::Hexadecimal => parse_hexadecimal_float(parser, negative, &self.settings),
Radix::Octal => parse_octal_float(parser, negative, &self.settings),
_ => parse_decimal_float(parser, negative, &self.settings),
}
}
fn parse_i128_body(
&self,
parser: &mut ParserCore,
negative: bool,
radix: Radix,
) -> ParseResult<i128> {
let mut digits = false;
let mut nonzero_pending = true;
let mut value = 0i128;
let mut fail_mul;
let mut fail_add;
let mut fail = false;
let accumulate = if negative {
i128::overflowing_sub
} else {
i128::overflowing_add
};
let base = radix.value();
while !parser.is_at_eof() {
let ch = parser.peek();
if self.settings.permit_underscores && ch == '_' {
parser.consume();
continue;
}
let mut dig = ch as u32;
if (0x30..=0x39).contains(&dig) {
dig -= 0x30;
} else if (0x41..0x5B).contains(&(dig & 0xdf)) {
dig = (dig & 0xdf) - 0x37;
} else {
break;
}
digits = true;
if dig >= base {
return Err(syntax_error(
parser.loc(),
&format!("The digit '{}' is invalid for base {}.", ch, base),
));
}
parser.consume();
if nonzero_pending {
if dig > 0 {
if negative {
value = -(dig as i128);
} else {
value = dig as i128;
}
nonzero_pending = false;
}
} else {
(value, fail_mul) = value.overflowing_mul(base as i128);
(value, fail_add) = accumulate(value, dig as i128);
fail = fail || fail_mul || fail_add;
}
}
if fail {
return Err(syntax_error(
parser.loc(),
"Integer value out of bounds for i64",
));
}
if !digits {
return Err(syntax_error(
parser.loc(),
"Expected a number but found no valid digits.",
));
}
Ok(value)
}
fn parse_u128_body(&self, parser: &mut ParserCore, radix: Radix) -> ParseResult<u128> {
let mut digits = false;
let mut nonzero_pending = true;
let mut value = 0u128;
let mut fail_mul;
let mut fail_add;
let mut fail = false;
let base = radix.value();
while !parser.is_at_eof() {
let ch = parser.peek();
if self.settings.permit_underscores && ch == '_' {
parser.consume();
continue;
}
let mut dig = ch as u32;
if (0x30..=0x39).contains(&dig) {
dig -= 0x30;
} else if (0x41..0x5B).contains(&(dig & 0xdf)) {
dig = (dig & 0xdf) - 0x37;
} else {
break;
}
digits = true;
if dig >= base {
return Err(syntax_error(
parser.loc(),
&format!("The digit '{}' is invalid for base {}.", ch, base),
));
}
parser.consume();
if nonzero_pending {
if dig > 0 {
value = dig as u128;
nonzero_pending = false;
}
} else {
(value, fail_mul) = value.overflowing_mul(base as u128);
(value, fail_add) = value.overflowing_add(dig as u128);
fail = fail || fail_mul || fail_add;
}
}
if fail {
return Err(syntax_error(
parser.loc(),
"Integer value too large for u64",
));
}
if !digits {
return Err(syntax_error(
parser.loc(),
"Expected a number but found no valid digits",
));
}
Ok(value)
}
fn parse_i64_body(
&self,
parser: &mut ParserCore,
negative: bool,
radix: Radix,
) -> ParseResult<i64> {
let mut digits = false;
let mut nonzero_pending = true;
let mut value = 0i64;
let mut fail_mul;
let mut fail_add;
let mut fail = false;
let accumulate = if negative {
i64::overflowing_sub
} else {
i64::overflowing_add
};
let base = radix.value();
while !parser.is_at_eof() {
let ch = parser.peek();
if self.settings.permit_underscores && ch == '_' {
parser.consume();
continue;
}
let mut dig = ch as u32;
if (0x30..=0x39).contains(&dig) {
dig -= 0x30;
} else if (0x41..0x5B).contains(&(dig & 0xdf)) {
dig = (dig & 0xdf) - 0x37;
} else {
break;
}
digits = true;
if dig >= base {
return Err(syntax_error(
parser.loc(),
&format!("The digit '{}' is invalid for base {}.", ch, base),
));
}
parser.consume();
if nonzero_pending {
if dig > 0 {
if negative {
value = -(dig as i64);
} else {
value = dig as i64;
}
nonzero_pending = false;
}
} else {
(value, fail_mul) = value.overflowing_mul(base as i64);
(value, fail_add) = accumulate(value, dig as i64);
fail = fail || fail_mul || fail_add;
}
}
if fail {
return Err(syntax_error(
parser.loc(),
"Integer value out of bounds for i64",
));
}
if !digits {
return Err(syntax_error(
parser.loc(),
"Expected a number but found no valid digits.",
));
}
Ok(value)
}
fn parse_u64_body(&self, parser: &mut ParserCore, radix: Radix) -> ParseResult<u64> {
let mut digits = false;
let mut nonzero_pending = true;
let mut value = 0u64;
let mut fail_mul;
let mut fail_add;
let mut fail = false;
let base = radix.value();
while !parser.is_at_eof() {
let ch = parser.peek();
if self.settings.permit_underscores && ch == '_' {
parser.consume();
continue;
}
let mut dig = ch as u32;
if (0x30..=0x39).contains(&dig) {
dig -= 0x30;
} else if (0x41..0x5B).contains(&(dig & 0xdf)) {
dig = (dig & 0xdf) - 0x37;
} else {
break;
}
digits = true;
if dig >= base {
return Err(syntax_error(
parser.loc(),
&format!("The digit '{}' is invalid for base {}.", ch, base),
));
}
parser.consume();
if nonzero_pending {
if dig > 0 {
value = dig as u64;
nonzero_pending = false;
}
} else {
(value, fail_mul) = value.overflowing_mul(base as u64);
(value, fail_add) = value.overflowing_add(dig as u64);
fail = fail || fail_mul || fail_add;
}
}
if fail {
return Err(syntax_error(
parser.loc(),
"Integer value too large for u64",
));
}
if !digits {
return Err(syntax_error(
parser.loc(),
"Expected a number but found no valid digits",
));
}
Ok(value)
}
pub fn parse_f64_decimal(&self, parser: &mut ParserCore) -> ParseResult<f64> {
let negative = parser.peek_and_consume('-');
if !negative {
parser.peek_and_consume('+');
}
parse_decimal_float(parser, negative, &self.settings)
}
pub fn parse_i128(&self, parser: &mut ParserCore) -> ParseResult<i128> {
let negative = parser.peek_and_consume('-');
if !negative {
parser.peek_and_consume('+');
}
let radix = self.get_radix(parser);
self.parse_i128_body(parser, negative, radix)
}
pub fn parse_u128(&self, parser: &mut ParserCore) -> ParseResult<u128> {
let radix = self.get_radix(parser);
self.parse_u128_body(parser, radix)
}
pub fn parse_i64(&self, parser: &mut ParserCore) -> ParseResult<i64> {
let negative = parser.peek_and_consume('-');
if !negative {
parser.peek_and_consume('+');
}
let radix = self.get_radix(parser);
self.parse_i64_body(parser, negative, radix)
}
pub fn parse_u64(&self, parser: &mut ParserCore) -> ParseResult<u64> {
let radix = self.get_radix(parser);
self.parse_u64_body(parser, radix)
}
pub fn parse_i128_radix(&self, parser: &mut ParserCore, radix: Radix) -> ParseResult<i128> {
let negative = parser.peek_and_consume('-');
if !negative {
parser.peek_and_consume('+');
}
self.parse_i128_body(parser, negative, radix)
}
pub fn parse_u128_radix(&self, parser: &mut ParserCore, radix: Radix) -> ParseResult<u128> {
self.parse_u128_body(parser, radix)
}
pub fn parse_i64_radix(&self, parser: &mut ParserCore, radix: Radix) -> ParseResult<i64> {
let negative = parser.peek_and_consume('-');
if !negative {
parser.peek_and_consume('+');
}
self.parse_i64_body(parser, negative, radix)
}
pub fn parse_u64_radix(&self, parser: &mut ParserCore, radix: Radix) -> ParseResult<u64> {
self.parse_u64_body(parser, radix)
}
}
#[cfg(test)]
mod tests {
use core::f64;
use crate::{
errors::ParseResult,
numbers::{NumberParser, Radix},
parse_from_string,
};
use super::{NumberParts, Sign};
#[test]
fn each() {
let numpar = NumberParser::new();
let mut parser = parse_from_string("-7563");
assert_eq!(numpar.parse_i128(parser.borrow_core()).unwrap(), -7563);
}
#[test]
fn get_text_test() -> ParseResult<()> {
let source = r#"
0
0.0
-0
-0.0
+0
+0.0
0x0
0o0
0b0
0x76_5afe
0b01_0010
0o14_234
+0x01_24ffp12
+12e-14
1_123_232e-74
1_123_998E+21
__1_123_543__P-__12__
0xfe
nan
inf
+inf
-inf
infinity
"#;
let result = &[
(Radix::Decimal, "0".to_string(), false),
(Radix::Decimal, "0.0".to_string(), true),
(Radix::Decimal, "-0".to_string(), false),
(Radix::Decimal, "-0.0".to_string(), true),
(Radix::Decimal, "0".to_string(), false),
(Radix::Decimal, "0.0".to_string(), true),
(Radix::Hexadecimal, "0".to_string(), false),
(Radix::Octal, "0".to_string(), false),
(Radix::Binary, "0".to_string(), false),
(Radix::Hexadecimal, "765afe".to_string(), false),
(Radix::Binary, "010010".to_string(), false),
(Radix::Octal, "14234".to_string(), false),
(Radix::Hexadecimal, "0124ffp12".to_string(), true),
(Radix::Decimal, "12e-14".to_string(), true),
(Radix::Decimal, "1123232e-74".to_string(), true),
(Radix::Decimal, "1123998e21".to_string(), true),
(Radix::Decimal, "1123543e-12".to_string(), true),
(Radix::Hexadecimal, "fe".to_string(), false),
(Radix::Decimal, "nan".to_string(), true),
(Radix::Decimal, "inf".to_string(), true),
(Radix::Decimal, "inf".to_string(), true),
(Radix::Decimal, "-inf".to_string(), true),
(Radix::Decimal, "inf".to_string(), true),
];
let mut parser = parse_from_string(source);
let np = NumberParser::new();
let mut index = 0;
parser.consume_ws();
loop {
if parser.is_at_eof() {
break;
}
print!("Trying {:?}... ", result[index]);
assert_eq!(result[index], np.get_text(parser.borrow_core()));
println!("Done");
parser.consume_ws();
index += 1;
}
Ok(())
}
#[test]
fn get_text_no_underscores_test() -> ParseResult<()> {
let source = r#"
0
0.0
-0
-0.0
+0
+0.0
0x0
0o0
0b0
0x765afe
0b010010
0o14234
+0x0124ffp12
+12e-14
1123232e-74
1123998E+21
1123543P-12
0xfe
"#;
let result = &[
(Radix::Decimal, "0".to_string(), false),
(Radix::Decimal, "0.0".to_string(), true),
(Radix::Decimal, "-0".to_string(), false),
(Radix::Decimal, "-0.0".to_string(), true),
(Radix::Decimal, "0".to_string(), false),
(Radix::Decimal, "0.0".to_string(), true),
(Radix::Hexadecimal, "0".to_string(), false),
(Radix::Octal, "0".to_string(), false),
(Radix::Binary, "0".to_string(), false),
(Radix::Hexadecimal, "765afe".to_string(), false),
(Radix::Binary, "010010".to_string(), false),
(Radix::Octal, "14234".to_string(), false),
(Radix::Hexadecimal, "0124ffp12".to_string(), true),
(Radix::Decimal, "12e-14".to_string(), true),
(Radix::Decimal, "1123232e-74".to_string(), true),
(Radix::Decimal, "1123998e21".to_string(), true),
(Radix::Decimal, "1123543e-12".to_string(), true),
(Radix::Hexadecimal, "fe".to_string(), false),
];
let mut parser = parse_from_string(source);
let mut np = NumberParser::new();
np.settings.permit_underscores = false;
let mut index = 0;
parser.consume_ws();
loop {
if parser.is_at_eof() {
break;
}
print!("Trying {:?}... ", result[index]);
assert_eq!(result[index], np.get_text(parser.borrow_core()));
println!("Done");
parser.consume_ws();
index += 1;
}
Ok(())
}
#[test]
fn get_text_no_hexadecimal_test() -> ParseResult<()> {
let source = r#"
0
0.0
-0
-0.0
+0
+0.0
0o0
0b0
0b010010
0o14234
+12e-14
1123232e-74
1123998E+21
"#;
let result = &[
(Radix::Decimal, "0".to_string(), false),
(Radix::Decimal, "0.0".to_string(), true),
(Radix::Decimal, "-0".to_string(), false),
(Radix::Decimal, "-0.0".to_string(), true),
(Radix::Decimal, "0".to_string(), false),
(Radix::Decimal, "0.0".to_string(), true),
(Radix::Octal, "0".to_string(), false),
(Radix::Binary, "0".to_string(), false),
(Radix::Binary, "010010".to_string(), false),
(Radix::Octal, "14234".to_string(), false),
(Radix::Decimal, "12e-14".to_string(), true),
(Radix::Decimal, "1123232e-74".to_string(), true),
(Radix::Decimal, "1123998e21".to_string(), true),
];
let mut parser = parse_from_string(source);
let mut np = NumberParser::new();
np.settings.permit_hexadecimal = false;
let mut index = 0;
parser.consume_ws();
loop {
if parser.is_at_eof() {
break;
}
print!("Trying {:?}... ", result[index]);
assert_eq!(result[index], np.get_text(parser.borrow_core()));
println!("Done");
parser.consume_ws();
index += 1;
}
Ok(())
}
#[test]
fn number_parts_test() {
let mut parts = NumberParts {
radix: Radix::Decimal,
sign: Sign::Negative,
is_nan: true,
is_inf: false,
whole: "16383".to_string(),
fraction: Some("525".to_string()),
exponent_sign: Some(Sign::Negative),
exponent: Some("2".to_string()),
};
assert_eq!(parts.as_string(true), "-nan");
parts.sign = Sign::Positive;
assert_eq!(parts.as_string(true), "nan");
parts.is_nan = false;
parts.is_inf = true;
assert_eq!(parts.as_string(true), "inf");
parts.sign = Sign::Negative;
assert_eq!(parts.as_string(true), "-inf");
parts.is_inf = false;
assert_eq!(parts.as_string(true), "-16383.525e-2");
parts.radix = Radix::Hexadecimal;
assert_eq!(parts.as_string(false), "-16383.525p-2");
assert_eq!(parts.as_string(true), "-0x16383.525p-2");
parts.exponent_sign = Some(Sign::Positive);
assert_eq!(parts.as_string(true), "-0x16383.525p2");
}
#[test]
fn conversions_test() {
let np: NumberParts = 65536000_u128.into();
assert_eq!(65536000_i128, np.into());
let np: NumberParts = 65536000_u64.into();
assert_eq!(65536000_i64, np.into());
let value = -6976363876985763_i64;
let np: NumberParts = value.into();
assert_eq!(-6976363876985763_i64, np.into());
let value = -6976363876985763000_i128;
let np: NumberParts = value.into();
assert_eq!(-6976363876985763000_i128, np.into());
let value = 6976363876985763_i64;
let np: NumberParts = value.into();
assert_eq!(6976363876985763_i64, np.into());
let value = 6976363876985763000_i128;
let np: NumberParts = value.into();
assert_eq!(6976363876985763000_i128, np.into());
let nan = f64::NAN;
let pinf = f64::INFINITY;
let ninf = f64::NEG_INFINITY;
let np: NumberParts = nan.into();
let back: f64 = np.into();
assert!(back.is_nan());
let np: NumberParts = pinf.into();
assert_eq!(f64::INFINITY, np.into());
let np: NumberParts = ninf.into();
assert_eq!(f64::NEG_INFINITY, np.into());
let np: NumberParts = 0.0_f64.into();
assert_eq!(0.0_f64, np.into());
let np: NumberParts = 15_f64.into();
assert_eq!(15_f64, np.into());
let np: NumberParts = 0.000021_f64.into();
assert_eq!(0.000021_f64, np.into());
let np: NumberParts = 81.743e16_f64.into();
assert_eq!(81.743e16_f64, np.into());
let value = -81.743e16_f64;
let np: NumberParts = value.into();
assert_eq!(value, np.into());
let value = -81.743e-16_f64;
let np: NumberParts = value.into();
assert_eq!(value, np.into());
let np = NumberParts {
radix: Radix::Binary,
sign: Sign::Negative,
is_nan: false,
is_inf: false,
whole: "10100110".into(),
fraction: Some("1".into()),
exponent_sign: Some(Sign::Positive),
exponent: Some("1".into()),
};
assert_eq!(-333.0, np.into());
let np = NumberParts {
radix: Radix::Octal,
sign: Sign::Positive,
is_nan: false,
is_inf: false,
whole: "0".into(),
fraction: Some("3404".into()),
exponent_sign: Some(Sign::Positive),
exponent: Some("3".into()),
};
assert_eq!(224.5, np.into());
let np = NumberParts {
radix: Radix::Hexadecimal,
sign: Sign::Negative,
is_nan: false,
is_inf: false,
whole: "1e4".into(),
fraction: Some("2".into()),
exponent_sign: Some(Sign::Negative),
exponent: Some("2".into()),
};
assert_eq!(
-(256.0 + 14.0 * 16.0 + 4.0 + 2.0 / 16.0) / 16.0 / 16.0,
np.into()
);
let np = NumberParts {
radix: Radix::Octal,
sign: Sign::Positive,
is_nan: false,
is_inf: false,
whole: "0".into(),
fraction: Some("384".into()),
exponent_sign: Some(Sign::Positive),
exponent: Some("3".into()),
};
let value: f64 = np.into();
assert!(value.is_nan());
let np = NumberParts {
radix: Radix::Octal,
sign: Sign::Positive,
is_nan: false,
is_inf: false,
whole: "".into(),
fraction: None,
exponent_sign: None,
exponent: None,
};
let value: i64 = np.clone().into();
assert_eq!(0, value);
let value: i128 = np.into();
assert_eq!(0, value);
}
}