blob: 8108c02f097c096a0a2c1e43b2a02118a9ddd96c [file] [log] [blame]
use serde_json::{Value};
use std::cmp;
use url;
use super::super::errors;
use super::super::scope;
#[derive(Debug)]
pub enum ItemsKind {
Schema(url::Url),
Array(Vec<url::Url>)
}
#[derive(Debug)]
pub enum AdditionalKind {
Boolean(bool),
Schema(url::Url)
}
#[allow(missing_copy_implementations)]
pub struct Items {
pub items: Option<ItemsKind>,
pub additional: Option<AdditionalKind>
}
impl super::Validator for Items {
fn validate(&self, val: &Value, path: &str, scope: &scope::Scope) -> super::ValidationState {
let array = nonstrict_process!(val.as_array(), path);
let mut state = super::ValidationState::new();
match self.items {
Some(ItemsKind::Schema(ref url)) => {
// Just validate all items against the schema
let schema = scope.resolve(url);
if schema.is_some() {
let schema = schema.unwrap();
for (idx, item) in array.iter().enumerate() {
let item_path = [path, idx.to_string().as_ref()].join("/");
state.append(schema.validate_in(item, item_path.as_ref()));
}
} else {
state.missing.push(url.clone());
}
},
Some(ItemsKind::Array(ref urls)) => {
let min = cmp::min(urls.len(), array.len());
// Validate against schemas
for idx in 0..min {
let schema = scope.resolve(&urls[idx]);
let item = &array[idx];
if schema.is_some() {
let item_path = [path, idx.to_string().as_ref()].join("/");
state.append(schema.unwrap().validate_in(item, item_path.as_ref()))
} else {
state.missing.push(urls[idx].clone())
}
}
// Validate agains additional items
if array.len() > urls.len() {
match self.additional {
Some(AdditionalKind::Boolean(allow)) if allow == false => {
state.errors.push(Box::new(
errors::Items {
path: path.to_string(),
detail: "Additional items are not allowed".to_string()
}
))
},
Some(AdditionalKind::Schema(ref url)) => {
let schema = scope.resolve(url);
if schema.is_some() {
let schema = schema.unwrap();
for (idx, item) in array[urls.len()..].iter().enumerate() {
let item_path = [path, idx.to_string().as_ref()].join("/");
state.append(schema.validate_in(item, item_path.as_ref()))
}
} else {
state.missing.push(url.clone())
}
},
_ => ()
}
}
}
_ => ()
}
state
}
}