From 5dbca06e61f1cd212a9e000b0771c424a892ebe6 Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Sat, 26 Oct 2024 19:20:45 +0200 Subject: [PATCH] refactor: Use enum dispatch Signed-off-by: Dmitry Dygalo --- crates/jsonschema/src/compiler.rs | 6 +- .../src/keywords/additional_items.rs | 14 +- .../src/keywords/additional_properties.rs | 99 ++++---- crates/jsonschema/src/keywords/all_of.rs | 8 +- crates/jsonschema/src/keywords/any_of.rs | 5 +- crates/jsonschema/src/keywords/boolean.rs | 2 +- crates/jsonschema/src/keywords/const_.rs | 32 +-- crates/jsonschema/src/keywords/contains.rs | 36 +-- crates/jsonschema/src/keywords/content.rs | 15 +- .../jsonschema/src/keywords/dependencies.rs | 6 +- crates/jsonschema/src/keywords/enum_.rs | 10 +- .../src/keywords/exclusive_maximum.rs | 15 +- .../src/keywords/exclusive_minimum.rs | 15 +- crates/jsonschema/src/keywords/format.rs | 12 +- crates/jsonschema/src/keywords/if_.rs | 9 +- crates/jsonschema/src/keywords/items.rs | 17 +- .../src/keywords/legacy/type_draft_4.rs | 4 +- crates/jsonschema/src/keywords/max_items.rs | 7 +- crates/jsonschema/src/keywords/max_length.rs | 7 +- .../jsonschema/src/keywords/max_properties.rs | 7 +- crates/jsonschema/src/keywords/maximum.rs | 15 +- crates/jsonschema/src/keywords/min_items.rs | 7 +- crates/jsonschema/src/keywords/min_length.rs | 7 +- .../jsonschema/src/keywords/min_properties.rs | 7 +- crates/jsonschema/src/keywords/minimum.rs | 15 +- crates/jsonschema/src/keywords/mod.rs | 211 +++++++++++++++++- crates/jsonschema/src/keywords/multiple_of.rs | 10 +- crates/jsonschema/src/keywords/not.rs | 9 +- crates/jsonschema/src/keywords/one_of.rs | 5 +- crates/jsonschema/src/keywords/pattern.rs | 5 +- .../src/keywords/pattern_properties.rs | 11 +- .../jsonschema/src/keywords/prefix_items.rs | 2 +- crates/jsonschema/src/keywords/properties.rs | 2 +- .../jsonschema/src/keywords/property_names.rs | 11 +- crates/jsonschema/src/keywords/ref_.rs | 21 +- crates/jsonschema/src/keywords/required.rs | 7 +- crates/jsonschema/src/keywords/type_.rs | 16 +- .../src/keywords/unevaluated_items.rs | 59 +++-- .../src/keywords/unevaluated_properties.rs | 58 +++-- .../jsonschema/src/keywords/unique_items.rs | 2 +- crates/jsonschema/src/node.rs | 63 ++---- crates/jsonschema/src/paths.rs | 10 +- 42 files changed, 575 insertions(+), 304 deletions(-) diff --git a/crates/jsonschema/src/compiler.rs b/crates/jsonschema/src/compiler.rs index 1ef998b7..36b18a47 100644 --- a/crates/jsonschema/src/compiler.rs +++ b/crates/jsonschema/src/compiler.rs @@ -5,7 +5,7 @@ use crate::{ self, custom::{CustomKeyword, KeywordFactory}, format::Format, - BoxedValidator, BuiltinKeyword, Keyword, + BuiltinKeyword, KeywordKind, KeywordValue, }, node::SchemaNode, options::ValidationOptions, @@ -400,8 +400,8 @@ pub(crate) fn compile_with<'a>( if let Some(factory) = ctx.get_keyword_factory(keyword) { let path = ctx.location().join(keyword); let validator = CustomKeyword::new(factory.init(schema, value, path)?); - let validator: BoxedValidator = Box::new(validator); - validators.push((Keyword::custom(keyword), validator)); + let validator: KeywordValue = validator.into(); + validators.push((KeywordKind::custom(keyword), validator)); } else if let Some((keyword, validator)) = keywords::get_for_draft(ctx, keyword) .and_then(|(keyword, f)| f(ctx, schema, value).map(|v| (keyword, v))) { diff --git a/crates/jsonschema/src/keywords/additional_items.rs b/crates/jsonschema/src/keywords/additional_items.rs index 69c041c0..125fa9f0 100644 --- a/crates/jsonschema/src/keywords/additional_items.rs +++ b/crates/jsonschema/src/keywords/additional_items.rs @@ -10,7 +10,7 @@ use crate::{ use serde_json::{Map, Value}; pub(crate) struct AdditionalItemsObjectValidator { - node: SchemaNode, + node: Box, items_count: usize, } impl AdditionalItemsObjectValidator { @@ -20,11 +20,8 @@ impl AdditionalItemsObjectValidator { schema: &'a Value, items_count: usize, ) -> CompilationResult<'a> { - let node = compiler::compile(ctx, ctx.as_resource_ref(schema))?; - Ok(Box::new(AdditionalItemsObjectValidator { - node, - items_count, - })) + let node = Box::new(compiler::compile(ctx, ctx.as_resource_ref(schema))?); + Ok(AdditionalItemsObjectValidator { node, items_count }.into()) } } impl Validate for AdditionalItemsObjectValidator { @@ -75,10 +72,11 @@ pub(crate) struct AdditionalItemsBooleanValidator { impl AdditionalItemsBooleanValidator { #[inline] pub(crate) fn compile<'a>(items_count: usize, location: Location) -> CompilationResult<'a> { - Ok(Box::new(AdditionalItemsBooleanValidator { + Ok(AdditionalItemsBooleanValidator { items_count, location, - })) + } + .into()) } } impl Validate for AdditionalItemsBooleanValidator { diff --git a/crates/jsonschema/src/keywords/additional_properties.rs b/crates/jsonschema/src/keywords/additional_properties.rs index 61031812..4191eb01 100644 --- a/crates/jsonschema/src/keywords/additional_properties.rs +++ b/crates/jsonschema/src/keywords/additional_properties.rs @@ -78,15 +78,16 @@ macro_rules! iter_errors { /// } /// ``` pub(crate) struct AdditionalPropertiesValidator { - node: SchemaNode, + node: Box, } impl AdditionalPropertiesValidator { #[inline] pub(crate) fn compile<'a>(schema: &'a Value, ctx: &compiler::Context) -> CompilationResult<'a> { let ctx = ctx.new_at_location("additionalProperties"); - Ok(Box::new(AdditionalPropertiesValidator { - node: compiler::compile(&ctx, ctx.as_resource_ref(schema))?, - })) + Ok(AdditionalPropertiesValidator { + node: Box::new(compiler::compile(&ctx, ctx.as_resource_ref(schema))?), + } + .into()) } } impl Validate for AdditionalPropertiesValidator { @@ -161,7 +162,7 @@ pub(crate) struct AdditionalPropertiesFalseValidator { impl AdditionalPropertiesFalseValidator { #[inline] pub(crate) fn compile<'a>(location: Location) -> CompilationResult<'a> { - Ok(Box::new(AdditionalPropertiesFalseValidator { location })) + Ok(AdditionalPropertiesFalseValidator { location }.into()) } } impl Validate for AdditionalPropertiesFalseValidator { @@ -219,10 +220,11 @@ impl AdditionalPropertiesNotEmptyFalseValidator { map: &'a Map, ctx: &compiler::Context, ) -> CompilationResult<'a> { - Ok(Box::new(AdditionalPropertiesNotEmptyFalseValidator { + Ok(AdditionalPropertiesNotEmptyFalseValidator { properties: compile_small_map(ctx, map)?, location: ctx.location().join("additionalProperties"), - })) + } + .into()) } } impl AdditionalPropertiesNotEmptyFalseValidator { @@ -231,10 +233,11 @@ impl AdditionalPropertiesNotEmptyFalseValidator { map: &'a Map, ctx: &compiler::Context, ) -> CompilationResult<'a> { - Ok(Box::new(AdditionalPropertiesNotEmptyFalseValidator { + Ok(AdditionalPropertiesNotEmptyFalseValidator { properties: compile_big_map(ctx, map)?, location: ctx.location().join("additionalProperties"), - })) + } + .into()) } } impl Validate for AdditionalPropertiesNotEmptyFalseValidator { @@ -354,7 +357,7 @@ impl core::fmt::Display /// } /// ``` pub(crate) struct AdditionalPropertiesNotEmptyValidator { - node: SchemaNode, + node: Box, properties: M, } impl AdditionalPropertiesNotEmptyValidator { @@ -365,10 +368,11 @@ impl AdditionalPropertiesNotEmptyValidator { schema: &'a Value, ) -> CompilationResult<'a> { let kctx = ctx.new_at_location("additionalProperties"); - Ok(Box::new(AdditionalPropertiesNotEmptyValidator { + Ok(AdditionalPropertiesNotEmptyValidator { properties: compile_small_map(ctx, map)?, - node: compiler::compile(&kctx, kctx.as_resource_ref(schema))?, - })) + node: Box::new(compiler::compile(&kctx, kctx.as_resource_ref(schema))?), + } + .into()) } } impl AdditionalPropertiesNotEmptyValidator { @@ -379,10 +383,11 @@ impl AdditionalPropertiesNotEmptyValidator { schema: &'a Value, ) -> CompilationResult<'a> { let kctx = ctx.new_at_location("additionalProperties"); - Ok(Box::new(AdditionalPropertiesNotEmptyValidator { + Ok(AdditionalPropertiesNotEmptyValidator { properties: compile_big_map(ctx, map)?, - node: compiler::compile(&kctx, kctx.as_resource_ref(schema))?, - })) + node: Box::new(compiler::compile(&kctx, kctx.as_resource_ref(schema))?), + } + .into()) } } impl Validate for AdditionalPropertiesNotEmptyValidator { @@ -479,7 +484,7 @@ impl Validate for AdditionalPropertiesNotEmptyValida /// } /// ``` pub(crate) struct AdditionalPropertiesWithPatternsValidator { - node: SchemaNode, + node: Box, patterns: PatternedValidators, /// We need this because `compiler::compile` uses the additionalProperties keyword to compile /// this validator. That means that the schema node which contains this validator has @@ -496,12 +501,13 @@ impl AdditionalPropertiesWithPatternsValidator { patterns: PatternedValidators, ) -> CompilationResult<'a> { let kctx = ctx.new_at_location("additionalProperties"); - Ok(Box::new(AdditionalPropertiesWithPatternsValidator { - node: compiler::compile(&kctx, kctx.as_resource_ref(schema))?, + Ok(AdditionalPropertiesWithPatternsValidator { + node: Box::new(compiler::compile(&kctx, kctx.as_resource_ref(schema))?), patterns, pattern_keyword_path: ctx.location().join("patternProperties"), pattern_keyword_absolute_location: ctx.new_at_location("patternProperties").base_uri(), - })) + } + .into()) } } impl Validate for AdditionalPropertiesWithPatternsValidator { @@ -642,12 +648,13 @@ impl AdditionalPropertiesWithPatternsFalseValidator { ctx: &compiler::Context, patterns: PatternedValidators, ) -> CompilationResult<'a> { - Ok(Box::new(AdditionalPropertiesWithPatternsFalseValidator { + Ok(AdditionalPropertiesWithPatternsFalseValidator { patterns, location: ctx.location().join("additionalProperties"), pattern_keyword_path: ctx.location().join("patternProperties"), pattern_keyword_absolute_location: ctx.new_at_location("patternProperties").base_uri(), - })) + } + .into()) } } impl Validate for AdditionalPropertiesWithPatternsFalseValidator { @@ -795,7 +802,7 @@ impl Validate for AdditionalPropertiesWithPatternsFalseValidator { /// } /// ``` pub(crate) struct AdditionalPropertiesWithPatternsNotEmptyValidator { - node: SchemaNode, + node: Box, properties: M, patterns: PatternedValidators, } @@ -808,13 +815,12 @@ impl AdditionalPropertiesWithPatternsNotEmptyValidator { patterns: PatternedValidators, ) -> CompilationResult<'a> { let kctx = ctx.new_at_location("additionalProperties"); - Ok(Box::new( - AdditionalPropertiesWithPatternsNotEmptyValidator { - node: compiler::compile(&kctx, kctx.as_resource_ref(schema))?, - properties: compile_small_map(ctx, map)?, - patterns, - }, - )) + Ok(AdditionalPropertiesWithPatternsNotEmptyValidator { + node: Box::new(compiler::compile(&kctx, kctx.as_resource_ref(schema))?), + properties: compile_small_map(ctx, map)?, + patterns, + } + .into()) } } impl AdditionalPropertiesWithPatternsNotEmptyValidator { @@ -826,13 +832,12 @@ impl AdditionalPropertiesWithPatternsNotEmptyValidator { patterns: PatternedValidators, ) -> CompilationResult<'a> { let kctx = ctx.new_at_location("additionalProperties"); - Ok(Box::new( - AdditionalPropertiesWithPatternsNotEmptyValidator { - node: compiler::compile(&kctx, kctx.as_resource_ref(schema))?, - properties: compile_big_map(ctx, map)?, - patterns, - }, - )) + Ok(AdditionalPropertiesWithPatternsNotEmptyValidator { + node: Box::new(compiler::compile(&kctx, kctx.as_resource_ref(schema))?), + properties: compile_big_map(ctx, map)?, + patterns, + } + .into()) } } impl Validate for AdditionalPropertiesWithPatternsNotEmptyValidator { @@ -1012,13 +1017,14 @@ impl AdditionalPropertiesWithPatternsNotEmptyFalseValidator ctx: &compiler::Context, patterns: PatternedValidators, ) -> CompilationResult<'a> { - Ok(Box::new( + Ok( AdditionalPropertiesWithPatternsNotEmptyFalseValidator:: { properties: compile_small_map(ctx, map)?, patterns, location: ctx.location().join("additionalProperties"), - }, - )) + } + .into(), + ) } } impl AdditionalPropertiesWithPatternsNotEmptyFalseValidator { @@ -1028,13 +1034,12 @@ impl AdditionalPropertiesWithPatternsNotEmptyFalseValidator { ctx: &compiler::Context, patterns: PatternedValidators, ) -> CompilationResult<'a> { - Ok(Box::new( - AdditionalPropertiesWithPatternsNotEmptyFalseValidator { - properties: compile_big_map(ctx, map)?, - patterns, - location: ctx.location().join("additionalProperties"), - }, - )) + Ok(AdditionalPropertiesWithPatternsNotEmptyFalseValidator { + properties: compile_big_map(ctx, map)?, + patterns, + location: ctx.location().join("additionalProperties"), + } + .into()) } } diff --git a/crates/jsonschema/src/keywords/all_of.rs b/crates/jsonschema/src/keywords/all_of.rs index 6462f24d..82b21f86 100644 --- a/crates/jsonschema/src/keywords/all_of.rs +++ b/crates/jsonschema/src/keywords/all_of.rs @@ -28,7 +28,7 @@ impl AllOfValidator { let validators = compiler::compile(&ctx, ctx.as_resource_ref(item))?; schemas.push(validators) } - Ok(Box::new(AllOfValidator { schemas })) + Ok(AllOfValidator { schemas }.into()) } } @@ -68,7 +68,7 @@ impl Validate for AllOfValidator { } pub(crate) struct SingleValueAllOfValidator { - node: SchemaNode, + node: Box, } impl SingleValueAllOfValidator { @@ -76,8 +76,8 @@ impl SingleValueAllOfValidator { pub(crate) fn compile<'a>(ctx: &compiler::Context, schema: &'a Value) -> CompilationResult<'a> { let ctx = ctx.new_at_location("allOf"); let ctx = ctx.new_at_location(0); - let node = compiler::compile(&ctx, ctx.as_resource_ref(schema))?; - Ok(Box::new(SingleValueAllOfValidator { node })) + let node = Box::new(compiler::compile(&ctx, ctx.as_resource_ref(schema))?); + Ok(SingleValueAllOfValidator { node }.into()) } } diff --git a/crates/jsonschema/src/keywords/any_of.rs b/crates/jsonschema/src/keywords/any_of.rs index cf296947..4343ba1b 100644 --- a/crates/jsonschema/src/keywords/any_of.rs +++ b/crates/jsonschema/src/keywords/any_of.rs @@ -26,10 +26,11 @@ impl AnyOfValidator { let node = compiler::compile(&ctx, ctx.as_resource_ref(item))?; schemas.push(node) } - Ok(Box::new(AnyOfValidator { + Ok(AnyOfValidator { schemas, location: ctx.location().clone(), - })) + } + .into()) } else { Err(ValidationError::single_type_error( Location::new(), diff --git a/crates/jsonschema/src/keywords/boolean.rs b/crates/jsonschema/src/keywords/boolean.rs index f1c223d5..46278ee1 100644 --- a/crates/jsonschema/src/keywords/boolean.rs +++ b/crates/jsonschema/src/keywords/boolean.rs @@ -9,7 +9,7 @@ pub(crate) struct FalseValidator { impl FalseValidator { #[inline] pub(crate) fn compile<'a>(location: Location) -> CompilationResult<'a> { - Ok(Box::new(FalseValidator { location })) + Ok(FalseValidator { location }.into()) } } impl Validate for FalseValidator { diff --git a/crates/jsonschema/src/keywords/const_.rs b/crates/jsonschema/src/keywords/const_.rs index 670262a0..f074497a 100644 --- a/crates/jsonschema/src/keywords/const_.rs +++ b/crates/jsonschema/src/keywords/const_.rs @@ -9,17 +9,18 @@ use serde_json::{Map, Number, Value}; use crate::paths::LazyLocation; -struct ConstArrayValidator { +pub(crate) struct ConstArrayValidator { value: Vec, location: Location, } impl ConstArrayValidator { #[inline] pub(crate) fn compile(value: &[Value], location: Location) -> CompilationResult { - Ok(Box::new(ConstArrayValidator { + Ok(ConstArrayValidator { value: value.to_vec(), location, - })) + } + .into()) } } impl Validate for ConstArrayValidator { @@ -50,14 +51,14 @@ impl Validate for ConstArrayValidator { } } -struct ConstBooleanValidator { +pub(crate) struct ConstBooleanValidator { value: bool, location: Location, } impl ConstBooleanValidator { #[inline] pub(crate) fn compile<'a>(value: bool, location: Location) -> CompilationResult<'a> { - Ok(Box::new(ConstBooleanValidator { value, location })) + Ok(ConstBooleanValidator { value, location }.into()) } } impl Validate for ConstBooleanValidator { @@ -88,13 +89,13 @@ impl Validate for ConstBooleanValidator { } } -struct ConstNullValidator { +pub(crate) struct ConstNullValidator { location: Location, } impl ConstNullValidator { #[inline] pub(crate) fn compile<'a>(location: Location) -> CompilationResult<'a> { - Ok(Box::new(ConstNullValidator { location })) + Ok(ConstNullValidator { location }.into()) } } impl Validate for ConstNullValidator { @@ -119,7 +120,7 @@ impl Validate for ConstNullValidator { } } -struct ConstNumberValidator { +pub(crate) struct ConstNumberValidator { // This is saved in order to ensure that the error message is not altered by precision loss original_value: Number, value: f64, @@ -129,13 +130,14 @@ struct ConstNumberValidator { impl ConstNumberValidator { #[inline] pub(crate) fn compile(original_value: &Number, location: Location) -> CompilationResult { - Ok(Box::new(ConstNumberValidator { + Ok(ConstNumberValidator { original_value: original_value.clone(), value: original_value .as_f64() .expect("A JSON number will always be representable as f64"), location, - })) + } + .into()) } } @@ -174,10 +176,11 @@ pub(crate) struct ConstObjectValidator { impl ConstObjectValidator { #[inline] pub(crate) fn compile(value: &Map, location: Location) -> CompilationResult { - Ok(Box::new(ConstObjectValidator { + Ok(ConstObjectValidator { value: value.clone(), location, - })) + } + .into()) } } @@ -215,10 +218,11 @@ pub(crate) struct ConstStringValidator { impl ConstStringValidator { #[inline] pub(crate) fn compile(value: &str, location: Location) -> CompilationResult { - Ok(Box::new(ConstStringValidator { + Ok(ConstStringValidator { value: value.to_string(), location, - })) + } + .into()) } } diff --git a/crates/jsonschema/src/keywords/contains.rs b/crates/jsonschema/src/keywords/contains.rs index a687c0ac..554b787d 100644 --- a/crates/jsonschema/src/keywords/contains.rs +++ b/crates/jsonschema/src/keywords/contains.rs @@ -12,16 +12,17 @@ use serde_json::{Map, Value}; use super::helpers::map_get_u64; pub(crate) struct ContainsValidator { - node: SchemaNode, + node: Box, } impl ContainsValidator { #[inline] pub(crate) fn compile<'a>(ctx: &compiler::Context, schema: &'a Value) -> CompilationResult<'a> { let ctx = ctx.new_at_location("contains"); - Ok(Box::new(ContainsValidator { - node: compiler::compile(&ctx, ctx.as_resource_ref(schema))?, - })) + Ok(ContainsValidator { + node: Box::new(compiler::compile(&ctx, ctx.as_resource_ref(schema))?), + } + .into()) } } @@ -91,7 +92,7 @@ impl Validate for ContainsValidator { /// /// Docs: pub(crate) struct MinContainsValidator { - node: SchemaNode, + node: Box, min_contains: u64, } @@ -103,10 +104,11 @@ impl MinContainsValidator { min_contains: u64, ) -> CompilationResult<'a> { let ctx = ctx.new_at_location("minContains"); - Ok(Box::new(MinContainsValidator { - node: compiler::compile(&ctx, ctx.as_resource_ref(schema))?, + Ok(MinContainsValidator { + node: Box::new(compiler::compile(&ctx, ctx.as_resource_ref(schema))?), min_contains, - })) + } + .into()) } } @@ -170,7 +172,7 @@ impl Validate for MinContainsValidator { /// /// Docs: pub(crate) struct MaxContainsValidator { - node: SchemaNode, + node: Box, max_contains: u64, } @@ -182,10 +184,11 @@ impl MaxContainsValidator { max_contains: u64, ) -> CompilationResult<'a> { let ctx = ctx.new_at_location("maxContains"); - Ok(Box::new(MaxContainsValidator { - node: compiler::compile(&ctx, ctx.as_resource_ref(schema))?, + Ok(MaxContainsValidator { + node: Box::new(compiler::compile(&ctx, ctx.as_resource_ref(schema))?), max_contains, - })) + } + .into()) } } @@ -255,7 +258,7 @@ impl Validate for MaxContainsValidator { /// `maxContains` - /// `minContains` - pub(crate) struct MinMaxContainsValidator { - node: SchemaNode, + node: Box, min_contains: u64, max_contains: u64, } @@ -268,11 +271,12 @@ impl MinMaxContainsValidator { min_contains: u64, max_contains: u64, ) -> CompilationResult<'a> { - Ok(Box::new(MinMaxContainsValidator { - node: compiler::compile(ctx, ctx.as_resource_ref(schema))?, + Ok(MinMaxContainsValidator { + node: Box::new(compiler::compile(ctx, ctx.as_resource_ref(schema))?), min_contains, max_contains, - })) + } + .into()) } } diff --git a/crates/jsonschema/src/keywords/content.rs b/crates/jsonschema/src/keywords/content.rs index 5c0e8e53..32de8827 100644 --- a/crates/jsonschema/src/keywords/content.rs +++ b/crates/jsonschema/src/keywords/content.rs @@ -25,11 +25,12 @@ impl ContentMediaTypeValidator { func: ContentMediaTypeCheckType, location: Location, ) -> CompilationResult { - Ok(Box::new(ContentMediaTypeValidator { + Ok(ContentMediaTypeValidator { media_type: media_type.to_string(), func, location, - })) + } + .into()) } } @@ -79,11 +80,12 @@ impl ContentEncodingValidator { func: ContentEncodingCheckType, location: Location, ) -> CompilationResult { - Ok(Box::new(ContentEncodingValidator { + Ok(ContentEncodingValidator { encoding: encoding.to_string(), func, location, - })) + } + .into()) } } @@ -136,13 +138,14 @@ impl ContentMediaTypeAndEncodingValidator { converter: ContentEncodingConverterType, location: Location, ) -> CompilationResult<'a> { - Ok(Box::new(ContentMediaTypeAndEncodingValidator { + Ok(ContentMediaTypeAndEncodingValidator { media_type: media_type.to_string(), encoding: encoding.to_string(), func, converter, location, - })) + } + .into()) } } diff --git a/crates/jsonschema/src/keywords/dependencies.rs b/crates/jsonschema/src/keywords/dependencies.rs index df5f68f1..02cf0e48 100644 --- a/crates/jsonschema/src/keywords/dependencies.rs +++ b/crates/jsonschema/src/keywords/dependencies.rs @@ -35,7 +35,7 @@ impl DependenciesValidator { }; dependencies.push((key.clone(), s)) } - Ok(Box::new(DependenciesValidator { dependencies })) + Ok(DependenciesValidator { dependencies }.into()) } else { Err(ValidationError::single_type_error( Location::new(), @@ -128,7 +128,7 @@ impl DependentRequiredValidator { )); } } - Ok(Box::new(DependentRequiredValidator { dependencies })) + Ok(DependentRequiredValidator { dependencies }.into()) } else { Err(ValidationError::single_type_error( Location::new(), @@ -196,7 +196,7 @@ impl DependentSchemasValidator { let schema_nodes = compiler::compile(&ctx, ctx.as_resource_ref(subschema))?; dependencies.push((key.clone(), schema_nodes)); } - Ok(Box::new(DependentSchemasValidator { dependencies })) + Ok(DependentSchemasValidator { dependencies }.into()) } else { Err(ValidationError::single_type_error( Location::new(), diff --git a/crates/jsonschema/src/keywords/enum_.rs b/crates/jsonschema/src/keywords/enum_.rs index bba1dd8a..253a570d 100644 --- a/crates/jsonschema/src/keywords/enum_.rs +++ b/crates/jsonschema/src/keywords/enum_.rs @@ -28,12 +28,13 @@ impl EnumValidator { for item in items { types |= PrimitiveType::from(item); } - Ok(Box::new(EnumValidator { + Ok(EnumValidator { options: schema.clone(), items: items.to_vec(), types, location, - })) + } + .into()) } } @@ -81,11 +82,12 @@ impl SingleValueEnumValidator { value: &'a Value, location: Location, ) -> CompilationResult<'a> { - Ok(Box::new(SingleValueEnumValidator { + Ok(SingleValueEnumValidator { options: schema.clone(), value: value.clone(), location, - })) + } + .into()) } } diff --git a/crates/jsonschema/src/keywords/exclusive_maximum.rs b/crates/jsonschema/src/keywords/exclusive_maximum.rs index e8f5d410..5a13e46c 100644 --- a/crates/jsonschema/src/keywords/exclusive_maximum.rs +++ b/crates/jsonschema/src/keywords/exclusive_maximum.rs @@ -109,24 +109,27 @@ pub(crate) fn compile<'a>( if let Value::Number(limit) = schema { let location = ctx.location().join("exclusiveMaximum"); if let Some(limit) = limit.as_u64() { - Some(Ok(Box::new(ExclusiveMaximumU64Validator { + Some(Ok(ExclusiveMaximumU64Validator { limit, limit_val: (*schema).clone(), location, - }))) + } + .into())) } else if let Some(limit) = limit.as_i64() { - Some(Ok(Box::new(ExclusiveMaximumI64Validator { + Some(Ok(ExclusiveMaximumI64Validator { limit, limit_val: (*schema).clone(), location, - }))) + } + .into())) } else { let limit = limit.as_f64().expect("Always valid"); - Some(Ok(Box::new(ExclusiveMaximumF64Validator { + Some(Ok(ExclusiveMaximumF64Validator { limit, limit_val: (*schema).clone(), location, - }))) + } + .into())) } } else { Some(Err(ValidationError::single_type_error( diff --git a/crates/jsonschema/src/keywords/exclusive_minimum.rs b/crates/jsonschema/src/keywords/exclusive_minimum.rs index 282f0f16..d72ee528 100644 --- a/crates/jsonschema/src/keywords/exclusive_minimum.rs +++ b/crates/jsonschema/src/keywords/exclusive_minimum.rs @@ -107,24 +107,27 @@ pub(crate) fn compile<'a>( if let Value::Number(limit) = schema { let location = ctx.location().join("exclusiveMinimum"); if let Some(limit) = limit.as_u64() { - Some(Ok(Box::new(ExclusiveMinimumU64Validator { + Some(Ok(ExclusiveMinimumU64Validator { limit, limit_val: schema.clone(), location, - }))) + } + .into())) } else if let Some(limit) = limit.as_i64() { - Some(Ok(Box::new(ExclusiveMinimumI64Validator { + Some(Ok(ExclusiveMinimumI64Validator { limit, limit_val: schema.clone(), location, - }))) + } + .into())) } else { let limit = limit.as_f64().expect("Always valid"); - Some(Ok(Box::new(ExclusiveMinimumF64Validator { + Some(Ok(ExclusiveMinimumF64Validator { limit, limit_val: schema.clone(), location, - }))) + } + .into())) } } else { Some(Err(ValidationError::single_type_error( diff --git a/crates/jsonschema/src/keywords/format.rs b/crates/jsonschema/src/keywords/format.rs index 6f8a59bb..88a17e5b 100644 --- a/crates/jsonschema/src/keywords/format.rs +++ b/crates/jsonschema/src/keywords/format.rs @@ -616,14 +616,14 @@ fn is_valid_uuid(uuid: &str) -> bool { macro_rules! format_validators { ($(($validator:ident, $format:expr, $validation_fn:ident)),+ $(,)?) => { $( - struct $validator { + pub(crate) struct $validator { location: Location, } impl $validator { pub(crate) fn compile<'a>(ctx: &compiler::Context) -> CompilationResult<'a> { let location = ctx.location().join("format"); - Ok(Box::new($validator { location })) + Ok($validator { location }.into()) } } @@ -691,11 +691,12 @@ format_validators!( (UuidValidator, "uuid", is_valid_uuid), ); -struct CustomFormatValidator { +pub(crate) struct CustomFormatValidator { location: Location, format_name: String, check: Arc, } + impl CustomFormatValidator { pub(crate) fn compile<'a>( ctx: &compiler::Context, @@ -703,11 +704,12 @@ impl CustomFormatValidator { check: Arc, ) -> CompilationResult<'a> { let location = ctx.location().join("format"); - Ok(Box::new(CustomFormatValidator { + Ok(CustomFormatValidator { location, format_name, check, - })) + } + .into()) } } diff --git a/crates/jsonschema/src/keywords/if_.rs b/crates/jsonschema/src/keywords/if_.rs index 84cc7ff0..22b8a365 100644 --- a/crates/jsonschema/src/keywords/if_.rs +++ b/crates/jsonschema/src/keywords/if_.rs @@ -30,7 +30,8 @@ impl IfThenValidator { let ctx = ctx.new_at_location("then"); compiler::compile(&ctx, ctx.as_resource_ref(then_schema))? }, - })) + }) + .into()) } } @@ -98,7 +99,8 @@ impl IfElseValidator { let ctx = ctx.new_at_location("else"); compiler::compile(&ctx, ctx.as_resource_ref(else_schema))? }, - })) + }) + .into()) } } @@ -170,7 +172,8 @@ impl IfThenElseValidator { let ctx = ctx.new_at_location("else"); compiler::compile(&ctx, ctx.as_resource_ref(else_schema))? }, - })) + }) + .into()) } } diff --git a/crates/jsonschema/src/keywords/items.rs b/crates/jsonschema/src/keywords/items.rs index bf076290..a34a0305 100644 --- a/crates/jsonschema/src/keywords/items.rs +++ b/crates/jsonschema/src/keywords/items.rs @@ -25,7 +25,7 @@ impl ItemsArrayValidator { let validators = compiler::compile(&ictx, ictx.as_resource_ref(item))?; items.push(validators) } - Ok(Box::new(ItemsArrayValidator { items })) + Ok(ItemsArrayValidator { items }.into()) } } impl Validate for ItemsArrayValidator { @@ -70,15 +70,15 @@ impl Validate for ItemsArrayValidator { } pub(crate) struct ItemsObjectValidator { - node: SchemaNode, + node: Box, } impl ItemsObjectValidator { #[inline] pub(crate) fn compile<'a>(ctx: &compiler::Context, schema: &'a Value) -> CompilationResult<'a> { let ctx = ctx.new_at_location("items"); - let node = compiler::compile(&ctx, ctx.as_resource_ref(schema))?; - Ok(Box::new(ItemsObjectValidator { node })) + let node = Box::new(compiler::compile(&ctx, ctx.as_resource_ref(schema))?); + Ok(ItemsObjectValidator { node }.into()) } } impl Validate for ItemsObjectValidator { @@ -140,7 +140,7 @@ impl Validate for ItemsObjectValidator { } pub(crate) struct ItemsObjectSkipPrefixValidator { - node: SchemaNode, + node: Box, skip_prefix: usize, } @@ -152,11 +152,8 @@ impl ItemsObjectSkipPrefixValidator { ctx: &compiler::Context, ) -> CompilationResult<'a> { let ctx = ctx.new_at_location("items"); - let node = compiler::compile(&ctx, ctx.as_resource_ref(schema))?; - Ok(Box::new(ItemsObjectSkipPrefixValidator { - node, - skip_prefix, - })) + let node = Box::new(compiler::compile(&ctx, ctx.as_resource_ref(schema))?); + Ok(ItemsObjectSkipPrefixValidator { node, skip_prefix }.into()) } } diff --git a/crates/jsonschema/src/keywords/legacy/type_draft_4.rs b/crates/jsonschema/src/keywords/legacy/type_draft_4.rs index 5903811a..a6770dfc 100644 --- a/crates/jsonschema/src/keywords/legacy/type_draft_4.rs +++ b/crates/jsonschema/src/keywords/legacy/type_draft_4.rs @@ -44,7 +44,7 @@ impl MultipleTypesValidator { } } } - Ok(Box::new(MultipleTypesValidator { types, location })) + Ok(MultipleTypesValidator { types, location }.into()) } } @@ -87,7 +87,7 @@ pub(crate) struct IntegerTypeValidator { impl IntegerTypeValidator { #[inline] pub(crate) fn compile<'a>(location: Location) -> CompilationResult<'a> { - Ok(Box::new(IntegerTypeValidator { location })) + Ok(IntegerTypeValidator { location }.into()) } } diff --git a/crates/jsonschema/src/keywords/max_items.rs b/crates/jsonschema/src/keywords/max_items.rs index b098a5a3..6d935916 100644 --- a/crates/jsonschema/src/keywords/max_items.rs +++ b/crates/jsonschema/src/keywords/max_items.rs @@ -20,17 +20,18 @@ impl MaxItemsValidator { location: Location, ) -> CompilationResult<'a> { if let Some(limit) = schema.as_u64() { - return Ok(Box::new(MaxItemsValidator { limit, location })); + return Ok(MaxItemsValidator { limit, location }.into()); } if ctx.supports_integer_valued_numbers() { if let Some(limit) = schema.as_f64() { if limit.trunc() == limit { #[allow(clippy::cast_possible_truncation)] - return Ok(Box::new(MaxItemsValidator { + return Ok(MaxItemsValidator { // NOTE: Imprecise cast as big integers are not supported yet limit: limit as u64, location, - })); + } + .into()); } } } diff --git a/crates/jsonschema/src/keywords/max_length.rs b/crates/jsonschema/src/keywords/max_length.rs index f044351f..9c959b7a 100644 --- a/crates/jsonschema/src/keywords/max_length.rs +++ b/crates/jsonschema/src/keywords/max_length.rs @@ -20,17 +20,18 @@ impl MaxLengthValidator { location: Location, ) -> CompilationResult<'a> { if let Some(limit) = schema.as_u64() { - return Ok(Box::new(MaxLengthValidator { limit, location })); + return Ok(MaxLengthValidator { limit, location }.into()); } if ctx.supports_integer_valued_numbers() { if let Some(limit) = schema.as_f64() { if limit.trunc() == limit { #[allow(clippy::cast_possible_truncation)] - return Ok(Box::new(MaxLengthValidator { + return Ok(MaxLengthValidator { // NOTE: Imprecise cast as big integers are not supported yet limit: limit as u64, location, - })); + } + .into()); } } } diff --git a/crates/jsonschema/src/keywords/max_properties.rs b/crates/jsonschema/src/keywords/max_properties.rs index 9a23882a..6e7ec4f8 100644 --- a/crates/jsonschema/src/keywords/max_properties.rs +++ b/crates/jsonschema/src/keywords/max_properties.rs @@ -20,17 +20,18 @@ impl MaxPropertiesValidator { location: Location, ) -> CompilationResult<'a> { if let Some(limit) = schema.as_u64() { - return Ok(Box::new(MaxPropertiesValidator { limit, location })); + return Ok(MaxPropertiesValidator { limit, location }.into()); } if ctx.supports_integer_valued_numbers() { if let Some(limit) = schema.as_f64() { if limit.trunc() == limit { #[allow(clippy::cast_possible_truncation)] - return Ok(Box::new(MaxPropertiesValidator { + return Ok(MaxPropertiesValidator { // NOTE: Imprecise cast as big integers are not supported yet limit: limit as u64, location, - })); + } + .into()); } } } diff --git a/crates/jsonschema/src/keywords/maximum.rs b/crates/jsonschema/src/keywords/maximum.rs index 4829b26d..02cd64ae 100644 --- a/crates/jsonschema/src/keywords/maximum.rs +++ b/crates/jsonschema/src/keywords/maximum.rs @@ -107,24 +107,27 @@ pub(crate) fn compile<'a>( if let Value::Number(limit) = schema { let location = ctx.location().join("maximum"); if let Some(limit) = limit.as_u64() { - Some(Ok(Box::new(MaximumU64Validator { + Some(Ok(MaximumU64Validator { limit, limit_val: schema.clone(), location, - }))) + } + .into())) } else if let Some(limit) = limit.as_i64() { - Some(Ok(Box::new(MaximumI64Validator { + Some(Ok(MaximumI64Validator { limit, limit_val: schema.clone(), location, - }))) + } + .into())) } else { let limit = limit.as_f64().expect("Always valid"); - Some(Ok(Box::new(MaximumF64Validator { + Some(Ok(MaximumF64Validator { limit, limit_val: schema.clone(), location, - }))) + } + .into())) } } else { Some(Err(ValidationError::single_type_error( diff --git a/crates/jsonschema/src/keywords/min_items.rs b/crates/jsonschema/src/keywords/min_items.rs index 435171ff..b4ddf26e 100644 --- a/crates/jsonschema/src/keywords/min_items.rs +++ b/crates/jsonschema/src/keywords/min_items.rs @@ -20,17 +20,18 @@ impl MinItemsValidator { location: Location, ) -> CompilationResult<'a> { if let Some(limit) = schema.as_u64() { - return Ok(Box::new(MinItemsValidator { limit, location })); + return Ok(MinItemsValidator { limit, location }.into()); } if ctx.supports_integer_valued_numbers() { if let Some(limit) = schema.as_f64() { if limit.trunc() == limit { #[allow(clippy::cast_possible_truncation)] - return Ok(Box::new(MinItemsValidator { + return Ok(MinItemsValidator { // NOTE: Imprecise cast as big integers are not supported yet limit: limit as u64, location, - })); + } + .into()); } } } diff --git a/crates/jsonschema/src/keywords/min_length.rs b/crates/jsonschema/src/keywords/min_length.rs index db81eaee..942c98d2 100644 --- a/crates/jsonschema/src/keywords/min_length.rs +++ b/crates/jsonschema/src/keywords/min_length.rs @@ -20,17 +20,18 @@ impl MinLengthValidator { location: Location, ) -> CompilationResult<'a> { if let Some(limit) = schema.as_u64() { - return Ok(Box::new(MinLengthValidator { limit, location })); + return Ok(MinLengthValidator { limit, location }.into()); } if ctx.supports_integer_valued_numbers() { if let Some(limit) = schema.as_f64() { if limit.trunc() == limit { #[allow(clippy::cast_possible_truncation)] - return Ok(Box::new(MinLengthValidator { + return Ok(MinLengthValidator { // NOTE: Imprecise cast as big integers are not supported yet limit: limit as u64, location, - })); + } + .into()); } } } diff --git a/crates/jsonschema/src/keywords/min_properties.rs b/crates/jsonschema/src/keywords/min_properties.rs index 9ff87f4b..69ac929f 100644 --- a/crates/jsonschema/src/keywords/min_properties.rs +++ b/crates/jsonschema/src/keywords/min_properties.rs @@ -20,17 +20,18 @@ impl MinPropertiesValidator { location: Location, ) -> CompilationResult<'a> { if let Some(limit) = schema.as_u64() { - return Ok(Box::new(MinPropertiesValidator { limit, location })); + return Ok(MinPropertiesValidator { limit, location }.into()); } if ctx.supports_integer_valued_numbers() { if let Some(limit) = schema.as_f64() { if limit.trunc() == limit { #[allow(clippy::cast_possible_truncation)] - return Ok(Box::new(MinPropertiesValidator { + return Ok(MinPropertiesValidator { // NOTE: Imprecise cast as big integers are not supported yet limit: limit as u64, location, - })); + } + .into()); } } } diff --git a/crates/jsonschema/src/keywords/minimum.rs b/crates/jsonschema/src/keywords/minimum.rs index 6ef0b2e2..6dc80b45 100644 --- a/crates/jsonschema/src/keywords/minimum.rs +++ b/crates/jsonschema/src/keywords/minimum.rs @@ -107,24 +107,27 @@ pub(crate) fn compile<'a>( if let Value::Number(limit) = schema { let location = ctx.location().join("minimum"); if let Some(limit) = limit.as_u64() { - Some(Ok(Box::new(MinimumU64Validator { + Some(Ok(MinimumU64Validator { limit, limit_val: schema.clone(), location, - }))) + } + .into())) } else if let Some(limit) = limit.as_i64() { - Some(Ok(Box::new(MinimumI64Validator { + Some(Ok(MinimumI64Validator { limit, limit_val: schema.clone(), location, - }))) + } + .into())) } else { let limit = limit.as_f64().expect("Always valid"); - Some(Ok(Box::new(MinimumF64Validator { + Some(Ok(MinimumF64Validator { limit, limit_val: schema.clone(), location, - }))) + } + .into())) } } else { Some(Err(ValidationError::single_type_error( diff --git a/crates/jsonschema/src/keywords/mod.rs b/crates/jsonschema/src/keywords/mod.rs index 94840b94..2ed1e147 100644 --- a/crates/jsonschema/src/keywords/mod.rs +++ b/crates/jsonschema/src/keywords/mod.rs @@ -43,17 +43,204 @@ use core::fmt; use referencing::{Draft, Vocabulary}; use serde_json::{Map, Value}; -use crate::{compiler, error, validator::Validate}; +use crate::{ + compiler, error, + paths::LazyLocation, + properties::{BigValidatorsMap, SmallValidatorsMap}, + validator::{PartialApplication, Validate}, + ErrorIterator, ValidationError, +}; -pub(crate) type CompilationResult<'a> = Result>; -pub(crate) type BoxedValidator = Box; +pub(crate) type CompilationResult<'a> = Result>; type CompileFunc<'a> = fn(&'a compiler::Context, &'a Map, &'a Value) -> Option>; +macro_rules! keyword_value { + ( + $( + $variant:ident($($type:ident)::+ $(< $($generic:ident)::+ >)?), + )* + ) => { + pub(crate) enum KeywordValue { + $( + $variant($($type)::+ $(< $($generic)::+ >)?), + )* + } + + $( + impl From<$($type)::+ $(< $($generic)::+ >)?> for KeywordValue { + fn from(value: $($type)::+ $(< $($generic)::+ >)?) -> Self { + Self::$variant(value) + } + } + )* + + impl KeywordValue { + pub(crate) fn is_valid(&self, instance: &Value) -> bool { + match self { + $( + Self::$variant(v) => v.is_valid(instance), + )* + } + } + + pub(crate) fn iter_errors<'i>( + &self, + instance: &'i Value, + location: &LazyLocation, + ) -> ErrorIterator<'i> { + match self { + $( + Self::$variant(v) => v.iter_errors(instance, location), + )* + } + } + + pub(crate) fn apply<'a>( + &'a self, + instance: &Value, + location: &LazyLocation, + ) -> PartialApplication<'a> { + match self { + $( + Self::$variant(v) => v.apply(instance, location), + )* + } + } + + pub(crate) fn validate<'i>( + &self, + instance: &'i Value, + location: &LazyLocation, + ) -> Result<(), ValidationError<'i>> { + match self { + $( + Self::$variant(v) => v.validate(instance, location), + )* + } + } + } + }; +} + +keyword_value! { + Custom(custom::CustomKeyword), + Draft4MultipleTypes(legacy::type_draft_4::MultipleTypesValidator), + Draft4IntegerType(legacy::type_draft_4::IntegerTypeValidator), + AdditionalItemsObject(additional_items::AdditionalItemsObjectValidator), + AdditionalItemsBool(additional_items::AdditionalItemsBooleanValidator), + AdditionalProperties(additional_properties::AdditionalPropertiesValidator), + AdditionalPropertiesFalse(additional_properties::AdditionalPropertiesFalseValidator), + AdditionalPropertiesWithPatterns(additional_properties::AdditionalPropertiesWithPatternsValidator), + AdditionalPropertiesWithPatternsFalse(additional_properties::AdditionalPropertiesWithPatternsFalseValidator), + AdditionalPropertiesWithPatternsFalseNonEmptySmall(additional_properties::AdditionalPropertiesWithPatternsNotEmptyValidator), + AdditionalPropertiesWithPatternsFalseNonEmptyBig(additional_properties::AdditionalPropertiesWithPatternsNotEmptyValidator), + AdditionalPropertiesWithPatternsNotEmptyFalseSmall(additional_properties::AdditionalPropertiesWithPatternsNotEmptyFalseValidator), + AdditionalPropertiesWithPatternsNotEmptyFalseBig(additional_properties::AdditionalPropertiesWithPatternsNotEmptyFalseValidator), + AdditionalPropertiesNotEmptyFalseSmall(additional_properties::AdditionalPropertiesNotEmptyFalseValidator), + AdditionalPropertiesNotEmptyFalseBig(additional_properties::AdditionalPropertiesNotEmptyFalseValidator), + AdditionalPropertiesNotEmptySmall(additional_properties::AdditionalPropertiesNotEmptyValidator), + AdditionalPropertiesNotEmptyBig(additional_properties::AdditionalPropertiesNotEmptyValidator), + AllOf(all_of::AllOfValidator), + AllOfSingle(all_of::SingleValueAllOfValidator), + AnyOf(any_of::AnyOfValidator), + Boolean(boolean::FalseValidator), + ConstObject(const_::ConstObjectValidator), + ConstArray(const_::ConstArrayValidator), + ConstString(const_::ConstStringValidator), + ConstNumber(const_::ConstNumberValidator), + ConstNull(const_::ConstNullValidator), + ConstBool(const_::ConstBooleanValidator), + Contains(contains::ContainsValidator), + ContainsMax(contains::MaxContainsValidator), + ContainsMin(contains::MinContainsValidator), + ContainsMinMax(contains::MinMaxContainsValidator), + ContentEncoding(content::ContentEncodingValidator), + ContentMediaType(content::ContentMediaTypeValidator), + ContentMediaTypeAndEncoding(content::ContentMediaTypeAndEncodingValidator), + Dependencies(dependencies::DependenciesValidator), + DependentSchemas(dependencies::DependentSchemasValidator), + DependentRequired(dependencies::DependentRequiredValidator), + Enum(enum_::EnumValidator), + EnumSingle(enum_::SingleValueEnumValidator), + ExclusiveMaximumU64(exclusive_maximum::ExclusiveMaximumU64Validator), + ExclusiveMaximumI64(exclusive_maximum::ExclusiveMaximumI64Validator), + ExclusiveMaximumF64(exclusive_maximum::ExclusiveMaximumF64Validator), + ExclusiveMinimumU64(exclusive_minimum::ExclusiveMinimumU64Validator), + ExclusiveMinimumI64(exclusive_minimum::ExclusiveMinimumI64Validator), + ExclusiveMinimumF64(exclusive_minimum::ExclusiveMinimumF64Validator), + FormatDate(format::DateValidator), + FormatDateTime(format::DateTimeValidator), + FormatDuration(format::DurationValidator), + FormatEmail(format::EmailValidator), + FormatHostname(format::HostnameValidator), + FormatIdnEmail(format::IdnEmailValidator), + FormatIdnHostname(format::IdnHostnameValidator), + FormatIpV4(format::IpV4Validator), + FormatIpV6(format::IpV6Validator), + FormatIri(format::IriValidator), + FormatIriReference(format::IriReferenceValidator), + FormatJsonPointer(format::JsonPointerValidator), + FormatRegex(format::RegexValidator), + FormatRelativeJsonPointer(format::RelativeJsonPointerValidator), + FormatTime(format::TimeValidator), + FormatUri(format::UriValidator), + FormatUriReference(format::UriReferenceValidator), + FormatUriTemplate(format::UriTemplateValidator), + FormatUuid(format::UuidValidator), + FormatCustom(format::CustomFormatValidator), + IfElse(Box), + IfThen(Box), + IfThenElse(Box), + ItemsArray(items::ItemsArrayValidator), + ItemsObject(items::ItemsObjectValidator), + ItemsObjectSkipPrefix(items::ItemsObjectSkipPrefixValidator), + MaxItems(max_items::MaxItemsValidator), + MaxLength(max_length::MaxLengthValidator), + MaxProperties(max_properties::MaxPropertiesValidator), + MaximumU64(maximum::MaximumU64Validator), + MaximumI64(maximum::MaximumI64Validator), + MaximumF64(maximum::MaximumF64Validator), + MinItems(min_items::MinItemsValidator), + MinLength(min_length::MinLengthValidator), + MinProperties(min_properties::MinPropertiesValidator), + MinimumU64(minimum::MinimumU64Validator), + MinimumI64(minimum::MinimumI64Validator), + MinimumF64(minimum::MinimumF64Validator), + MultipleOfFloat(multiple_of::MultipleOfFloatValidator), + MultipleOfInteger(multiple_of::MultipleOfIntegerValidator), + Not(not::NotValidator), + OneOf(one_of::OneOfValidator), + Pattern(pattern::PatternValidator), + SinglePatternProperties(pattern_properties::SingleValuePatternPropertiesValidator), + PatternProperties(pattern_properties::PatternPropertiesValidator), + PrefixItems(prefix_items::PrefixItemsValidator), + Properties(properties::PropertiesValidator), + PropertyNamesBoolean(property_names::PropertyNamesBooleanValidator), + PropertyNamesObject(property_names::PropertyNamesObjectValidator), + LazyRef(ref_::LazyRefValidator), + Ref(ref_::RefValidator), + SingleRequired(required::SingleItemRequiredValidator), + Required(required::RequiredValidator), + MultipleTypes(type_::MultipleTypesValidator), + BooleanType(type_::BooleanTypeValidator), + NullType(type_::NullTypeValidator), + IntegerType(type_::IntegerTypeValidator), + NumberType(type_::NumberTypeValidator), + StringType(type_::StringTypeValidator), + ObjectType(type_::ObjectTypeValidator), + ArrayType(type_::ArrayTypeValidator), + UnevaluatedItems2019(unevaluated_items::UnevaluatedItemsValidator), + UnevaluatedItems(unevaluated_items::UnevaluatedItemsValidator), + UnevaluatedProperties2019(unevaluated_properties::UnevaluatedPropertiesValidator), + UnevaluatedProperties(unevaluated_properties::UnevaluatedPropertiesValidator), + UniqueItems(unique_items::UniqueItemsValidator), +} + #[derive(Debug, Clone)] -pub(crate) enum Keyword { - Buildin(BuiltinKeyword), +pub(crate) enum KeywordKind { + Builtin(BuiltinKeyword), Custom(Box), } @@ -150,25 +337,25 @@ impl BuiltinKeyword { } } -impl Keyword { +impl KeywordKind { pub(crate) fn custom(name: impl Into) -> Self { - Keyword::Custom(name.into().into_boxed_str()) + KeywordKind::Custom(name.into().into_boxed_str()) } pub(crate) fn as_str(&self) -> &str { match self { - Self::Buildin(d) => d.as_str(), + Self::Builtin(d) => d.as_str(), Self::Custom(s) => s, } } } -impl From for Keyword { +impl From for KeywordKind { fn from(value: BuiltinKeyword) -> Self { - Keyword::Buildin(value) + KeywordKind::Builtin(value) } } -impl fmt::Display for Keyword { +impl fmt::Display for KeywordKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.as_str()) } @@ -177,7 +364,7 @@ impl fmt::Display for Keyword { pub(crate) fn get_for_draft<'a>( ctx: &compiler::Context<'a>, keyword: &'a str, -) -> Option<(Keyword, CompileFunc<'a>)> { +) -> Option<(KeywordKind, CompileFunc<'a>)> { match (ctx.draft(), keyword) { // Keywords common to all drafts (_, "$ref") => Some((BuiltinKeyword::Ref.into(), ref_::compile_ref)), diff --git a/crates/jsonschema/src/keywords/multiple_of.rs b/crates/jsonschema/src/keywords/multiple_of.rs index cb74dac3..c2579200 100644 --- a/crates/jsonschema/src/keywords/multiple_of.rs +++ b/crates/jsonschema/src/keywords/multiple_of.rs @@ -17,10 +17,11 @@ pub(crate) struct MultipleOfFloatValidator { impl MultipleOfFloatValidator { #[inline] pub(crate) fn compile<'a>(multiple_of: f64, location: Location) -> CompilationResult<'a> { - Ok(Box::new(MultipleOfFloatValidator { + Ok(MultipleOfFloatValidator { multiple_of, location, - })) + } + .into()) } } @@ -70,10 +71,11 @@ pub(crate) struct MultipleOfIntegerValidator { impl MultipleOfIntegerValidator { #[inline] pub(crate) fn compile<'a>(multiple_of: f64, location: Location) -> CompilationResult<'a> { - Ok(Box::new(MultipleOfIntegerValidator { + Ok(MultipleOfIntegerValidator { multiple_of, location, - })) + } + .into()) } } diff --git a/crates/jsonschema/src/keywords/not.rs b/crates/jsonschema/src/keywords/not.rs index 612eb34b..8e27d386 100644 --- a/crates/jsonschema/src/keywords/not.rs +++ b/crates/jsonschema/src/keywords/not.rs @@ -7,17 +7,18 @@ use serde_json::{Map, Value}; pub(crate) struct NotValidator { // needed only for error representation original: Value, - node: SchemaNode, + node: Box, } impl NotValidator { #[inline] pub(crate) fn compile<'a>(ctx: &compiler::Context, schema: &'a Value) -> CompilationResult<'a> { let ctx = ctx.new_at_location("not"); - Ok(Box::new(NotValidator { + Ok(NotValidator { original: schema.clone(), - node: compiler::compile(&ctx, ctx.as_resource_ref(schema))?, - })) + node: Box::new(compiler::compile(&ctx, ctx.as_resource_ref(schema))?), + } + .into()) } } diff --git a/crates/jsonschema/src/keywords/one_of.rs b/crates/jsonschema/src/keywords/one_of.rs index c5e16e3e..7b98092c 100644 --- a/crates/jsonschema/src/keywords/one_of.rs +++ b/crates/jsonschema/src/keywords/one_of.rs @@ -26,10 +26,11 @@ impl OneOfValidator { let node = compiler::compile(&ctx, ctx.as_resource_ref(item))?; schemas.push(node) } - Ok(Box::new(OneOfValidator { + Ok(OneOfValidator { schemas, location: ctx.location().clone(), - })) + } + .into()) } else { Err(ValidationError::single_type_error( Location::new(), diff --git a/crates/jsonschema/src/keywords/pattern.rs b/crates/jsonschema/src/keywords/pattern.rs index 80139dd8..60843e5b 100644 --- a/crates/jsonschema/src/keywords/pattern.rs +++ b/crates/jsonschema/src/keywords/pattern.rs @@ -91,11 +91,12 @@ impl PatternValidator { cache.insert(item.clone(), regex.clone()); regex }; - Ok(Box::new(PatternValidator { + Ok(PatternValidator { original: item.clone(), pattern, location: ctx.location().join("pattern"), - })) + } + .into()) } _ => Err(ValidationError::single_type_error( Location::new(), diff --git a/crates/jsonschema/src/keywords/pattern_properties.rs b/crates/jsonschema/src/keywords/pattern_properties.rs index 080fbd82..22116e44 100644 --- a/crates/jsonschema/src/keywords/pattern_properties.rs +++ b/crates/jsonschema/src/keywords/pattern_properties.rs @@ -40,7 +40,7 @@ impl PatternPropertiesValidator { compiler::compile(&pctx, pctx.as_resource_ref(subschema))?, )); } - Ok(Box::new(PatternPropertiesValidator { patterns })) + Ok(PatternPropertiesValidator { patterns }.into()) } } @@ -119,7 +119,7 @@ impl Validate for PatternPropertiesValidator { pub(crate) struct SingleValuePatternPropertiesValidator { pattern: Regex, - node: SchemaNode, + node: Box, } impl SingleValuePatternPropertiesValidator { @@ -131,7 +131,7 @@ impl SingleValuePatternPropertiesValidator { ) -> CompilationResult<'a> { let kctx = ctx.new_at_location("patternProperties"); let pctx = kctx.new_at_location(pattern); - Ok(Box::new(SingleValuePatternPropertiesValidator { + Ok(SingleValuePatternPropertiesValidator { pattern: { match ecma::to_rust_regex(pattern).map(|pattern| Regex::new(&pattern)) { Ok(Ok(r)) => r, @@ -145,8 +145,9 @@ impl SingleValuePatternPropertiesValidator { } } }, - node: compiler::compile(&pctx, pctx.as_resource_ref(schema))?, - })) + node: Box::new(compiler::compile(&pctx, pctx.as_resource_ref(schema))?), + } + .into()) } } diff --git a/crates/jsonschema/src/keywords/prefix_items.rs b/crates/jsonschema/src/keywords/prefix_items.rs index 6a4a7ef2..2f097b17 100644 --- a/crates/jsonschema/src/keywords/prefix_items.rs +++ b/crates/jsonschema/src/keywords/prefix_items.rs @@ -27,7 +27,7 @@ impl PrefixItemsValidator { let validators = compiler::compile(&ctx, ctx.as_resource_ref(item))?; schemas.push(validators) } - Ok(Box::new(PrefixItemsValidator { schemas })) + Ok(PrefixItemsValidator { schemas }.into()) } } diff --git a/crates/jsonschema/src/keywords/properties.rs b/crates/jsonschema/src/keywords/properties.rs index e65cac9d..9cdb083e 100644 --- a/crates/jsonschema/src/keywords/properties.rs +++ b/crates/jsonschema/src/keywords/properties.rs @@ -28,7 +28,7 @@ impl PropertiesValidator { compiler::compile(&ctx, ctx.as_resource_ref(subschema))?, )); } - Ok(Box::new(PropertiesValidator { properties })) + Ok(PropertiesValidator { properties }.into()) } _ => Err(ValidationError::single_type_error( Location::new(), diff --git a/crates/jsonschema/src/keywords/property_names.rs b/crates/jsonschema/src/keywords/property_names.rs index fe75e2d0..ff0a01cb 100644 --- a/crates/jsonschema/src/keywords/property_names.rs +++ b/crates/jsonschema/src/keywords/property_names.rs @@ -9,16 +9,17 @@ use crate::{ use serde_json::{Map, Value}; pub(crate) struct PropertyNamesObjectValidator { - node: SchemaNode, + node: Box, } impl PropertyNamesObjectValidator { #[inline] pub(crate) fn compile<'a>(ctx: &compiler::Context, schema: &'a Value) -> CompilationResult<'a> { let ctx = ctx.new_at_location("propertyNames"); - Ok(Box::new(PropertyNamesObjectValidator { - node: compiler::compile(&ctx, ctx.as_resource_ref(schema))?, - })) + Ok(PropertyNamesObjectValidator { + node: Box::new(compiler::compile(&ctx, ctx.as_resource_ref(schema))?), + } + .into()) } } @@ -108,7 +109,7 @@ impl PropertyNamesBooleanValidator { #[inline] pub(crate) fn compile<'a>(ctx: &compiler::Context) -> CompilationResult<'a> { let location = ctx.location().join("propertyNames"); - Ok(Box::new(PropertyNamesBooleanValidator { location })) + Ok(PropertyNamesBooleanValidator { location }.into()) } } diff --git a/crates/jsonschema/src/keywords/ref_.rs b/crates/jsonschema/src/keywords/ref_.rs index cd0faae8..bd6b6e47 100644 --- a/crates/jsonschema/src/keywords/ref_.rs +++ b/crates/jsonschema/src/keywords/ref_.rs @@ -15,7 +15,7 @@ use referencing::{Draft, List, Registry, Resource, Uri, VocabularySet}; use serde_json::{Map, Value}; pub(crate) enum RefValidator { - Default { inner: SchemaNode }, + Default { inner: Box }, Lazy(LazyRefValidator), } @@ -43,7 +43,7 @@ impl RefValidator { } } } - Ok(Box::new(RefValidator::Lazy(LazyRefValidator { + Ok(RefValidator::Lazy(LazyRefValidator { resource, config: Arc::clone(ctx.config()), registry: Arc::clone(&ctx.registry), @@ -53,7 +53,8 @@ impl RefValidator { vocabularies: ctx.vocabularies().clone(), draft: ctx.draft(), inner: OnceCell::default(), - }))) + }) + .into()) } else { let (contents, resolver, draft) = match ctx.lookup(reference) { Ok(resolved) => resolved.into_inner(), @@ -73,7 +74,10 @@ impl RefValidator { Ok(inner) => inner, Err(error) => return Some(Err(error)), }; - Ok(Box::new(RefValidator::Default { inner })) + Ok(RefValidator::Default { + inner: Box::new(inner), + } + .into()) }, ) } @@ -95,7 +99,7 @@ pub(crate) struct LazyRefValidator { vocabularies: VocabularySet, location: Location, draft: Draft, - inner: OnceCell, + inner: OnceCell>, } impl LazyRefValidator { @@ -109,7 +113,7 @@ impl LazyRefValidator { if let Some(id) = resource.id() { base_uri = resolver.resolve_against(&base_uri.borrow(), id)?; }; - Ok(Box::new(LazyRefValidator { + Ok(LazyRefValidator { resource, config: Arc::clone(ctx.config()), registry: Arc::clone(&ctx.registry), @@ -119,7 +123,8 @@ impl LazyRefValidator { location: ctx.location().join("$recursiveRef"), draft: ctx.draft(), inner: OnceCell::default(), - })) + } + .into()) } fn lazy_compile(&self) -> &SchemaNode { self.inner.get_or_init(|| { @@ -137,7 +142,7 @@ impl LazyRefValidator { ); // INVARIANT: This schema was already used during compilation before detecting a // reference cycle that lead to building this validator. - compiler::compile(&ctx, self.resource.as_ref()).expect("Invalid schema") + Box::new(compiler::compile(&ctx, self.resource.as_ref()).expect("Invalid schema")) }) } } diff --git a/crates/jsonschema/src/keywords/required.rs b/crates/jsonschema/src/keywords/required.rs index 2cfbf09e..0cb06cea 100644 --- a/crates/jsonschema/src/keywords/required.rs +++ b/crates/jsonschema/src/keywords/required.rs @@ -30,7 +30,7 @@ impl RequiredValidator { } } } - Ok(Box::new(RequiredValidator { required, location })) + Ok(RequiredValidator { required, location }.into()) } } @@ -95,10 +95,11 @@ pub(crate) struct SingleItemRequiredValidator { impl SingleItemRequiredValidator { #[inline] pub(crate) fn compile(value: &str, location: Location) -> CompilationResult { - Ok(Box::new(SingleItemRequiredValidator { + Ok(SingleItemRequiredValidator { value: value.to_string(), location, - })) + } + .into()) } } diff --git a/crates/jsonschema/src/keywords/type_.rs b/crates/jsonschema/src/keywords/type_.rs index 2ca5cfb5..9e3ac70b 100644 --- a/crates/jsonschema/src/keywords/type_.rs +++ b/crates/jsonschema/src/keywords/type_.rs @@ -46,7 +46,7 @@ impl MultipleTypesValidator { } } } - Ok(Box::new(MultipleTypesValidator { types, location })) + Ok(MultipleTypesValidator { types, location }.into()) } } @@ -89,7 +89,7 @@ pub(crate) struct NullTypeValidator { impl NullTypeValidator { #[inline] pub(crate) fn compile<'a>(location: Location) -> CompilationResult<'a> { - Ok(Box::new(NullTypeValidator { location })) + Ok(NullTypeValidator { location }.into()) } } @@ -122,7 +122,7 @@ pub(crate) struct BooleanTypeValidator { impl BooleanTypeValidator { #[inline] pub(crate) fn compile<'a>(location: Location) -> CompilationResult<'a> { - Ok(Box::new(BooleanTypeValidator { location })) + Ok(BooleanTypeValidator { location }.into()) } } @@ -155,7 +155,7 @@ pub(crate) struct StringTypeValidator { impl StringTypeValidator { #[inline] pub(crate) fn compile<'a>(location: Location) -> CompilationResult<'a> { - Ok(Box::new(StringTypeValidator { location })) + Ok(StringTypeValidator { location }.into()) } } @@ -189,7 +189,7 @@ pub(crate) struct ArrayTypeValidator { impl ArrayTypeValidator { #[inline] pub(crate) fn compile<'a>(location: Location) -> CompilationResult<'a> { - Ok(Box::new(ArrayTypeValidator { location })) + Ok(ArrayTypeValidator { location }.into()) } } @@ -223,7 +223,7 @@ pub(crate) struct ObjectTypeValidator { impl ObjectTypeValidator { #[inline] pub(crate) fn compile<'a>(location: Location) -> CompilationResult<'a> { - Ok(Box::new(ObjectTypeValidator { location })) + Ok(ObjectTypeValidator { location }.into()) } } @@ -256,7 +256,7 @@ pub(crate) struct NumberTypeValidator { impl NumberTypeValidator { #[inline] pub(crate) fn compile<'a>(location: Location) -> CompilationResult<'a> { - Ok(Box::new(NumberTypeValidator { location })) + Ok(NumberTypeValidator { location }.into()) } } @@ -289,7 +289,7 @@ pub(crate) struct IntegerTypeValidator { impl IntegerTypeValidator { #[inline] pub(crate) fn compile<'a>(location: Location) -> CompilationResult<'a> { - Ok(Box::new(IntegerTypeValidator { location })) + Ok(IntegerTypeValidator { location }.into()) } } diff --git a/crates/jsonschema/src/keywords/unevaluated_items.rs b/crates/jsonschema/src/keywords/unevaluated_items.rs index 84a843fc..35cdace2 100644 --- a/crates/jsonschema/src/keywords/unevaluated_items.rs +++ b/crates/jsonschema/src/keywords/unevaluated_items.rs @@ -33,16 +33,31 @@ pub(crate) struct UnevaluatedItemsValidator { filter: F, } -impl UnevaluatedItemsValidator { +impl UnevaluatedItemsValidator { #[inline] pub(crate) fn compile<'a>( ctx: &'a compiler::Context, parent: &'a Map, ) -> CompilationResult<'a> { - Ok(Box::new(UnevaluatedItemsValidator { + Ok(UnevaluatedItemsValidator { location: ctx.location().join("unevaluatedItems"), - filter: F::new(ctx, parent)?, - })) + filter: Draft2019ItemsFilter::new(ctx, parent)?, + } + .into()) + } +} + +impl UnevaluatedItemsValidator { + #[inline] + pub(crate) fn compile<'a>( + ctx: &'a compiler::Context, + parent: &'a Map, + ) -> CompilationResult<'a> { + Ok(UnevaluatedItemsValidator { + location: ctx.location().join("unevaluatedItems"), + filter: DefaultItemsFilter::new(ctx, parent)?, + } + .into()) } } @@ -90,9 +105,9 @@ impl Validate for UnevaluatedItemsValidator { } } -struct Draft2019ItemsFilter { - unevaluated: Option, - contains: Option, +pub(crate) struct Draft2019ItemsFilter { + unevaluated: Option>, + contains: Option>, ref_: Option>, recursive_ref: Option>, items: Option, @@ -147,11 +162,17 @@ impl ItemsFilter for Draft2019ItemsFilter { let mut contains = None; if let Some(subschema) = parent.get("contains") { - contains = Some(compiler::compile(ctx, ctx.as_resource_ref(subschema))?); + contains = Some(Box::new(compiler::compile( + ctx, + ctx.as_resource_ref(subschema), + )?)); }; let mut unevaluated = None; if let Some(subschema) = parent.get("unevaluatedItems") { - unevaluated = Some(compiler::compile(ctx, ctx.as_resource_ref(subschema))?); + unevaluated = Some(Box::new(compiler::compile( + ctx, + ctx.as_resource_ref(subschema), + )?)); }; let mut all_of = None; if let Some(Some(subschemas)) = parent.get("allOf").map(Value::as_array) { @@ -191,7 +212,7 @@ impl ItemsFilter for Draft2019ItemsFilter { }) } fn unevaluated(&self) -> Option<&SchemaNode> { - self.unevaluated.as_ref() + self.unevaluated.as_deref() } fn mark_evaluated_indexes(&self, instance: &Value, indexes: &mut Vec) { if let Some(limit) = self.items { @@ -264,9 +285,9 @@ impl ItemsFilter for Draft2019ItemsFilter { } } -struct DefaultItemsFilter { - unevaluated: Option, - contains: Option, +pub(crate) struct DefaultItemsFilter { + unevaluated: Option>, + contains: Option>, ref_: Option>, dynamic_ref: Option>, items: bool, @@ -328,11 +349,17 @@ impl ItemsFilter for DefaultItemsFilter { let mut contains = None; if let Some(subschema) = parent.get("contains") { - contains = Some(compiler::compile(ctx, ctx.as_resource_ref(subschema))?); + contains = Some(Box::new(compiler::compile( + ctx, + ctx.as_resource_ref(subschema), + )?)); }; let mut unevaluated = None; if let Some(subschema) = parent.get("unevaluatedItems") { - unevaluated = Some(compiler::compile(ctx, ctx.as_resource_ref(subschema))?); + unevaluated = Some(Box::new(compiler::compile( + ctx, + ctx.as_resource_ref(subschema), + )?)); }; let mut all_of = None; if let Some(Some(subschemas)) = parent.get("allOf").map(Value::as_array) { @@ -362,7 +389,7 @@ impl ItemsFilter for DefaultItemsFilter { }) } fn unevaluated(&self) -> Option<&SchemaNode> { - self.unevaluated.as_ref() + self.unevaluated.as_deref() } fn mark_evaluated_indexes(&self, instance: &Value, indexes: &mut Vec) { diff --git a/crates/jsonschema/src/keywords/unevaluated_properties.rs b/crates/jsonschema/src/keywords/unevaluated_properties.rs index 5ee48795..a7575a46 100644 --- a/crates/jsonschema/src/keywords/unevaluated_properties.rs +++ b/crates/jsonschema/src/keywords/unevaluated_properties.rs @@ -42,16 +42,30 @@ pub(crate) struct UnevaluatedPropertiesValidator { filter: F, } -impl UnevaluatedPropertiesValidator { +impl UnevaluatedPropertiesValidator { #[inline] pub(crate) fn compile<'a>( ctx: &'a compiler::Context, parent: &'a Map, ) -> CompilationResult<'a> { - Ok(Box::new(UnevaluatedPropertiesValidator { + Ok(UnevaluatedPropertiesValidator { location: ctx.location().join("unevaluatedProperties"), - filter: F::new(ctx, parent)?, - })) + filter: DefaultPropertiesFilter::new(ctx, parent)?, + } + .into()) + } +} +impl UnevaluatedPropertiesValidator { + #[inline] + pub(crate) fn compile<'a>( + ctx: &'a compiler::Context, + parent: &'a Map, + ) -> CompilationResult<'a> { + Ok(UnevaluatedPropertiesValidator { + location: ctx.location().join("unevaluatedProperties"), + filter: Draft2019PropertiesFilter::new(ctx, parent)?, + } + .into()) } } @@ -100,9 +114,9 @@ impl Validate for UnevaluatedPropertiesValidator { } } -struct Draft2019PropertiesFilter { - unevaluated: Option, - additional: Option, +pub(crate) struct Draft2019PropertiesFilter { + unevaluated: Option>, + additional: Option>, properties: Vec<(String, SchemaNode)>, dependent: Vec<(String, Self)>, pattern_properties: Vec<(fancy_regex::Regex, SchemaNode)>, @@ -262,7 +276,10 @@ impl PropertiesFilter for Draft2019PropertiesFilter { let mut additional = None; if let Some(subschema) = parent.get("additionalProperties") { - additional = Some(compiler::compile(ctx, ctx.as_resource_ref(subschema))?); + additional = Some(Box::new(compiler::compile( + ctx, + ctx.as_resource_ref(subschema), + )?)); } let mut pattern_properties = Vec::new(); @@ -287,7 +304,10 @@ impl PropertiesFilter for Draft2019PropertiesFilter { let mut unevaluated = None; if let Some(subschema) = parent.get("unevaluatedProperties") { - unevaluated = Some(compiler::compile(ctx, ctx.as_resource_ref(subschema))?); + unevaluated = Some(Box::new(compiler::compile( + ctx, + ctx.as_resource_ref(subschema), + )?)); }; let mut all_of = None; @@ -410,13 +430,13 @@ impl PropertiesFilter for Draft2019PropertiesFilter { } fn unevaluated(&self) -> Option<&SchemaNode> { - self.unevaluated.as_ref() + self.unevaluated.as_deref() } } -struct DefaultPropertiesFilter { - unevaluated: Option, - additional: Option, +pub(crate) struct DefaultPropertiesFilter { + unevaluated: Option>, + additional: Option>, properties: Vec<(String, SchemaNode)>, dependent: Vec<(String, Self)>, pattern_properties: Vec<(fancy_regex::Regex, SchemaNode)>, @@ -519,7 +539,10 @@ impl PropertiesFilter for DefaultPropertiesFilter { let mut additional = None; if let Some(subschema) = parent.get("additionalProperties") { - additional = Some(compiler::compile(ctx, ctx.as_resource_ref(subschema))?); + additional = Some(Box::new(compiler::compile( + ctx, + ctx.as_resource_ref(subschema), + )?)); } let mut pattern_properties = Vec::new(); @@ -544,7 +567,10 @@ impl PropertiesFilter for DefaultPropertiesFilter { let mut unevaluated = None; if let Some(subschema) = parent.get("unevaluatedProperties") { - unevaluated = Some(compiler::compile(ctx, ctx.as_resource_ref(subschema))?); + unevaluated = Some(Box::new(compiler::compile( + ctx, + ctx.as_resource_ref(subschema), + )?)); }; let mut all_of = None; @@ -665,7 +691,7 @@ impl PropertiesFilter for DefaultPropertiesFilter { } fn unevaluated(&self) -> Option<&SchemaNode> { - self.unevaluated.as_ref() + self.unevaluated.as_deref() } } diff --git a/crates/jsonschema/src/keywords/unique_items.rs b/crates/jsonschema/src/keywords/unique_items.rs index 51d2e816..7c48255d 100644 --- a/crates/jsonschema/src/keywords/unique_items.rs +++ b/crates/jsonschema/src/keywords/unique_items.rs @@ -103,7 +103,7 @@ pub(crate) struct UniqueItemsValidator { impl UniqueItemsValidator { #[inline] pub(crate) fn compile<'a>(location: Location) -> CompilationResult<'a> { - Ok(Box::new(UniqueItemsValidator { location })) + Ok(UniqueItemsValidator { location }.into()) } } diff --git a/crates/jsonschema/src/node.rs b/crates/jsonschema/src/node.rs index f1e52ed4..092fc3e7 100644 --- a/crates/jsonschema/src/node.rs +++ b/crates/jsonschema/src/node.rs @@ -1,7 +1,7 @@ use crate::{ compiler::Context, error::ErrorIterator, - keywords::{BoxedValidator, Keyword}, + keywords::{KeywordKind, KeywordValue}, output::{Annotations, BasicOutput, ErrorDescription, OutputUnit}, paths::{LazyLocation, Location, LocationSegment}, validator::{PartialApplication, Validate}, @@ -31,12 +31,12 @@ enum NodeValidators { /// /// Here the result of `compiler::compile` called with the `false` value will return a /// `SchemaNode` with a single `BooleanValidator` as it's `validators`. - Boolean { validator: Option }, + Boolean { validator: Option }, /// The result of compiling a schema which is composed of keywords (almost all schemas) Keyword(Box), /// The result of compiling a schema which is "array valued", e.g the "dependencies" keyword of /// draft 7 which can take values which are an array of other property names - Array { validators: Vec }, + Array { validators: Vec }, } impl fmt::Debug for NodeValidators { @@ -53,13 +53,12 @@ struct KeywordValidators { /// The keywords on this node which were not recognized by any vocabularies. These are /// stored so we can later produce them as annotations unmatched_keywords: Option>, - // We should probably use AHashMap here but it breaks a bunch of test which assume - // validators are in a particular order - validators: Vec<(Keyword, BoxedValidator)>, + // TODO: Avoid `KeywordKind` + validators: Vec<(KeywordKind, KeywordValue)>, } impl SchemaNode { - pub(crate) fn from_boolean(ctx: &Context<'_>, validator: Option) -> SchemaNode { + pub(crate) fn from_boolean(ctx: &Context<'_>, validator: Option) -> SchemaNode { SchemaNode { location: ctx.location().clone(), absolute_path: ctx.base_uri(), @@ -69,7 +68,7 @@ impl SchemaNode { pub(crate) fn from_keywords( ctx: &Context<'_>, - validators: Vec<(Keyword, BoxedValidator)>, + validators: Vec<(KeywordKind, KeywordValue)>, unmatched_keywords: Option>, ) -> SchemaNode { SchemaNode { @@ -82,7 +81,7 @@ impl SchemaNode { } } - pub(crate) fn from_array(ctx: &Context<'_>, validators: Vec) -> SchemaNode { + pub(crate) fn from_array(ctx: &Context<'_>, validators: Vec) -> SchemaNode { SchemaNode { location: ctx.location().clone(), absolute_path: ctx.base_uri(), @@ -90,7 +89,7 @@ impl SchemaNode { } } - pub(crate) fn validators(&self) -> impl ExactSizeIterator { + pub(crate) fn validators(&self) -> impl ExactSizeIterator { match &self.validators { NodeValidators::Boolean { validator } => { if let Some(v) = validator { @@ -166,16 +165,16 @@ impl SchemaNode { /// Here we return a `NodeValidatorsErrIter` to avoid allocating in some situations. This isn't /// always possible but for a lot of common cases (e.g nodes with a single child) we can do it. /// This is wrapped in a `Box` by `SchemaNode::validate` - pub(crate) fn err_iter<'a>( + pub(crate) fn iter_errors<'a>( &self, instance: &'a Value, location: &LazyLocation, - ) -> NodeValidatorsErrIter<'a> { + ) -> ErrorIterator<'a> { match &self.validators { NodeValidators::Keyword(kvs) if kvs.validators.len() == 1 => { - NodeValidatorsErrIter::Single(kvs.validators[0].1.iter_errors(instance, location)) + kvs.validators[0].1.iter_errors(instance, location) } - NodeValidators::Keyword(kvs) => NodeValidatorsErrIter::Multiple( + NodeValidators::Keyword(kvs) => Box::new( kvs.validators .iter() .flat_map(|(_, v)| v.iter_errors(instance, location)) @@ -184,11 +183,11 @@ impl SchemaNode { ), NodeValidators::Boolean { validator: Some(v), .. - } => NodeValidatorsErrIter::Single(v.iter_errors(instance, location)), + } => v.iter_errors(instance, location), NodeValidators::Boolean { validator: None, .. - } => NodeValidatorsErrIter::NoErrs, - NodeValidators::Array { validators } => NodeValidatorsErrIter::Multiple( + } => Box::new(std::iter::empty()), + NodeValidators::Array { validators } => Box::new( validators .iter() .flat_map(move |v| v.iter_errors(instance, location)) @@ -210,7 +209,7 @@ impl SchemaNode { annotations: Option>, ) -> PartialApplication<'a> where - I: Iterator)> + 'a, + I: Iterator + 'a, P: Into> + fmt::Display, { let mut success_results: VecDeque> = VecDeque::new(); @@ -293,7 +292,7 @@ impl SchemaNode { impl Validate for SchemaNode { fn iter_errors<'i>(&self, instance: &'i Value, location: &LazyLocation) -> ErrorIterator<'i> { - Box::new(self.err_iter(instance, location)) + Box::new(self.iter_errors(instance, location)) } fn validate<'i>( @@ -382,13 +381,13 @@ impl Validate for SchemaNode { enum NodeValidatorsIter<'a> { NoValidator, - BooleanValidators(std::iter::Once<&'a BoxedValidator>), - KeywordValidators(std::slice::Iter<'a, (Keyword, BoxedValidator)>), - ArrayValidators(std::slice::Iter<'a, BoxedValidator>), + BooleanValidators(std::iter::Once<&'a KeywordValue>), + KeywordValidators(std::slice::Iter<'a, (KeywordKind, KeywordValue)>), + ArrayValidators(std::slice::Iter<'a, KeywordValue>), } impl<'a> Iterator for NodeValidatorsIter<'a> { - type Item = &'a BoxedValidator; + type Item = &'a KeywordValue; fn next(&mut self) -> Option { match self { @@ -423,21 +422,3 @@ impl<'a> ExactSizeIterator for NodeValidatorsIter<'a> { } } } - -pub(crate) enum NodeValidatorsErrIter<'a> { - NoErrs, - Single(ErrorIterator<'a>), - Multiple(std::vec::IntoIter>), -} - -impl<'a> Iterator for NodeValidatorsErrIter<'a> { - type Item = ValidationError<'a>; - - fn next(&mut self) -> Option { - match self { - Self::NoErrs => None, - Self::Single(i) => i.next(), - Self::Multiple(ms) => ms.next(), - } - } -} diff --git a/crates/jsonschema/src/paths.rs b/crates/jsonschema/src/paths.rs index 73ea2d90..e2e8d397 100644 --- a/crates/jsonschema/src/paths.rs +++ b/crates/jsonschema/src/paths.rs @@ -1,7 +1,7 @@ //! Facilities for working with paths within schemas or validated instances. use std::{fmt, sync::Arc}; -use crate::keywords::Keyword; +use crate::keywords::KeywordKind; /// A location segment. #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -105,11 +105,11 @@ impl<'a> From<&'a LazyLocation<'_, '_>> for Location { } } -impl<'a> From<&'a Keyword> for LocationSegment<'a> { - fn from(value: &'a Keyword) -> Self { +impl<'a> From<&'a KeywordKind> for LocationSegment<'a> { + fn from(value: &'a KeywordKind) -> Self { match value { - Keyword::Buildin(k) => LocationSegment::Property(k.as_str()), - Keyword::Custom(s) => LocationSegment::Property(s), + KeywordKind::Builtin(k) => LocationSegment::Property(k.as_str()), + KeywordKind::Custom(s) => LocationSegment::Property(s), } } }