Unifying number comparison.
This commit is contained in:
parent
731f235d9e
commit
830bb06a92
179
src/bin.rs
179
src/bin.rs
@ -192,46 +192,24 @@ impl CompareContextElement for serde_json::Value {
|
|||||||
(
|
(
|
||||||
serde_json::Value::Number(self_number),
|
serde_json::Value::Number(self_number),
|
||||||
serde_json::Value::Number(other_number),
|
serde_json::Value::Number(other_number),
|
||||||
) => match (
|
) => return compare_json_numbers(self_number, other_number),
|
||||||
self_number.as_f64(),
|
(
|
||||||
other_number.as_f64(),
|
serde_json::Value::String(self_string),
|
||||||
self_number.as_u64(),
|
serde_json::Value::Number(other_number),
|
||||||
other_number.as_u64(),
|
) => return compare_json_numbers(self_string, other_number),
|
||||||
self_number.as_i64(),
|
(
|
||||||
other_number.as_i64(),
|
serde_json::Value::Number(self_number),
|
||||||
) {
|
serde_json::Value::String(other_string),
|
||||||
(_, _, _, _, Some(self_int), Some(other_int)) => {
|
) => return compare_json_numbers(self_number, other_string),
|
||||||
self_int.partial_cmp(&other_int)
|
|
||||||
}
|
|
||||||
(_, _, Some(self_uint), Some(other_uint), _, _) => {
|
|
||||||
self_uint.partial_cmp(&other_uint)
|
|
||||||
}
|
|
||||||
(_, _, Some(_self_uint), _, _, Some(_other_int)) => {
|
|
||||||
// If the previous matches did not catch
|
|
||||||
// it, then other must be negative and
|
|
||||||
// self must be larger than can be
|
|
||||||
// represented with an i64, therefore self
|
|
||||||
// is greater than other.
|
|
||||||
Some(Ordering::Greater)
|
|
||||||
}
|
|
||||||
(_, _, _, Some(_other_uint), Some(_self_int), _) => {
|
|
||||||
// If the previous matches did not catch
|
|
||||||
// it, then self must be negative and
|
|
||||||
// other must be larger than can be
|
|
||||||
// represented with an i64, therefore
|
|
||||||
// other is greater than self.
|
|
||||||
Some(Ordering::Less)
|
|
||||||
}
|
|
||||||
(Some(self_float), Some(other_float), _, _, _, _) => {
|
|
||||||
self_float.partial_cmp(&other_float)
|
|
||||||
}
|
|
||||||
_ => panic!("This should be impossible since u64 and i64 can both be converted to floats"),
|
|
||||||
},
|
|
||||||
(
|
(
|
||||||
serde_json::Value::String(self_string),
|
serde_json::Value::String(self_string),
|
||||||
serde_json::Value::String(other_string),
|
serde_json::Value::String(other_string),
|
||||||
) => self_string.partial_cmp(other_string),
|
) => self_string.partial_cmp(other_string),
|
||||||
(serde_json::Value::Array(self_array), serde_json::Value::Array(other_array)) => convert_vec_to_context_element(self_array).partial_cmp(&convert_vec_to_context_element(other_array)),
|
(
|
||||||
|
serde_json::Value::Array(self_array),
|
||||||
|
serde_json::Value::Array(other_array),
|
||||||
|
) => convert_vec_to_context_element(self_array)
|
||||||
|
.partial_cmp(&convert_vec_to_context_element(other_array)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -246,35 +224,14 @@ impl CompareContextElement for serde_json::Value {
|
|||||||
(
|
(
|
||||||
serde_json::Value::String(self_string),
|
serde_json::Value::String(self_string),
|
||||||
OwnedLiteral::LPositiveInteger(other_num),
|
OwnedLiteral::LPositiveInteger(other_num),
|
||||||
) => return self_string.partial_cmp(&other_num.to_string()),
|
) => return compare_json_numbers(self_string, other_literal),
|
||||||
(
|
(serde_json::Value::Number(self_num), OwnedLiteral::LString(other_string)) => {
|
||||||
serde_json::Value::Number(self_num),
|
return compare_json_numbers(self_num, other_string)
|
||||||
OwnedLiteral::LString(other_string),
|
}
|
||||||
) => return None,
|
|
||||||
(
|
(
|
||||||
serde_json::Value::Number(self_num),
|
serde_json::Value::Number(self_num),
|
||||||
OwnedLiteral::LPositiveInteger(other_num),
|
OwnedLiteral::LPositiveInteger(other_num),
|
||||||
) => match (
|
) => return compare_json_numbers(self_num, other_literal),
|
||||||
self_num.as_u64(),
|
|
||||||
self_num.as_i64(),
|
|
||||||
self_num.as_f64(),
|
|
||||||
) {
|
|
||||||
(Some(self_uint), _, _) => {
|
|
||||||
return self_uint.partial_cmp(other_num)
|
|
||||||
}
|
|
||||||
(_, Some(self_int), _) => {
|
|
||||||
return if other_num <= &(i64::max_value() as u64) {
|
|
||||||
self_int.partial_cmp(&(*other_num as i64))
|
|
||||||
} else {
|
|
||||||
Some(Ordering::Less)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(_, _, Some(self_float)) => {
|
|
||||||
// TODO: How does javascript compare ints and floats? I'm just going to assume a cast to a string for now.
|
|
||||||
return self_float.to_string().partial_cmp(&other_num.to_string())
|
|
||||||
}
|
|
||||||
(None, None, None) => panic!("This should be impossible since u64 and i64 can both be converted to floats")
|
|
||||||
}
|
|
||||||
(serde_json::Value::Array(_), _) => {
|
(serde_json::Value::Array(_), _) => {
|
||||||
// TODO
|
// TODO
|
||||||
todo!()
|
todo!()
|
||||||
@ -311,6 +268,104 @@ fn convert_vec_to_context_element(array: &Vec<serde_json::Value>) -> Vec<&dyn Co
|
|||||||
array.iter().map(|v| v as _).collect()
|
array.iter().map(|v| v as _).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum JsonNumber {
|
||||||
|
UnsignedInteger(u64),
|
||||||
|
SignedInteger(i64),
|
||||||
|
Decimal(f64),
|
||||||
|
Failure,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&String> for JsonNumber {
|
||||||
|
fn from(original: &String) -> Self {
|
||||||
|
match original.parse::<u64>() {
|
||||||
|
Ok(num) => return JsonNumber::UnsignedInteger(num),
|
||||||
|
Err(_) => (),
|
||||||
|
};
|
||||||
|
match original.parse::<i64>() {
|
||||||
|
Ok(num) => return JsonNumber::SignedInteger(num),
|
||||||
|
Err(_) => (),
|
||||||
|
};
|
||||||
|
match original.parse::<f64>() {
|
||||||
|
Ok(num) => return JsonNumber::Decimal(num),
|
||||||
|
Err(_) => (),
|
||||||
|
};
|
||||||
|
JsonNumber::Failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&serde_json::Number> for JsonNumber {
|
||||||
|
fn from(original: &serde_json::Number) -> Self {
|
||||||
|
match original.as_u64() {
|
||||||
|
Some(num) => return JsonNumber::UnsignedInteger(num),
|
||||||
|
None => (),
|
||||||
|
};
|
||||||
|
match original.as_i64() {
|
||||||
|
Some(num) => return JsonNumber::SignedInteger(num),
|
||||||
|
None => (),
|
||||||
|
};
|
||||||
|
match original.as_f64() {
|
||||||
|
Some(num) => return JsonNumber::Decimal(num),
|
||||||
|
None => (),
|
||||||
|
};
|
||||||
|
JsonNumber::Failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&OwnedLiteral> for JsonNumber {
|
||||||
|
fn from(original: &OwnedLiteral) -> Self {
|
||||||
|
match original {
|
||||||
|
OwnedLiteral::LPositiveInteger(num) => JsonNumber::UnsignedInteger(*num),
|
||||||
|
OwnedLiteral::LString(text) => text.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compare json numbers
|
||||||
|
///
|
||||||
|
/// While this function can be called with two strings, it would not
|
||||||
|
/// make sense because javascript does not use numeric comparisons for
|
||||||
|
/// strings
|
||||||
|
fn compare_json_numbers<S, O>(self_input: S, other_input: O) -> Option<Ordering>
|
||||||
|
where
|
||||||
|
S: Into<JsonNumber>,
|
||||||
|
O: Into<JsonNumber>,
|
||||||
|
{
|
||||||
|
let self_number: JsonNumber = self_input.into();
|
||||||
|
let other_number: JsonNumber = other_input.into();
|
||||||
|
// println!(
|
||||||
|
// "compare_number_and_string {:?} | {:?}",
|
||||||
|
// self_number, other_number
|
||||||
|
// );
|
||||||
|
// TODO: Figure out how javascript compares floats and ints
|
||||||
|
match (self_number, other_number) {
|
||||||
|
(JsonNumber::Failure, _) => return None,
|
||||||
|
(_, JsonNumber::Failure) => return None,
|
||||||
|
(JsonNumber::UnsignedInteger(self_num), JsonNumber::UnsignedInteger(other_num)) => {
|
||||||
|
return self_num.partial_cmp(&other_num)
|
||||||
|
}
|
||||||
|
(JsonNumber::UnsignedInteger(self_num), JsonNumber::SignedInteger(other_num)) => {
|
||||||
|
return Some(Ordering::Greater)
|
||||||
|
}
|
||||||
|
(JsonNumber::UnsignedInteger(self_num), JsonNumber::Decimal(other_num)) => return None,
|
||||||
|
|
||||||
|
(JsonNumber::SignedInteger(self_num), JsonNumber::UnsignedInteger(other_num)) => {
|
||||||
|
return Some(Ordering::Less)
|
||||||
|
}
|
||||||
|
(JsonNumber::SignedInteger(self_num), JsonNumber::SignedInteger(other_num)) => {
|
||||||
|
return self_num.partial_cmp(&other_num)
|
||||||
|
}
|
||||||
|
(JsonNumber::SignedInteger(self_num), JsonNumber::Decimal(other_num)) => return None,
|
||||||
|
|
||||||
|
(JsonNumber::Decimal(self_num), JsonNumber::UnsignedInteger(other_num)) => return None,
|
||||||
|
(JsonNumber::Decimal(self_num), JsonNumber::SignedInteger(other_num)) => return None,
|
||||||
|
(JsonNumber::Decimal(self_num), JsonNumber::Decimal(other_num)) => {
|
||||||
|
return self_num.partial_cmp(&other_num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
Loading…
Reference in New Issue
Block a user