feat: Use meta-schemas to validate input schemas

This commit is contained in:
Eden Yefet 2021-06-17 16:04:29 +03:00 committed by GitHub
parent 1212e8893b
commit 5e65010387
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 547 additions and 461 deletions

View File

@ -2,6 +2,15 @@
## [Unreleased]
### Added
- **BREAKING**: Meta-schema validation for input schemas. By default, all input schemas are validated with their respective meta-schemas
and instead of `CompilationError` there will be the usual `ValidationError`. [#198](https://github.com/Stranger6667/jsonschema-rs/issues/198)
### Removed
- `CompilationError`. Use `ValidationError` instead.
## [0.9.1] - 2021-06-17
### Fixed

View File

@ -22,13 +22,13 @@ jsonschema = "0.9"
To validate documents against some schema and get validation errors (if any):
```rust
use jsonschema::{JSONSchema, Draft, CompilationError};
use jsonschema::{Draft, JSONSchema};
use serde_json::json;
fn main() -> Result<(), CompilationError> {
fn main() {
let schema = json!({"maxLength": 5});
let instance = json!("foo");
let compiled = JSONSchema::compile(&schema)?;
let compiled = JSONSchema::compile(&schema).expect("A valid schema");
let result = compiled.validate(&instance);
if let Err(errors) = result {
for error in errors {
@ -38,7 +38,6 @@ fn main() -> Result<(), CompilationError> {
);
}
}
Ok(())
}
```
@ -61,17 +60,16 @@ fn main() {
Or use a compiled schema (preferred):
```rust
use jsonschema::{JSONSchema, Draft, CompilationError};
use jsonschema::{Draft, JSONSchema};
use serde_json::json;
fn main() -> Result<(), CompilationError> {
fn main() {
let schema = json!({"maxLength": 5});
let instance = json!("foo");
// Draft is detected automatically
// with fallback to Draft7
let compiled = JSONSchema::compile(&schema)?;
let compiled = JSONSchema::compile(&schema).expect("A valid schema");
assert!(compiled.is_valid(&instance));
Ok(())
}
```

View File

@ -2,6 +2,15 @@
## [Unreleased]
### Added
- **BREAKING**: Meta-schema validation for input schemas. By default, all input schemas are validated with their respective meta-schemas
and instead of `CompilationError` there will be the usual `ValidationError`. [#198](https://github.com/Stranger6667/jsonschema-rs/issues/198)
### Removed
- `CompilationError`. Use `ValidationError` instead.
## [0.9.1] - 2021-06-17
### Fixed

View File

@ -28,16 +28,11 @@ const DRAFT4: u8 = 4;
create_exception!(jsonschema_rs, ValidationError, exceptions::PyValueError);
#[derive(Debug)]
enum JSONSchemaError {
Compilation(jsonschema::CompilationError),
}
struct ValidationErrorWrapper<'a>(jsonschema::ValidationError<'a>);
impl From<JSONSchemaError> for PyErr {
fn from(error: JSONSchemaError) -> PyErr {
exceptions::PyValueError::new_err(match error {
JSONSchemaError::Compilation(_) => "Invalid schema",
})
impl<'a> From<ValidationErrorWrapper<'a>> for PyErr {
fn from(error: ValidationErrorWrapper<'a>) -> PyErr {
ValidationError::new_err(to_error_message(&error.0))
}
}
@ -70,12 +65,9 @@ fn make_options(
fn raise_on_error(compiled: &jsonschema::JSONSchema, instance: &PyAny) -> PyResult<()> {
let instance = ser::to_value(instance)?;
let result = compiled.validate(&instance);
let error = if let Some(mut errors) = result.err() {
// If we have `Err` case, then the iterator is not empty
Some(errors.next().expect("Iterator should not be empty"))
} else {
None
};
let error = result
.err()
.map(|mut errors| errors.next().expect("Iterator should not be empty"));
error.map_or_else(
|| Ok(()),
|err| {
@ -127,9 +119,7 @@ fn is_valid(
) -> PyResult<bool> {
let options = make_options(draft, with_meta_schemas)?;
let schema = ser::to_value(schema)?;
let compiled = options
.compile(&schema)
.map_err(JSONSchemaError::Compilation)?;
let compiled = options.compile(&schema).map_err(ValidationErrorWrapper)?;
let instance = ser::to_value(instance)?;
Ok(compiled.is_valid(&instance))
}
@ -155,9 +145,7 @@ fn validate(
) -> PyResult<()> {
let options = make_options(draft, with_meta_schemas)?;
let schema = ser::to_value(schema)?;
let compiled = options
.compile(&schema)
.map_err(JSONSchemaError::Compilation)?;
let compiled = options.compile(&schema).map_err(ValidationErrorWrapper)?;
raise_on_error(&compiled, instance)
}
@ -187,9 +175,7 @@ impl JSONSchema {
let raw_schema = ser::to_value(schema)?;
let schema: &'static Value = Box::leak(Box::new(raw_schema));
Ok(JSONSchema {
schema: options
.compile(schema)
.map_err(JSONSchemaError::Compilation)?,
schema: options.compile(schema).map_err(ValidationErrorWrapper)?,
raw_schema: schema,
})
}

View File

@ -66,7 +66,7 @@ def test_recursive_list():
@pytest.mark.parametrize(
"schema, draft, error",
(
([], None, "Invalid schema"),
([], None, r'\[\] is not of types "boolean", "object"'),
({}, 5, "Unknown draft: 5"),
),
)

View File

@ -5,11 +5,8 @@ pub(crate) mod context;
pub(crate) mod options;
use crate::{
error::{CompilationError, ErrorIterator},
keywords,
keywords::Validators,
paths::InstancePath,
resolver::Resolver,
error::ErrorIterator, keywords, keywords::Validators, paths::InstancePath, resolver::Resolver,
ValidationError,
};
use context::CompilationContext;
use options::CompilationOptions;
@ -54,7 +51,7 @@ impl<'a> JSONSchema<'a> {
/// Compile the input schema into a validation tree.
///
/// The method is equivalent to `JSONSchema::options().compile(schema)`
pub fn compile(schema: &'a Value) -> Result<JSONSchema<'a>, CompilationError> {
pub fn compile(schema: &'a Value) -> Result<JSONSchema<'a>, ValidationError<'a>> {
Self::options().compile(schema)
}
@ -87,10 +84,10 @@ impl<'a> JSONSchema<'a> {
/// Compile JSON schema into a tree of validators.
#[inline]
pub(crate) fn compile_validators(
schema: &Value,
context: &CompilationContext,
) -> Result<Validators, CompilationError> {
pub(crate) fn compile_validators<'a, 'c>(
schema: &'a Value,
context: &'c CompilationContext,
) -> Result<Validators, ValidationError<'a>> {
let context = context.push(schema)?;
match schema {
Value::Bool(value) => match value {
@ -105,7 +102,7 @@ pub(crate) fn compile_validators(
Ok(vec![keywords::ref_::compile(schema, reference, &context)
.expect("Should always return Some")?])
} else {
Err(CompilationError::SchemaError)
Err(ValidationError::schema(schema))
}
} else {
let mut validators = Vec::with_capacity(object.len());
@ -119,7 +116,7 @@ pub(crate) fn compile_validators(
Ok(validators)
}
}
_ => Err(CompilationError::SchemaError),
_ => Err(ValidationError::schema(schema)),
}
}

View File

@ -5,28 +5,49 @@ use crate::{
DEFAULT_CONTENT_ENCODING_CHECKS_AND_CONVERTERS,
},
content_media_type::{ContentMediaTypeCheckType, DEFAULT_CONTENT_MEDIA_TYPE_CHECKS},
error::CompilationError,
resolver::Resolver,
schemas,
schemas, ValidationError,
};
use ahash::AHashMap;
use serde_json::Value;
use std::{borrow::Cow, fmt};
lazy_static::lazy_static! {
static ref META_SCHEMAS: AHashMap<String, Value> = {
static ref DRAFT4:serde_json::Value = serde_json::from_str(include_str!("../../meta_schemas/draft4.json")).expect("Valid schema!");
static ref DRAFT6:serde_json::Value = serde_json::from_str(include_str!("../../meta_schemas/draft6.json")).expect("Valid schema!");
static ref DRAFT7:serde_json::Value = serde_json::from_str(include_str!("../../meta_schemas/draft7.json")).expect("Valid schema!");
static ref META_SCHEMAS: AHashMap<String, serde_json::Value> = {
let mut store = AHashMap::with_capacity(3);
store.insert(
"http://json-schema.org/draft-04/schema".to_string(),
serde_json::from_str(include_str!("../../meta_schemas/draft4.json")).expect("Valid schema!")
DRAFT4.clone()
);
store.insert(
"http://json-schema.org/draft-06/schema".to_string(),
serde_json::from_str(include_str!("../../meta_schemas/draft6.json")).expect("Valid schema!")
DRAFT6.clone()
);
store.insert(
"http://json-schema.org/draft-07/schema".to_string(),
serde_json::from_str(include_str!("../../meta_schemas/draft7.json")).expect("Valid schema!")
DRAFT7.clone()
);
store
};
static ref META_SCHEMA_VALIDATORS: AHashMap<schemas::Draft, JSONSchema<'static>> = {
let mut store = AHashMap::with_capacity(3);
const EXPECT_MESSAGE: &str = "Valid meta-schema!";
store.insert(
schemas::Draft::Draft4,
JSONSchema::options().without_schema_validation().compile(&DRAFT4).expect(EXPECT_MESSAGE)
);
store.insert(
schemas::Draft::Draft6,
JSONSchema::options().without_schema_validation().compile(&DRAFT6).expect(EXPECT_MESSAGE)
);
store.insert(
schemas::Draft::Draft7,
JSONSchema::options().without_schema_validation().compile(&DRAFT7).expect(EXPECT_MESSAGE)
);
store
};
@ -36,13 +57,26 @@ lazy_static::lazy_static! {
///
/// Using a `CompilationOptions` instance you can configure the supported draft,
/// content media types and more (check the exposed methods)
#[derive(Clone, Default)]
#[derive(Clone)]
pub struct CompilationOptions {
draft: Option<schemas::Draft>,
content_media_type_checks: AHashMap<&'static str, Option<ContentMediaTypeCheckType>>,
content_encoding_checks_and_converters:
AHashMap<&'static str, Option<(ContentEncodingCheckType, ContentEncodingConverterType)>>,
store: AHashMap<String, Value>,
store: AHashMap<String, serde_json::Value>,
validate_schema: bool,
}
impl Default for CompilationOptions {
fn default() -> Self {
CompilationOptions {
validate_schema: true,
draft: Default::default(),
content_media_type_checks: Default::default(),
content_encoding_checks_and_converters: Default::default(),
store: Default::default(),
}
}
}
impl CompilationOptions {
@ -51,7 +85,10 @@ impl CompilationOptions {
}
/// Compile `schema` into `JSONSchema` using the currently defined options.
pub fn compile<'a>(&self, schema: &'a Value) -> Result<JSONSchema<'a>, CompilationError> {
pub fn compile<'a>(
&self,
schema: &'a serde_json::Value,
) -> Result<JSONSchema<'a>, ValidationError<'a>> {
// Draft is detected in the following precedence order:
// - Explicitly specified;
// - $schema field in the document;
@ -79,6 +116,17 @@ impl CompilationOptions {
let resolver = Resolver::new(draft, &scope, schema, self.store.clone())?;
let context = CompilationContext::new(scope, processed_config);
if self.validate_schema {
if let Some(mut errors) = META_SCHEMA_VALIDATORS
.get(&draft)
.expect("Existing draft")
.validate(schema)
.err()
{
return Err(errors.next().expect("Should have at least one element"));
}
}
let mut validators = compile_validators(schema, &context)?;
validators.shrink_to_fit();
@ -295,10 +343,21 @@ impl CompilationOptions {
/// Add a new document to the store. It works as a cache to avoid making additional network
/// calls to remote schemas via the `$ref` keyword.
#[inline]
pub fn with_document(&mut self, id: String, document: Value) -> &mut Self {
pub fn with_document(&mut self, id: String, document: serde_json::Value) -> &mut Self {
self.store.insert(id, document);
self
}
/// Do not perform schema validation during compilation.
/// This method is only used to disable meta-schema validation for meta-schemas itself to avoid
/// infinite recursion.
/// The end-user will still receive `ValidationError` that are crafted manually during
/// compilation.
#[inline]
pub(crate) fn without_schema_validation(&mut self) -> &mut Self {
self.validate_schema = false;
self
}
}
impl fmt::Debug for CompilationOptions {

View File

@ -7,45 +7,13 @@ use serde_json::{Map, Number, Value};
use std::{
borrow::Cow,
error, fmt,
fmt::{Error, Formatter},
fmt::Formatter,
io,
iter::{empty, once},
str::Utf8Error,
string::FromUtf8Error,
};
/// The error type that happens when the input schema is not valid.
///
/// It includes cases when during validation a reference is resolved into an invalid schema,
/// which we can't know upfront because schemas can be in remote locations.
#[derive(Debug, PartialEq)]
pub enum CompilationError {
/// Invalid schema structure
SchemaError,
}
impl error::Error for CompilationError {}
impl fmt::Display for CompilationError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
write!(f, "Schema compilation error")
}
}
impl From<fancy_regex::Error> for CompilationError {
#[inline]
fn from(_: fancy_regex::Error) -> Self {
CompilationError::SchemaError
}
}
impl From<url::ParseError> for CompilationError {
#[inline]
fn from(_: url::ParseError) -> Self {
CompilationError::SchemaError
}
}
/// An error that can occur during validation.
#[derive(Debug)]
pub struct ValidationError<'a> {
@ -612,13 +580,23 @@ impl<'a> ValidationError<'a> {
kind: ValidationErrorKind::Reqwest { error },
}
}
pub(crate) fn schema() -> ValidationError<'a> {
pub(crate) fn schema(instance: &'a Value) -> ValidationError<'a> {
ValidationError {
instance_path: JSONPointer::default(),
instance: Cow::Borrowed(instance),
kind: ValidationErrorKind::Schema,
}
}
pub(crate) fn null_schema() -> ValidationError<'a> {
ValidationError {
instance_path: JSONPointer::default(),
instance: Cow::Owned(Value::Null),
kind: ValidationErrorKind::Schema,
}
}
pub(crate) const fn single_type_error(
instance_path: JSONPointer,
instance: &'a Value,
@ -671,12 +649,6 @@ impl<'a> ValidationError<'a> {
}
}
impl From<CompilationError> for ValidationError<'_> {
#[inline]
fn from(_: CompilationError) -> Self {
ValidationError::schema()
}
}
impl error::Error for ValidationError<'_> {}
impl From<serde_json::Error> for ValidationError<'_> {
#[inline]

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{compile_validators, context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::{boolean::FalseValidator, format_validators, CompilationResult, Validators},
paths::InstancePath,
validator::Validate,
@ -13,11 +13,11 @@ pub(crate) struct AdditionalItemsObjectValidator {
}
impl AdditionalItemsObjectValidator {
#[inline]
pub(crate) fn compile(
schema: &Value,
pub(crate) fn compile<'a>(
schema: &'a Value,
items_count: usize,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
let validators = compile_validators(schema, context)?;
Ok(Box::new(AdditionalItemsObjectValidator {
validators,
@ -72,7 +72,7 @@ pub(crate) struct AdditionalItemsBooleanValidator {
}
impl AdditionalItemsBooleanValidator {
#[inline]
pub(crate) fn compile(items_count: usize) -> CompilationResult {
pub(crate) fn compile<'a>(items_count: usize) -> CompilationResult<'a> {
Ok(Box::new(AdditionalItemsBooleanValidator { items_count }))
}
}
@ -111,11 +111,11 @@ impl ToString for AdditionalItemsBooleanValidator {
}
#[inline]
pub(crate) fn compile(
pub(crate) fn compile<'a>(
parent: &Map<String, Value>,
schema: &Value,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
if let Some(items) = parent.get("items") {
match items {
Value::Object(_) => None,
@ -140,7 +140,7 @@ pub(crate) fn compile(
Some(FalseValidator::compile())
}
}
_ => Some(Err(CompilationError::SchemaError)),
_ => Some(Err(ValidationError::schema(schema))),
}
} else {
None

View File

@ -8,7 +8,7 @@
//! Each valid combination of these keywords has a validator here.
use crate::{
compilation::{compile_validators, context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::{format_validators, CompilationResult, Validators},
paths::InstancePath,
validator::Validate,
@ -76,7 +76,7 @@ macro_rules! dynamic_map {
))
}
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::null_schema()))
}
}};
}
@ -127,20 +127,20 @@ macro_rules! validate {
}};
}
fn compile_small_map(
map: &Map<String, Value>,
fn compile_small_map<'a>(
map: &'a Map<String, Value>,
context: &CompilationContext,
) -> Result<SmallValidatorsMap, CompilationError> {
) -> Result<SmallValidatorsMap, ValidationError<'a>> {
let mut properties = Vec::with_capacity(map.len());
for (key, subschema) in map {
properties.push((key.clone(), compile_validators(subschema, context)?));
}
Ok(properties)
}
fn compile_big_map(
map: &Map<String, Value>,
fn compile_big_map<'a>(
map: &'a Map<String, Value>,
context: &CompilationContext,
) -> Result<BigValidatorsMap, CompilationError> {
) -> Result<BigValidatorsMap, ValidationError<'a>> {
let mut properties = AHashMap::with_capacity(map.len());
for (key, subschema) in map {
properties.insert(key.clone(), compile_validators(subschema, context)?);
@ -168,7 +168,10 @@ pub(crate) struct AdditionalPropertiesValidator {
}
impl AdditionalPropertiesValidator {
#[inline]
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult<'a> {
Ok(Box::new(AdditionalPropertiesValidator {
validators: compile_validators(schema, context)?,
}))
@ -231,7 +234,7 @@ impl ToString for AdditionalPropertiesValidator {
pub(crate) struct AdditionalPropertiesFalseValidator {}
impl AdditionalPropertiesFalseValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(AdditionalPropertiesFalseValidator {}))
}
}
@ -287,10 +290,10 @@ pub(crate) struct AdditionalPropertiesNotEmptyFalseValidator<M: PropertiesValida
}
impl AdditionalPropertiesNotEmptyFalseValidator<SmallValidatorsMap> {
#[inline]
pub(crate) fn compile(
map: &Map<String, Value>,
pub(crate) fn compile<'a>(
map: &'a Map<String, Value>,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(AdditionalPropertiesNotEmptyFalseValidator {
properties: compile_small_map(map, context)?,
}))
@ -298,10 +301,10 @@ impl AdditionalPropertiesNotEmptyFalseValidator<SmallValidatorsMap> {
}
impl AdditionalPropertiesNotEmptyFalseValidator<BigValidatorsMap> {
#[inline]
pub(crate) fn compile(
map: &Map<String, Value>,
pub(crate) fn compile<'a>(
map: &'a Map<String, Value>,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(AdditionalPropertiesNotEmptyFalseValidator {
properties: compile_big_map(map, context)?,
}))
@ -385,11 +388,11 @@ pub(crate) struct AdditionalPropertiesNotEmptyValidator<M: PropertiesValidatorsM
}
impl AdditionalPropertiesNotEmptyValidator<SmallValidatorsMap> {
#[inline]
pub(crate) fn compile(
map: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
map: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(AdditionalPropertiesNotEmptyValidator {
properties: compile_small_map(map, context)?,
validators: compile_validators(schema, context)?,
@ -398,11 +401,11 @@ impl AdditionalPropertiesNotEmptyValidator<SmallValidatorsMap> {
}
impl AdditionalPropertiesNotEmptyValidator<BigValidatorsMap> {
#[inline]
pub(crate) fn compile(
map: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
map: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(AdditionalPropertiesNotEmptyValidator {
properties: compile_big_map(map, context)?,
validators: compile_validators(schema, context)?,
@ -499,11 +502,11 @@ pub(crate) struct AdditionalPropertiesWithPatternsValidator {
}
impl AdditionalPropertiesWithPatternsValidator {
#[inline]
pub(crate) fn compile(
schema: &Value,
pub(crate) fn compile<'a>(
schema: &'a Value,
patterns: PatternedValidators,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(AdditionalPropertiesWithPatternsValidator {
validators: compile_validators(schema, context)?,
patterns,
@ -600,7 +603,7 @@ pub(crate) struct AdditionalPropertiesWithPatternsFalseValidator {
}
impl AdditionalPropertiesWithPatternsFalseValidator {
#[inline]
pub(crate) fn compile(patterns: PatternedValidators) -> CompilationResult {
pub(crate) fn compile<'a>(patterns: PatternedValidators) -> CompilationResult<'a> {
Ok(Box::new(AdditionalPropertiesWithPatternsFalseValidator {
patterns,
}))
@ -694,12 +697,12 @@ pub(crate) struct AdditionalPropertiesWithPatternsNotEmptyValidator<M: Propertie
}
impl AdditionalPropertiesWithPatternsNotEmptyValidator<SmallValidatorsMap> {
#[inline]
pub(crate) fn compile(
map: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
map: &'a Map<String, Value>,
schema: &'a Value,
patterns: PatternedValidators,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(
AdditionalPropertiesWithPatternsNotEmptyValidator {
validators: compile_validators(schema, context)?,
@ -711,12 +714,12 @@ impl AdditionalPropertiesWithPatternsNotEmptyValidator<SmallValidatorsMap> {
}
impl AdditionalPropertiesWithPatternsNotEmptyValidator<BigValidatorsMap> {
#[inline]
pub(crate) fn compile(
map: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
map: &'a Map<String, Value>,
schema: &'a Value,
patterns: PatternedValidators,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(
AdditionalPropertiesWithPatternsNotEmptyValidator {
validators: compile_validators(schema, context)?,
@ -851,11 +854,11 @@ pub(crate) struct AdditionalPropertiesWithPatternsNotEmptyFalseValidator<M: Prop
}
impl AdditionalPropertiesWithPatternsNotEmptyFalseValidator<SmallValidatorsMap> {
#[inline]
pub(crate) fn compile(
map: &Map<String, Value>,
pub(crate) fn compile<'a>(
map: &'a Map<String, Value>,
patterns: PatternedValidators,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(
AdditionalPropertiesWithPatternsNotEmptyFalseValidator::<SmallValidatorsMap> {
properties: compile_small_map(map, context)?,
@ -866,11 +869,11 @@ impl AdditionalPropertiesWithPatternsNotEmptyFalseValidator<SmallValidatorsMap>
}
impl AdditionalPropertiesWithPatternsNotEmptyFalseValidator<BigValidatorsMap> {
#[inline]
pub(crate) fn compile(
map: &Map<String, Value>,
pub(crate) fn compile<'a>(
map: &'a Map<String, Value>,
patterns: PatternedValidators,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(
AdditionalPropertiesWithPatternsNotEmptyFalseValidator {
properties: compile_big_map(map, context)?,
@ -967,11 +970,11 @@ impl<M: PropertiesValidatorsMap> ToString
}
}
#[inline]
pub(crate) fn compile(
parent: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
parent: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
let properties = parent.get("properties");
if let Some(patterns) = parent.get("patternProperties") {
if let Value::Object(obj) = patterns {
@ -1012,10 +1015,10 @@ pub(crate) fn compile(
}
}
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::null_schema()))
}
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::null_schema()))
}
} else {
match schema {
@ -1049,20 +1052,20 @@ pub(crate) fn compile(
/// Create a vector of pattern-validators pairs.
#[inline]
fn compile_patterns(
obj: &Map<String, Value>,
fn compile_patterns<'a>(
obj: &'a Map<String, Value>,
context: &CompilationContext,
) -> Result<PatternedValidators, CompilationError> {
) -> Result<PatternedValidators, ValidationError<'a>> {
let mut compiled_patterns = Vec::with_capacity(obj.len());
for (pattern, subschema) in obj {
if let Ok(compiled_pattern) = Regex::new(pattern) {
if let Ok(validators) = compile_validators(subschema, context) {
compiled_patterns.push((compiled_pattern, validators));
} else {
return Err(CompilationError::SchemaError);
return Err(ValidationError::schema(subschema));
}
} else {
return Err(CompilationError::SchemaError);
return Err(ValidationError::schema(subschema));
}
}
Ok(compiled_patterns)

View File

@ -1,19 +1,24 @@
use crate::{
compilation::{compile_validators, context::CompilationContext, JSONSchema},
error::{CompilationError, ErrorIterator},
keywords::{format_validators, format_vec_of_validators, CompilationResult, Validators},
error::{ErrorIterator, ValidationError},
keywords::{format_validators, format_vec_of_validators, Validators},
paths::InstancePath,
validator::Validate,
};
use serde_json::{Map, Value};
use super::CompilationResult;
pub(crate) struct AllOfValidator {
schemas: Vec<Validators>,
}
impl AllOfValidator {
#[inline]
pub(crate) fn compile(items: &[Value], context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
items: &'a [Value],
context: &CompilationContext,
) -> CompilationResult<'a> {
let mut schemas = Vec::with_capacity(items.len());
for item in items {
let validators = compile_validators(item, context)?;
@ -62,7 +67,10 @@ pub(crate) struct SingleValueAllOfValidator {
impl SingleValueAllOfValidator {
#[inline]
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult<'a> {
let validators = compile_validators(schema, context)?;
Ok(Box::new(SingleValueAllOfValidator { validators }))
}
@ -96,11 +104,11 @@ impl ToString for SingleValueAllOfValidator {
}
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
if let Value::Array(items) = schema {
if items.len() == 1 {
let value = items.iter().next().expect("Vec is not empty");
@ -109,6 +117,6 @@ pub(crate) fn compile(
Some(AllOfValidator::compile(items, context))
}
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::schema(schema)))
}
}

View File

@ -1,19 +1,24 @@
use crate::{
compilation::{compile_validators, context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
keywords::{format_vec_of_validators, CompilationResult, Validators},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::{format_vec_of_validators, Validators},
paths::InstancePath,
validator::Validate,
};
use serde_json::{Map, Value};
use super::CompilationResult;
pub(crate) struct AnyOfValidator {
schemas: Vec<Validators>,
}
impl AnyOfValidator {
#[inline]
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult<'a> {
if let Value::Array(items) = schema {
let mut schemas = Vec::with_capacity(items.len());
for item in items {
@ -22,7 +27,7 @@ impl AnyOfValidator {
}
Ok(Box::new(AnyOfValidator { schemas }))
} else {
Err(CompilationError::SchemaError)
Err(ValidationError::schema(schema))
}
}
}
@ -60,10 +65,10 @@ impl ToString for AnyOfValidator {
}
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(AnyOfValidator::compile(schema, context))
}

View File

@ -11,7 +11,7 @@ use serde_json::Value;
pub(crate) struct FalseValidator {}
impl FalseValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(FalseValidator {}))
}
}

View File

@ -66,7 +66,7 @@ struct ConstBooleanValidator {
}
impl ConstBooleanValidator {
#[inline]
pub(crate) fn compile(value: bool) -> CompilationResult {
pub(crate) fn compile<'a>(value: bool) -> CompilationResult<'a> {
Ok(Box::new(ConstBooleanValidator { value }))
}
}
@ -107,7 +107,7 @@ impl ToString for ConstBooleanValidator {
struct ConstNullValidator {}
impl ConstNullValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(ConstNullValidator {}))
}
}
@ -291,11 +291,11 @@ impl ToString for ConstStringValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
match schema {
Value::Array(items) => Some(ConstArrayValidator::compile(items)),
Value::Bool(item) => Some(ConstBooleanValidator::compile(*item)),

View File

@ -13,7 +13,10 @@ pub(crate) struct ContainsValidator {
impl ContainsValidator {
#[inline]
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult<'a> {
Ok(Box::new(ContainsValidator {
validators: compile_validators(schema, context)?,
}))
@ -68,10 +71,10 @@ impl ToString for ContainsValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(ContainsValidator::compile(schema, context))
}

View File

@ -3,7 +3,7 @@ use crate::{
compilation::{context::CompilationContext, JSONSchema},
content_encoding::{ContentEncodingCheckType, ContentEncodingConverterType},
content_media_type::ContentMediaTypeCheckType,
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -127,12 +127,12 @@ pub(crate) struct ContentMediaTypeAndEncodingValidator {
impl ContentMediaTypeAndEncodingValidator {
#[inline]
pub(crate) fn compile(
media_type: &str,
encoding: &str,
pub(crate) fn compile<'a>(
media_type: &'a str,
encoding: &'a str,
func: ContentMediaTypeCheckType,
converter: ContentEncodingConverterType,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(ContentMediaTypeAndEncodingValidator {
media_type: media_type.to_string(),
encoding: encoding.to_string(),
@ -197,11 +197,11 @@ impl ToString for ContentMediaTypeAndEncodingValidator {
}
#[inline]
pub(crate) fn compile_media_type(
schema: &Map<String, Value>,
subschema: &Value,
pub(crate) fn compile_media_type<'a>(
schema: &'a Map<String, Value>,
subschema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
match subschema {
Value::String(media_type) => {
let func = match context.config.content_media_type_check(media_type.as_str()) {
@ -225,22 +225,22 @@ pub(crate) fn compile_media_type(
converter,
))
}
_ => Some(Err(CompilationError::SchemaError)),
_ => Some(Err(ValidationError::schema(subschema))),
}
} else {
Some(ContentMediaTypeValidator::compile(media_type, func))
}
}
_ => Some(Err(CompilationError::SchemaError)),
_ => Some(Err(ValidationError::schema(subschema))),
}
}
#[inline]
pub(crate) fn compile_content_encoding(
schema: &Map<String, Value>,
subschema: &Value,
pub(crate) fn compile_content_encoding<'a>(
schema: &'a Map<String, Value>,
subschema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
// Performed during media type validation
if schema.get("contentMediaType").is_some() {
// TODO. what if media type is not supported?
@ -257,6 +257,6 @@ pub(crate) fn compile_content_encoding(
};
Some(ContentEncodingValidator::compile(content_encoding, func))
}
_ => Some(Err(CompilationError::SchemaError)),
_ => Some(Err(ValidationError::schema(subschema))),
}
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{compile_validators, context::CompilationContext, JSONSchema},
error::{no_error, CompilationError, ErrorIterator},
error::{no_error, ErrorIterator, ValidationError},
keywords::{format_key_value_validators, required, CompilationResult, Validators},
paths::InstancePath,
validator::Validate,
@ -13,7 +13,10 @@ pub(crate) struct DependenciesValidator {
impl DependenciesValidator {
#[inline]
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult<'a> {
if let Value::Object(map) = schema {
let mut dependencies = Vec::with_capacity(map.len());
for (key, subschema) in map {
@ -28,7 +31,7 @@ impl DependenciesValidator {
}
Ok(Box::new(DependenciesValidator { dependencies }))
} else {
Err(CompilationError::SchemaError)
Err(ValidationError::schema(schema))
}
}
}
@ -84,10 +87,10 @@ impl ToString for DependenciesValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(DependenciesValidator::compile(schema, context))
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::{helpers, CompilationResult},
paths::InstancePath,
primitive_type::{PrimitiveType, PrimitiveTypesBitMap},
@ -18,7 +18,7 @@ pub(crate) struct EnumValidator {
impl EnumValidator {
#[inline]
pub(crate) fn compile(schema: &Value, items: &[Value]) -> CompilationResult {
pub(crate) fn compile<'a>(schema: &'a Value, items: &'a [Value]) -> CompilationResult<'a> {
let mut types = PrimitiveTypesBitMap::new();
for item in items.iter() {
types |= PrimitiveType::from(item);
@ -82,7 +82,7 @@ pub(crate) struct SingleValueEnumValidator {
impl SingleValueEnumValidator {
#[inline]
pub(crate) fn compile(schema: &Value, value: &Value) -> CompilationResult {
pub(crate) fn compile<'a>(schema: &'a Value, value: &'a Value) -> CompilationResult<'a> {
Ok(Box::new(SingleValueEnumValidator {
options: schema.clone(),
value: value.clone(),
@ -120,11 +120,11 @@ impl ToString for SingleValueEnumValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
if let Value::Array(items) = schema {
if items.len() == 1 {
let value = items.iter().next().expect("Vec is not empty");
@ -133,6 +133,6 @@ pub(crate) fn compile(
Some(EnumValidator::compile(schema, items))
}
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::schema(schema)))
}
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -104,11 +104,11 @@ impl ToString for ExclusiveMaximumF64Validator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
if let Value::Number(limit) = schema {
if let Some(limit) = limit.as_u64() {
Some(Ok(Box::new(ExclusiveMaximumU64Validator { limit })))
@ -119,7 +119,7 @@ pub(crate) fn compile(
Some(Ok(Box::new(ExclusiveMaximumF64Validator { limit })))
}
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::schema(schema)))
}
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -102,11 +102,11 @@ impl ToString for ExclusiveMinimumF64Validator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
if let Value::Number(limit) = schema {
if let Some(limit) = limit.as_u64() {
Some(Ok(Box::new(ExclusiveMinimumU64Validator { limit })))
@ -117,7 +117,7 @@ pub(crate) fn compile(
Some(Ok(Box::new(ExclusiveMinimumF64Validator { limit })))
}
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::schema(schema)))
}
}

View File

@ -1,7 +1,7 @@
//! Validator for `format` keyword.
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::{pattern, CompilationResult},
paths::InstancePath,
validator::Validate,
@ -38,7 +38,7 @@ macro_rules! format_validator {
($validator:ident, $format_name:tt) => {
struct $validator {}
impl $validator {
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new($validator {}))
}
}
@ -325,11 +325,11 @@ impl Validate for URITemplateValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
if let Value::String(format) = schema {
let draft_version = context.config.draft();
match format.as_str() {
@ -365,7 +365,7 @@ pub(crate) fn compile(
_ => None,
}
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::schema(schema)))
}
}

View File

@ -14,11 +14,11 @@ pub(crate) struct IfThenValidator {
impl IfThenValidator {
#[inline]
pub(crate) fn compile(
schema: &Value,
then_schema: &Value,
pub(crate) fn compile<'a>(
schema: &'a Value,
then_schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(IfThenValidator {
schema: compile_validators(schema, context)?,
then_schema: compile_validators(then_schema, context)?,
@ -85,7 +85,7 @@ impl IfElseValidator {
schema: &'a Value,
else_schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(IfElseValidator {
schema: compile_validators(schema, context)?,
else_schema: compile_validators(else_schema, context)?,
@ -149,12 +149,12 @@ pub(crate) struct IfThenElseValidator {
impl IfThenElseValidator {
#[inline]
pub(crate) fn compile(
schema: &Value,
then_schema: &Value,
else_schema: &Value,
pub(crate) fn compile<'a>(
schema: &'a Value,
then_schema: &'a Value,
else_schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(IfThenElseValidator {
schema: compile_validators(schema, context)?,
then_schema: compile_validators(then_schema, context)?,
@ -220,11 +220,11 @@ impl ToString for IfThenElseValidator {
}
#[inline]
pub(crate) fn compile(
parent: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
parent: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
let then = parent.get("then");
let else_ = parent.get("else");
match (then, else_) {

View File

@ -12,7 +12,10 @@ pub(crate) struct ItemsArrayValidator {
}
impl ItemsArrayValidator {
#[inline]
pub(crate) fn compile(schemas: &[Value], context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
schemas: &'a [Value],
context: &CompilationContext,
) -> CompilationResult<'a> {
let mut items = Vec::with_capacity(schemas.len());
for item in schemas {
let validators = compile_validators(item, context)?;
@ -72,7 +75,10 @@ pub(crate) struct ItemsObjectValidator {
}
impl ItemsObjectValidator {
#[inline]
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult<'a> {
let validators = compile_validators(schema, context)?;
Ok(Box::new(ItemsObjectValidator { validators }))
}
@ -120,11 +126,11 @@ impl ToString for ItemsObjectValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
match schema {
Value::Array(items) => Some(ItemsArrayValidator::compile(items, context)),
Value::Object(_) => Some(ItemsObjectValidator::compile(schema, context)),

View File

@ -5,11 +5,11 @@ use crate::{
use serde_json::{Map, Value};
#[inline]
pub(crate) fn compile(
parent: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
parent: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
if let Some(Value::Bool(true)) = parent.get("exclusiveMaximum") {
exclusive_maximum::compile(parent, schema, context)
} else {

View File

@ -5,11 +5,11 @@ use crate::{
use serde_json::{Map, Value};
#[inline]
pub(crate) fn compile(
parent: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
parent: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
if let Some(Value::Bool(true)) = parent.get("exclusiveMinimum") {
exclusive_minimum::compile(parent, schema, context)
} else {

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::{type_, CompilationResult},
paths::InstancePath,
primitive_type::{PrimitiveType, PrimitiveTypesBitMap},
@ -23,10 +23,10 @@ impl MultipleTypesValidator {
if let Ok(primitive_type) = PrimitiveType::try_from(string.as_str()) {
types |= primitive_type;
} else {
return Err(CompilationError::SchemaError);
return Err(ValidationError::schema(item));
}
}
_ => return Err(CompilationError::SchemaError),
_ => return Err(ValidationError::schema(item)),
}
}
Ok(Box::new(MultipleTypesValidator { types }))
@ -82,7 +82,7 @@ pub(crate) struct IntegerTypeValidator {}
impl IntegerTypeValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(IntegerTypeValidator {}))
}
}
@ -125,11 +125,11 @@ fn is_integer(num: &Number) -> bool {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
match schema {
Value::String(item) => compile_single_type(item.as_str()),
Value::Array(items) => {
@ -137,17 +137,17 @@ pub(crate) fn compile(
if let Some(Value::String(item)) = items.iter().next() {
compile_single_type(item.as_str())
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::schema(schema)))
}
} else {
Some(MultipleTypesValidator::compile(items))
}
}
_ => Some(Err(CompilationError::SchemaError)),
_ => Some(Err(ValidationError::schema(schema))),
}
}
fn compile_single_type(item: &str) -> Option<CompilationResult> {
fn compile_single_type<'a>(item: &str) -> Option<CompilationResult<'a>> {
match PrimitiveType::try_from(item) {
Ok(PrimitiveType::Array) => Some(type_::ArrayTypeValidator::compile()),
Ok(PrimitiveType::Boolean) => Some(type_::BooleanTypeValidator::compile()),
@ -156,6 +156,6 @@ fn compile_single_type(item: &str) -> Option<CompilationResult> {
Ok(PrimitiveType::Number) => Some(type_::NumberTypeValidator::compile()),
Ok(PrimitiveType::Object) => Some(type_::ObjectTypeValidator::compile()),
Ok(PrimitiveType::String) => Some(type_::StringTypeValidator::compile()),
Err(()) => Some(Err(CompilationError::SchemaError)),
Err(()) => Some(Err(ValidationError::null_schema())),
}
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -17,7 +17,7 @@ impl MaxItemsValidator {
if let Some(limit) = schema.as_u64() {
Ok(Box::new(MaxItemsValidator { limit }))
} else {
Err(CompilationError::SchemaError)
Err(ValidationError::schema(schema))
}
}
}
@ -58,10 +58,10 @@ impl ToString for MaxItemsValidator {
}
#[inline]
pub(crate) fn compile(
pub(crate) fn compile<'a>(
_: &Map<String, Value>,
schema: &Value,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(MaxItemsValidator::compile(schema))
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -17,7 +17,7 @@ impl MaxLengthValidator {
if let Some(limit) = schema.as_u64() {
Ok(Box::new(MaxLengthValidator { limit }))
} else {
Err(CompilationError::SchemaError)
Err(ValidationError::schema(schema))
}
}
}
@ -58,10 +58,10 @@ impl ToString for MaxLengthValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(MaxLengthValidator::compile(schema))
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -17,7 +17,7 @@ impl MaxPropertiesValidator {
if let Some(limit) = schema.as_u64() {
Ok(Box::new(MaxPropertiesValidator { limit }))
} else {
Err(CompilationError::SchemaError)
Err(ValidationError::schema(schema))
}
}
}
@ -58,10 +58,10 @@ impl ToString for MaxPropertiesValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(MaxPropertiesValidator::compile(schema))
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -102,11 +102,11 @@ impl ToString for MaximumF64Validator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
if let Value::Number(limit) = schema {
if let Some(limit) = limit.as_u64() {
Some(Ok(Box::new(MaximumU64Validator { limit })))
@ -117,7 +117,7 @@ pub(crate) fn compile(
Some(Ok(Box::new(MaximumF64Validator { limit })))
}
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::schema(schema)))
}
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -17,7 +17,7 @@ impl MinItemsValidator {
if let Some(limit) = schema.as_u64() {
Ok(Box::new(MinItemsValidator { limit }))
} else {
Err(CompilationError::SchemaError)
Err(ValidationError::schema(schema))
}
}
}
@ -58,10 +58,10 @@ impl ToString for MinItemsValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(MinItemsValidator::compile(schema))
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -17,7 +17,7 @@ impl MinLengthValidator {
if let Some(limit) = schema.as_u64() {
Ok(Box::new(MinLengthValidator { limit }))
} else {
Err(CompilationError::SchemaError)
Err(ValidationError::schema(schema))
}
}
}
@ -58,10 +58,10 @@ impl ToString for MinLengthValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(MinLengthValidator::compile(schema))
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -17,7 +17,7 @@ impl MinPropertiesValidator {
if let Some(limit) = schema.as_u64() {
Ok(Box::new(MinPropertiesValidator { limit }))
} else {
Err(CompilationError::SchemaError)
Err(ValidationError::schema(schema))
}
}
}
@ -58,10 +58,10 @@ impl ToString for MinPropertiesValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(MinPropertiesValidator::compile(schema))
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -102,11 +102,11 @@ impl ToString for MinimumF64Validator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
if let Value::Number(limit) = schema {
if let Some(limit) = limit.as_u64() {
Some(Ok(Box::new(MinimumU64Validator { limit })))
@ -117,7 +117,7 @@ pub(crate) fn compile(
Some(Ok(Box::new(MinimumF64Validator { limit })))
}
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::schema(schema)))
}
}

View File

@ -36,7 +36,7 @@ pub(crate) mod type_;
pub(crate) mod unique_items;
use crate::{error, validator::Validate};
pub(crate) type CompilationResult = Result<BoxedValidator, error::CompilationError>;
pub(crate) type CompilationResult<'a> = Result<BoxedValidator, error::ValidationError<'a>>;
pub(crate) type BoxedValidator = Box<dyn Validate + Send + Sync>;
pub(crate) type Validators = Vec<BoxedValidator>;

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -15,7 +15,7 @@ pub(crate) struct MultipleOfFloatValidator {
impl MultipleOfFloatValidator {
#[inline]
pub(crate) fn compile(multiple_of: f64) -> CompilationResult {
pub(crate) fn compile<'a>(multiple_of: f64) -> CompilationResult<'a> {
Ok(Box::new(MultipleOfFloatValidator { multiple_of }))
}
}
@ -67,7 +67,7 @@ pub(crate) struct MultipleOfIntegerValidator {
impl MultipleOfIntegerValidator {
#[inline]
pub(crate) fn compile(multiple_of: f64) -> CompilationResult {
pub(crate) fn compile<'a>(multiple_of: f64) -> CompilationResult<'a> {
Ok(Box::new(MultipleOfIntegerValidator { multiple_of }))
}
}
@ -112,11 +112,11 @@ impl ToString for MultipleOfIntegerValidator {
}
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
if let Value::Number(multiple_of) = schema {
let multiple_of = multiple_of.as_f64().expect("Always valid");
if multiple_of.fract() == 0. {
@ -125,6 +125,6 @@ pub(crate) fn compile(
Some(MultipleOfFloatValidator::compile(multiple_of))
}
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::schema(schema)))
}
}

View File

@ -15,7 +15,10 @@ pub(crate) struct NotValidator {
impl NotValidator {
#[inline]
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult<'a> {
Ok(Box::new(NotValidator {
original: schema.clone(),
validators: compile_validators(schema, context)?,
@ -56,10 +59,10 @@ impl ToString for NotValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(NotValidator::compile(schema, context))
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{compile_validators, context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::{format_vec_of_validators, CompilationResult, Validators},
paths::InstancePath,
validator::Validate,
@ -13,7 +13,10 @@ pub(crate) struct OneOfValidator {
impl OneOfValidator {
#[inline]
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult<'a> {
if let Value::Array(items) = schema {
let mut schemas = Vec::with_capacity(items.len());
for item in items {
@ -21,7 +24,7 @@ impl OneOfValidator {
}
Ok(Box::new(OneOfValidator { schemas }))
} else {
Err(CompilationError::SchemaError)
Err(ValidationError::schema(schema))
}
}
@ -92,10 +95,10 @@ impl ToString for OneOfValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(OneOfValidator::compile(schema, context))
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -24,13 +24,16 @@ impl PatternValidator {
pub(crate) fn compile(pattern: &Value) -> CompilationResult {
match pattern {
Value::String(item) => {
let pattern = convert_regex(item)?;
let pattern = match convert_regex(item) {
Ok(r) => r,
Err(_) => return Err(ValidationError::schema(pattern)),
};
Ok(Box::new(PatternValidator {
original: item.clone(),
pattern,
}))
}
_ => Err(CompilationError::SchemaError),
_ => Err(ValidationError::schema(pattern)),
}
}
}
@ -137,11 +140,11 @@ fn replace_control_group(captures: &regex::Captures) -> String {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(PatternValidator::compile(schema))
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{compile_validators, context::CompilationContext, JSONSchema},
error::{no_error, CompilationError, ErrorIterator},
error::{no_error, ErrorIterator, ValidationError},
keywords::{format_validators, CompilationResult, Validators},
paths::InstancePath,
validator::Validate,
@ -14,14 +14,17 @@ pub(crate) struct PatternPropertiesValidator {
impl PatternPropertiesValidator {
#[inline]
pub(crate) fn compile(
map: &Map<String, Value>,
pub(crate) fn compile<'a>(
map: &'a Map<String, Value>,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
let mut patterns = Vec::with_capacity(map.len());
for (pattern, subschema) in map {
patterns.push((
Regex::new(pattern)?,
match Regex::new(pattern) {
Ok(r) => r,
Err(_) => return Err(ValidationError::schema(subschema)),
},
compile_validators(subschema, context)?,
));
}
@ -94,13 +97,16 @@ pub(crate) struct SingleValuePatternPropertiesValidator {
impl SingleValuePatternPropertiesValidator {
#[inline]
pub(crate) fn compile(
pattern: &str,
schema: &Value,
pub(crate) fn compile<'a>(
pattern: &'a str,
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult {
) -> CompilationResult<'a> {
Ok(Box::new(SingleValuePatternPropertiesValidator {
pattern: Regex::new(pattern)?,
pattern: match Regex::new(pattern) {
Ok(r) => r,
Err(_) => return Err(ValidationError::schema(schema)),
},
validators: compile_validators(schema, context)?,
}))
}
@ -156,11 +162,11 @@ impl ToString for SingleValuePatternPropertiesValidator {
}
#[inline]
pub(crate) fn compile(
parent: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
parent: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
match parent.get("additionalProperties") {
// This type of `additionalProperties` validator handles `patternProperties` logic
Some(Value::Bool(false)) | Some(Value::Object(_)) => None,
@ -175,7 +181,7 @@ pub(crate) fn compile(
Some(PatternPropertiesValidator::compile(map, context))
}
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::schema(schema)))
}
}
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{compile_validators, context::CompilationContext, JSONSchema},
error::{no_error, CompilationError, ErrorIterator},
error::{no_error, ErrorIterator, ValidationError},
keywords::{format_key_value_validators, CompilationResult, Validators},
paths::InstancePath,
validator::Validate,
@ -13,7 +13,10 @@ pub(crate) struct PropertiesValidator {
impl PropertiesValidator {
#[inline]
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult<'a> {
match schema {
Value::Object(map) => {
let mut properties = Vec::with_capacity(map.len());
@ -22,7 +25,7 @@ impl PropertiesValidator {
}
Ok(Box::new(PropertiesValidator { properties }))
}
_ => Err(CompilationError::SchemaError),
_ => Err(ValidationError::schema(schema)),
}
}
}
@ -80,11 +83,11 @@ impl ToString for PropertiesValidator {
}
#[inline]
pub(crate) fn compile(
parent: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
parent: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
match parent.get("additionalProperties") {
// This type of `additionalProperties` validator handles `properties` logic
Some(Value::Bool(false)) | Some(Value::Object(_)) => None,

View File

@ -14,7 +14,10 @@ pub(crate) struct PropertyNamesObjectValidator {
impl PropertyNamesObjectValidator {
#[inline]
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
schema: &'a Value,
context: &CompilationContext,
) -> CompilationResult<'a> {
Ok(Box::new(PropertyNamesObjectValidator {
validators: compile_validators(schema, context)?,
}))
@ -78,7 +81,7 @@ pub(crate) struct PropertyNamesBooleanValidator {}
impl PropertyNamesBooleanValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(PropertyNamesBooleanValidator {}))
}
}
@ -117,11 +120,11 @@ impl ToString for PropertyNamesBooleanValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
match schema {
Value::Object(_) => Some(PropertyNamesObjectValidator::compile(schema, context)),
Value::Bool(false) => Some(PropertyNamesBooleanValidator::compile()),

View File

@ -2,6 +2,7 @@ use crate::{
compilation::{compile_validators, context::CompilationContext, JSONSchema},
error::{error, ErrorIterator},
keywords::{CompilationResult, Validators},
paths::InstancePath,
validator::Validate,
};
use parking_lot::RwLock;
@ -9,8 +10,6 @@ use serde_json::Value;
use std::borrow::Cow;
use url::Url;
use crate::paths::InstancePath;
pub(crate) struct RefValidator {
reference: Url,
/// Precomputed validators.
@ -23,7 +22,10 @@ pub(crate) struct RefValidator {
impl RefValidator {
#[inline]
pub(crate) fn compile(reference: &str, context: &CompilationContext) -> CompilationResult {
pub(crate) fn compile<'a>(
reference: &str,
context: &CompilationContext,
) -> CompilationResult<'a> {
let reference = context.build_url(reference)?;
Ok(Box::new(RefValidator {
reference,
@ -92,7 +94,7 @@ impl Validate for RefValidator {
*self.validators.write() = Some(validators);
result
}
Err(err) => error(err.into()),
Err(err) => error(err.into_owned()),
}
}
Err(err) => error(err),
@ -107,10 +109,10 @@ impl ToString for RefValidator {
}
#[inline]
pub(crate) fn compile(
_: &Value,
reference: &str,
pub(crate) fn compile<'a>(
_: &'a Value,
reference: &'a str,
context: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
Some(RefValidator::compile(reference, context))
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
paths::InstancePath,
validator::Validate,
@ -18,7 +18,7 @@ impl RequiredValidator {
for item in items {
match item {
Value::String(string) => required.push(string.clone()),
_ => return Err(CompilationError::SchemaError),
_ => return Err(ValidationError::schema(item)),
}
}
Ok(Box::new(RequiredValidator { required }))
@ -115,11 +115,11 @@ impl ToString for SingleItemRequiredValidator {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
// IMPORTANT: If this function will ever return `None`, adjust `dependencies.rs` accordingly
match schema {
Value::Array(items) => {
@ -127,12 +127,12 @@ pub(crate) fn compile(
if let Some(Value::String(item)) = items.iter().next() {
Some(SingleItemRequiredValidator::compile(item))
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::schema(schema)))
}
} else {
Some(RequiredValidator::compile(items))
}
}
_ => Some(Err(CompilationError::SchemaError)),
_ => Some(Err(ValidationError::schema(schema))),
}
}

View File

@ -1,6 +1,6 @@
use crate::{
compilation::{context::CompilationContext, JSONSchema},
error::{error, no_error, CompilationError, ErrorIterator, ValidationError},
error::{error, no_error, ErrorIterator, ValidationError},
keywords::CompilationResult,
primitive_type::{PrimitiveType, PrimitiveTypesBitMap},
validator::Validate,
@ -24,10 +24,10 @@ impl MultipleTypesValidator {
if let Ok(primitive_type) = PrimitiveType::try_from(string.as_str()) {
types |= primitive_type;
} else {
return Err(CompilationError::SchemaError);
return Err(ValidationError::schema(item));
}
}
_ => return Err(CompilationError::SchemaError),
_ => return Err(ValidationError::schema(item)),
}
}
Ok(Box::new(MultipleTypesValidator { types }))
@ -83,7 +83,7 @@ pub(crate) struct NullTypeValidator {}
impl NullTypeValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(NullTypeValidator {}))
}
}
@ -120,7 +120,7 @@ pub(crate) struct BooleanTypeValidator {}
impl BooleanTypeValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(BooleanTypeValidator {}))
}
}
@ -157,7 +157,7 @@ pub(crate) struct StringTypeValidator {}
impl StringTypeValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(StringTypeValidator {}))
}
}
@ -194,7 +194,7 @@ pub(crate) struct ArrayTypeValidator {}
impl ArrayTypeValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(ArrayTypeValidator {}))
}
}
@ -232,7 +232,7 @@ pub(crate) struct ObjectTypeValidator {}
impl ObjectTypeValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(ObjectTypeValidator {}))
}
}
@ -269,7 +269,7 @@ pub(crate) struct NumberTypeValidator {}
impl NumberTypeValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(NumberTypeValidator {}))
}
}
@ -304,7 +304,7 @@ pub(crate) struct IntegerTypeValidator {}
impl IntegerTypeValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(IntegerTypeValidator {}))
}
}
@ -346,11 +346,11 @@ fn is_integer(num: &Number) -> bool {
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
match schema {
Value::String(item) => compile_single_type(item.as_str()),
Value::Array(items) => {
@ -358,13 +358,13 @@ pub(crate) fn compile(
if let Some(Value::String(item)) = items.iter().next() {
compile_single_type(item.as_str())
} else {
Some(Err(CompilationError::SchemaError))
Some(Err(ValidationError::schema(schema)))
}
} else {
Some(MultipleTypesValidator::compile(items))
}
}
_ => Some(Err(CompilationError::SchemaError)),
_ => Some(Err(ValidationError::schema(schema))),
}
}
@ -377,6 +377,6 @@ fn compile_single_type(item: &str) -> Option<CompilationResult> {
Ok(PrimitiveType::Number) => Some(NumberTypeValidator::compile()),
Ok(PrimitiveType::Object) => Some(ObjectTypeValidator::compile()),
Ok(PrimitiveType::String) => Some(StringTypeValidator::compile()),
Err(()) => Some(Err(CompilationError::SchemaError)),
Err(()) => Some(Err(ValidationError::null_schema())),
}
}

View File

@ -86,7 +86,7 @@ pub(crate) struct UniqueItemsValidator {}
impl UniqueItemsValidator {
#[inline]
pub(crate) fn compile() -> CompilationResult {
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
Ok(Box::new(UniqueItemsValidator {}))
}
}
@ -124,11 +124,11 @@ impl ToString for UniqueItemsValidator {
}
}
#[inline]
pub(crate) fn compile(
_: &Map<String, Value>,
schema: &Value,
pub(crate) fn compile<'a>(
_: &'a Map<String, Value>,
schema: &'a Value,
_: &CompilationContext,
) -> Option<CompilationResult> {
) -> Option<CompilationResult<'a>> {
if let Value::Bool(value) = schema {
if *value {
Some(UniqueItemsValidator::compile())

View File

@ -11,46 +11,43 @@
//! A schema can be compiled with two main flavours:
//! * using default configurations
//! ```rust
//! # use jsonschema::{CompilationError, Draft, JSONSchema};
//! # use jsonschema::{Draft, JSONSchema};
//! # use serde_json::json;
//! # fn foo() -> Result<(), CompilationError> {
//! # fn foo() {
//! # let schema = json!({"maxLength": 5});
//! let compiled_schema = JSONSchema::compile(&schema)?;
//! # Ok(())
//! let compiled_schema = JSONSchema::compile(&schema).expect("A valid schema");
//! # }
//! ```
//! * using custom configurations (such as define a Draft version)
//! ```rust
//! # use jsonschema::{CompilationError, Draft, JSONSchema};
//! # use jsonschema::{Draft, JSONSchema};
//! # use serde_json::json;
//! # fn foo() -> Result<(), CompilationError> {
//! # fn foo() {
//! # let schema = json!({"maxLength": 5});
//! let compiled_schema = JSONSchema::options()
//! .with_draft(Draft::Draft7)
//! .compile(&schema)?;
//! # Ok(())
//! .compile(&schema)
//! .expect("A valid schema");
//! # }
//! ```
//!
//! ## Example (CLI tool to highlight print errors)
//! ```rust
//! use jsonschema::{CompilationError, Draft, JSONSchema};
//! use jsonschema::{Draft, JSONSchema};
//! use serde_json::json;
//!
//! fn main() -> Result<(), CompilationError> {
//! let schema = json!({"maxLength": 5});
//! let instance = json!("foo");
//! let compiled = JSONSchema::options()
//! .with_draft(Draft::Draft7)
//! .compile(&schema)?;
//! let result = compiled.validate(&instance);
//! if let Err(errors) = result {
//! for error in errors {
//! println!("Validation error: {}", error);
//! println!("Instance path: {}", error.instance_path);
//! }
//! let schema = json!({"maxLength": 5});
//! let instance = json!("foo");
//! let compiled = JSONSchema::options()
//! .with_draft(Draft::Draft7)
//! .compile(&schema)
//! .expect("A valid schema");
//! let result = compiled.validate(&instance);
//! if let Err(errors) = result {
//! for error in errors {
//! println!("Validation error: {}", error);
//! println!("Instance path: {}", error.instance_path);
//! }
//! Ok(())
//! }
//! ```
//! Each error has an `instance_path` attribute that indicates the path to the erroneous part within the validated instance.
@ -91,7 +88,7 @@ mod schemas;
mod validator;
pub use compilation::{options::CompilationOptions, JSONSchema};
pub use error::{CompilationError, ErrorIterator, ValidationError};
pub use error::{ErrorIterator, ValidationError};
pub use schemas::Draft;
use serde_json::Value;

View File

@ -48,25 +48,30 @@ fn validate_instances(instances: &[PathBuf], schema: PathBuf) -> BoxErrorResult<
let schema_json = fs::read_to_string(schema)?;
let schema_json = serde_json::from_str(&schema_json)?;
let schema = JSONSchema::compile(&schema_json)?;
match JSONSchema::compile(&schema_json) {
Ok(schema) => {
for instance in instances {
let instance_path_name = instance.to_str().unwrap();
let instance_json = fs::read_to_string(&instance)?;
let instance_json = serde_json::from_str(&instance_json)?;
let validation = schema.validate(&instance_json);
match validation {
Ok(_) => println!("{} - VALID", instance_path_name),
Err(errors) => {
success = false;
for instance in instances {
let instance_path_name = instance.to_str().unwrap();
let instance_json = fs::read_to_string(&instance)?;
let instance_json = serde_json::from_str(&instance_json)?;
let validation = schema.validate(&instance_json);
match validation {
Ok(_) => println!("{} - VALID", instance_path_name),
Err(errors) => {
success = false;
println!("{} - INVALID. Errors:", instance_path_name);
for (i, e) in errors.enumerate() {
println!("{}. {}", i + 1, e);
println!("{} - INVALID. Errors:", instance_path_name);
for (i, e) in errors.enumerate() {
println!("{}. {}", i + 1, e);
}
}
}
}
}
Err(error) => {
println!("Schema is invalid. Error: {}", error);
success = false;
}
}
Ok(success)
}

View File

@ -2,7 +2,7 @@
//! Is able to load documents from remote locations via HTTP(S).
use crate::{
compilation::{DEFAULT_ROOT_URL, DEFAULT_SCOPE},
error::{CompilationError, ValidationError},
error::ValidationError,
schemas::{id_of, Draft},
};
use ahash::AHashMap;
@ -26,7 +26,7 @@ impl<'a> Resolver<'a> {
scope: &Url,
schema: &'a Value,
store: AHashMap<String, Value>,
) -> Result<Resolver<'a>, CompilationError> {
) -> Result<Resolver<'a>, ValidationError<'a>> {
let mut schemas = AHashMap::new();
// traverse the schema and store all named ones under their canonical ids
find_schemas(draft, schema, scope, &mut |id, schema| {

View File

@ -2,7 +2,7 @@ use crate::{compilation::context::CompilationContext, keywords};
use serde_json::{Map, Value};
/// JSON Schema Draft version
#[derive(Debug, PartialEq, Copy, Clone)]
#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)]
pub enum Draft {
/// JSON Schema Draft 4
Draft4,
@ -18,8 +18,11 @@ impl Default for Draft {
}
}
type CompileFunc =
fn(&Map<String, Value>, &Value, &CompilationContext) -> Option<keywords::CompilationResult>;
type CompileFunc<'a> = fn(
&'a Map<String, Value>,
&'a Value,
&CompilationContext,
) -> Option<keywords::CompilationResult<'a>>;
impl Draft {
pub(crate) fn get_validator(self, keyword: &str) -> Option<CompileFunc> {