use serde_json::{Number, Value};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ScalarKind {
String,
Number,
Integer,
Boolean,
}
impl ScalarKind {
pub(crate) fn from_name(name: &str) -> Option<Self> {
match name {
"string" => Some(Self::String),
"number" => Some(Self::Number),
"integer" => Some(Self::Integer),
"boolean" => Some(Self::Boolean),
_ => None,
}
}
}
#[derive(Debug, Clone, Default, PartialEq)]
pub(crate) struct ScalarMatcher {
pub(crate) kind: Option<ScalarKind>,
pub(crate) const_value: Option<Value>,
pub(crate) enum_values: Vec<Value>,
pub(crate) minimum: Option<Number>,
pub(crate) maximum: Option<Number>,
pub(crate) exclusive_minimum: Option<Number>,
pub(crate) exclusive_maximum: Option<Number>,
pub(crate) multiple_of: Option<Number>,
pub(crate) min_length: Option<u64>,
pub(crate) max_length: Option<u64>,
pub(crate) pattern: Option<String>,
pub(crate) format: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scalar_kind_classifies_only_supported_scalar_types() {
assert_eq!(ScalarKind::from_name("string"), Some(ScalarKind::String));
assert_eq!(ScalarKind::from_name("integer"), Some(ScalarKind::Integer));
assert_eq!(ScalarKind::from_name("object"), None);
assert_eq!(ScalarKind::from_name("null"), None);
}
}
pub(crate) fn value_token_decimal(number: &Number) -> String {
if let Some(float) = number.as_f64()
&& float.fract() == 0.0
&& float.is_finite()
&& float.abs() <= 9_007_199_254_740_991.0
{
return format!("{}", float as i64);
}
number.to_string()
}
#[cfg(test)]
mod value_token_decimal_tests {
use super::value_token_decimal;
use serde_json::json;
fn token(value: serde_json::Value) -> String {
value_token_decimal(value.as_number().expect("a number"))
}
#[test]
fn integral_spellings_collapse_to_one_token() {
for spelling in [json!(1), json!(1.0)] {
assert_eq!(token(spelling), "1");
}
assert_eq!(token(json!(-3.0)), "-3");
assert_eq!(token(json!(0.0)), "0");
assert_eq!(token(json!(-0.0)), "0", "P1 compares ±0 equal");
}
#[test]
fn fractions_keep_their_decimal() {
assert_eq!(token(json!(3.14)), "3.14");
assert_eq!(token(json!(-3.14)), "-3.14");
assert_eq!(token(json!(1.50)), "1.5", "shortest round-trippable");
}
}