136 lines
4.0 KiB
Rust
136 lines
4.0 KiB
Rust
use std::collections::HashSet;
|
|
|
|
use serde_json::Value;
|
|
|
|
use crate::validator::context::ValidationContext;
|
|
use crate::validator::error::ValidationError;
|
|
use crate::validator::result::ValidationResult;
|
|
|
|
impl<'a> ValidationContext<'a> {
|
|
pub(crate) fn validate_array(
|
|
&self,
|
|
result: &mut ValidationResult,
|
|
) -> Result<bool, ValidationError> {
|
|
let current = self.instance;
|
|
if let Some(arr) = current.as_array() {
|
|
if let Some(min) = self.schema.min_items
|
|
&& (arr.len() as f64) < min
|
|
{
|
|
result.errors.push(ValidationError {
|
|
code: "MIN_ITEMS".to_string(),
|
|
message: "Too few items".to_string(),
|
|
path: self.path.to_string(),
|
|
});
|
|
}
|
|
if let Some(max) = self.schema.max_items
|
|
&& (arr.len() as f64) > max
|
|
{
|
|
result.errors.push(ValidationError {
|
|
code: "MAX_ITEMS".to_string(),
|
|
message: "Too many items".to_string(),
|
|
path: self.path.to_string(),
|
|
});
|
|
}
|
|
|
|
if self.schema.unique_items.unwrap_or(false) {
|
|
let mut seen: Vec<&Value> = Vec::new();
|
|
for item in arr {
|
|
if seen.contains(&item) {
|
|
result.errors.push(ValidationError {
|
|
code: "UNIQUE_ITEMS_VIOLATED".to_string(),
|
|
message: "Array has duplicate items".to_string(),
|
|
path: self.path.to_string(),
|
|
});
|
|
break;
|
|
}
|
|
seen.push(item);
|
|
}
|
|
}
|
|
|
|
if let Some(ref contains_schema) = self.schema.contains {
|
|
let mut _match_count = 0;
|
|
for (i, child_instance) in arr.iter().enumerate() {
|
|
let derived = self.derive(
|
|
contains_schema,
|
|
child_instance,
|
|
&self.path,
|
|
HashSet::new(),
|
|
self.extensible,
|
|
false,
|
|
);
|
|
|
|
let check = derived.validate()?;
|
|
if check.is_valid() {
|
|
_match_count += 1;
|
|
result.evaluated_indices.insert(i);
|
|
}
|
|
}
|
|
|
|
let min = self.schema.min_contains.unwrap_or(1.0) as usize;
|
|
if _match_count < min {
|
|
result.errors.push(ValidationError {
|
|
code: "CONTAINS_VIOLATED".to_string(),
|
|
message: format!("Contains matches {} < min {}", _match_count, min),
|
|
path: self.path.to_string(),
|
|
});
|
|
}
|
|
if let Some(max) = self.schema.max_contains
|
|
&& _match_count > max as usize
|
|
{
|
|
result.errors.push(ValidationError {
|
|
code: "CONTAINS_VIOLATED".to_string(),
|
|
message: format!("Contains matches {} > max {}", _match_count, max),
|
|
path: self.path.to_string(),
|
|
});
|
|
}
|
|
}
|
|
|
|
let len = arr.len();
|
|
let mut validation_index = 0;
|
|
|
|
if let Some(ref prefix) = self.schema.prefix_items {
|
|
for (i, sub_schema) in prefix.iter().enumerate() {
|
|
if i < len {
|
|
let path = format!("{}/{}", self.path, i);
|
|
if let Some(child_instance) = arr.get(i) {
|
|
let derived = self.derive(
|
|
sub_schema,
|
|
child_instance,
|
|
&path,
|
|
HashSet::new(),
|
|
self.extensible,
|
|
false,
|
|
);
|
|
let item_res = derived.validate()?;
|
|
result.merge(item_res);
|
|
result.evaluated_indices.insert(i);
|
|
validation_index += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if let Some(ref items_schema) = self.schema.items {
|
|
for i in validation_index..len {
|
|
let path = format!("{}/{}", self.path, i);
|
|
if let Some(child_instance) = arr.get(i) {
|
|
let derived = self.derive(
|
|
items_schema,
|
|
child_instance,
|
|
&path,
|
|
HashSet::new(),
|
|
self.extensible,
|
|
false,
|
|
);
|
|
let item_res = derived.validate()?;
|
|
result.merge(item_res);
|
|
result.evaluated_indices.insert(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(true)
|
|
}
|
|
}
|