jsonschema-rs/jsonschema/src/keywords/maximum.rs

121 lines
3.7 KiB
Rust

use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
keywords::CompilationResult,
validator::Validate,
};
use num_cmp::NumCmp;
use serde_json::{Map, Value};
pub(crate) struct MaximumU64Validator {
limit: u64,
}
pub(crate) struct MaximumI64Validator {
limit: i64,
}
pub(crate) struct MaximumF64Validator {
limit: f64,
}
macro_rules! validate {
($validator: ty) => {
impl Validate for $validator {
fn validate<'a>(
&self,
schema: &'a JSONSchema,
instance: &'a Value,
) -> ErrorIterator<'a> {
if self.is_valid(schema, instance) {
no_error()
} else {
error(ValidationError::maximum(instance, self.limit as f64)) // do not cast
}
}
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
if let Value::Number(item) = instance {
return if let Some(item) = item.as_u64() {
!NumCmp::num_gt(item, self.limit)
} else if let Some(item) = item.as_i64() {
!NumCmp::num_gt(item, self.limit)
} else {
let item = item.as_f64().expect("Always valid");
!NumCmp::num_gt(item, self.limit)
};
}
true
}
}
impl ToString for $validator {
fn to_string(&self) -> String {
format!("maximum: {}", self.limit)
}
}
};
}
validate!(MaximumU64Validator);
validate!(MaximumI64Validator);
impl Validate for MaximumF64Validator {
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
if let Value::Number(item) = instance {
return if let Some(item) = item.as_u64() {
!NumCmp::num_gt(item, self.limit)
} else if let Some(item) = item.as_i64() {
!NumCmp::num_gt(item, self.limit)
} else {
let item = item.as_f64().expect("Always valid");
!NumCmp::num_gt(item, self.limit)
};
}
true
}
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
if self.is_valid(schema, instance) {
no_error()
} else {
error(ValidationError::maximum(instance, self.limit))
}
}
}
impl ToString for MaximumF64Validator {
fn to_string(&self) -> String {
format!("maximum: {}", self.limit)
}
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
if let Value::Number(limit) = schema {
if let Some(limit) = limit.as_u64() {
Some(Ok(Box::new(MaximumU64Validator { limit })))
} else if let Some(limit) = limit.as_i64() {
Some(Ok(Box::new(MaximumI64Validator { limit })))
} else {
let limit = limit.as_f64().expect("Always valid");
Some(Ok(Box::new(MaximumF64Validator { limit })))
}
} else {
Some(Err(CompilationError::SchemaError))
}
}
#[cfg(test)]
mod tests {
use crate::tests_util;
use serde_json::{json, Value};
use test_case::test_case;
#[test_case(&json!({"maximum": 1u64 << 54}), &json!((1u64 << 54) + 1))]
#[test_case(&json!({"maximum": 1i64 << 54}), &json!((1i64 << 54) + 1))]
fn is_not_valid(schema: &Value, instance: &Value) {
tests_util::is_not_valid(schema, instance)
}
}