Add String Number Value

This commit is contained in:
Fabrice Reix 2023-11-19 17:37:49 +01:00
parent 5d8628662d
commit f3909c21cf
No known key found for this signature in database
GPG Key ID: BF5213154B2E7155
5 changed files with 113 additions and 2 deletions

View File

@ -36,7 +36,7 @@ md5 = "0.7.0"
percent-encoding = "2.3.1"
regex = "1.10.2"
serde = "1.0.193"
serde_json = "1.0.108"
serde_json = { version= "1.0.108",features = ["arbitrary_precision"] }
sha2 = "0.10.8"
url = "2.5.0"
xml-rs = { version = "0.8.19" }

View File

@ -18,6 +18,7 @@
use base64::engine::general_purpose;
use base64::Engine;
use std::str::FromStr;
use crate::runner::{Number, Value};
@ -67,6 +68,10 @@ impl Number {
Number::Float(f) => {
serde_json::Value::Number(serde_json::Number::from_f64(*f).unwrap())
}
Number::String(s) => {
let number = serde_json::Number::from_str(s).unwrap();
serde_json::Value::Number(number)
}
}
}
}

View File

@ -25,6 +25,7 @@ use std::fmt;
pub enum Number {
Float(f64),
Integer(i64),
String(String),
}
// You must implement it yourself because of the Float
@ -33,6 +34,7 @@ impl PartialEq for Number {
match (self, other) {
(Number::Float(v1), Number::Float(v2)) => (v1 - v2).abs() < f64::EPSILON,
(Number::Integer(v1), Number::Integer(v2)) => v1 == v2,
(Number::String(v1), Number::String(v2)) => v1 == v2,
_ => false,
}
}
@ -45,6 +47,7 @@ impl fmt::Display for Number {
let value = match self {
Number::Float(f) => format_float(*f),
Number::Integer(x) => x.to_string(),
Number::String(s) => s.to_string(),
};
write!(f, "{value}")
}
@ -63,6 +66,7 @@ impl Number {
match self {
Number::Float(_) => "float".to_string(),
Number::Integer(_) => "integer".to_string(),
Number::String(_) => "string".to_string(),
}
}
}
@ -86,6 +90,7 @@ impl Number {
(Number::Float(f1), Number::Float(f2)) => compare_float(*f1, *f2),
(Number::Integer(i1), Number::Float(f2)) => compare_float(*i1 as f64, *f2),
(Number::Float(f1), Number::Integer(i2)) => compare_float(*f1, *i2 as f64),
(n1, n2) => compare_number_string(&n1.to_string(), &n2.to_string()),
}
}
}
@ -100,6 +105,40 @@ fn compare_float(f1: f64, f2: f64) -> Ordering {
}
}
fn compare_number_string(n1: &str, n2: &str) -> Ordering {
let (neg1, i1, d1) = number_components(n1);
let (neg2, i2, d2) = number_components(n2);
if neg1 == neg2 {
match i1.cmp(i2) {
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
Ordering::Equal => d1.cmp(d2),
}
} else if neg1 {
Ordering::Less
} else {
Ordering::Greater
}
}
// return triple (negative, integer, decimals)
fn number_components(s: &str) -> (bool, &str, &str) {
match s.strip_prefix('-') {
None => match s.find('.') {
None => (false, s.trim_start_matches('0'), ""),
Some(index) => (
false,
&s[..index].trim_start_matches('0'),
&s[(index + 1)..].trim_end_matches('0'),
),
},
Some(s) => {
let (_, integer, decimal) = number_components(s);
(true, integer, decimal)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -110,11 +149,17 @@ mod tests {
assert_eq!(Number::Float(1.1).to_string(), "1.1".to_string());
assert_eq!(Number::from(1.0).to_string(), "1.0".to_string());
assert_eq!(Number::from(1.1).to_string(), "1.1".to_string());
assert_eq!(
Number::String("1.1".to_string()).to_string(),
"1.1".to_string()
);
assert_eq!(Number::String("1".to_string()).to_string(), "1".to_string());
}
#[test]
fn test_cmp_value() {
let integer_zero = Number::from(0);
let integer_minus_one = Number::from(-1);
let integer_one = Number::from(1);
let integer_two = Number::from(2);
let integer_max = Number::from(i64::max_value());
@ -128,12 +173,24 @@ mod tests {
let float_min = Number::from(f64::MIN);
let float_max = Number::from(f64::MAX);
let number_one = Number::String("1".to_string());
let number_two = Number::String("2".to_string());
let number_two_with_decimal = Number::String("2.0".to_string());
assert_eq!(integer_minus_one.cmp_value(&integer_zero), Ordering::Less);
assert_eq!(integer_one.cmp_value(&integer_one), Ordering::Equal);
assert_eq!(integer_one.cmp_value(&number_one), Ordering::Equal);
assert_eq!(integer_one.cmp_value(&float_one), Ordering::Equal);
assert_eq!(integer_one.cmp_value(&integer_zero), Ordering::Greater);
assert_eq!(integer_one.cmp_value(&float_zero), Ordering::Greater);
assert_eq!(integer_one.cmp_value(&integer_two), Ordering::Less);
assert_eq!(integer_one.cmp_value(&float_two), Ordering::Less);
assert_eq!(integer_one.cmp_value(&number_two), Ordering::Less);
assert_eq!(
integer_one.cmp_value(&number_two_with_decimal),
Ordering::Less
);
assert_eq!(integer_min.cmp_value(&float_min), Ordering::Greater);
assert_eq!(integer_max.cmp_value(&float_max), Ordering::Less);
@ -156,4 +213,27 @@ mod tests {
Ordering::Equal
);
}
#[test]
fn test_cmp_number_string() {
assert_eq!(compare_number_string("1", "1"), Ordering::Equal);
assert_eq!(compare_number_string("1", "1.0"), Ordering::Equal);
assert_eq!(compare_number_string("1.000", "1.0"), Ordering::Equal);
assert_eq!(compare_number_string("1", "2"), Ordering::Less);
assert_eq!(compare_number_string("1.1", "2"), Ordering::Less);
assert_eq!(compare_number_string("-001.1000", "-1.1"), Ordering::Equal);
}
#[test]
fn test_number_components() {
assert_eq!(number_components("1"), (false, "1", ""));
assert_eq!(number_components("1.0"), (false, "1", ""));
assert_eq!(number_components("01"), (false, "1", ""));
assert_eq!(number_components("1.1"), (false, "1", "1"));
assert_eq!(number_components("1.100"), (false, "1", "1"));
assert_eq!(number_components("-1.1"), (true, "1", "1"));
assert_eq!(number_components("-01.100"), (true, "1", "1"));
}
}

View File

@ -135,6 +135,7 @@ impl Number {
match self {
Number::Float(f) => format!("float <{}>", format_float(*f)),
Number::Integer(v) => format!("int <{v}>"),
Number::String(s) => format!("number <{s}>"),
}
}
}
@ -162,6 +163,7 @@ impl Number {
match self {
Number::Float(f) => format!("float <{}>", format_float(*f)),
Number::Integer(value) => format!("integer <{value}>"),
Number::String(s) => format!("number <{s}>"),
}
}
}

View File

@ -326,8 +326,10 @@ impl Value {
serde_json::Value::Number(n) => {
if n.is_f64() {
Value::Number(Number::from(n.as_f64().unwrap()))
} else {
} else if n.is_i64() {
Value::Number(Number::from(n.as_i64().unwrap()))
} else {
Value::Number(Number::String(n.to_string()))
}
}
serde_json::Value::String(s) => Value::String(s.to_string()),
@ -522,6 +524,28 @@ pub mod tests {
}
}
#[test]
pub fn value_from_json() {
let json_number: serde_json::Value = serde_json::from_str("1000").unwrap();
assert_eq!(
Value::from_json(&json_number),
Value::Number(Number::Integer(1000))
);
let json_number: serde_json::Value = serde_json::from_str("1.0").unwrap();
assert_eq!(
Value::from_json(&json_number),
Value::Number(Number::Float(1.0))
);
let json_number: serde_json::Value =
serde_json::from_str("1000000000000000000000").unwrap();
assert_eq!(
Value::from_json(&json_number),
Value::Number(Number::String("1000000000000000000000".to_string()))
)
}
#[test]
fn test_query_status() {
let variables = HashMap::new();