fast_json-schema 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Dockerfile +17 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +68 -0
- data/LICENSE.txt +21 -0
- data/README.md +156 -0
- data/Rakefile +60 -0
- data/build-deps +3 -0
- data/data/invalid.json +31 -0
- data/data/schema.json +150 -0
- data/data/valid.json +49 -0
- data/ext/fast_json/schema/all_of.c +23 -0
- data/ext/fast_json/schema/all_of.h +4 -0
- data/ext/fast_json/schema/any_of.c +22 -0
- data/ext/fast_json/schema/any_of.h +4 -0
- data/ext/fast_json/schema/compiled_schema.c +503 -0
- data/ext/fast_json/schema/compiled_schema.h +10 -0
- data/ext/fast_json/schema/context.c +78 -0
- data/ext/fast_json/schema/error.c +26 -0
- data/ext/fast_json/schema/error.h +5 -0
- data/ext/fast_json/schema/extconf.rb +7 -0
- data/ext/fast_json/schema/formats/custom_format.c +63 -0
- data/ext/fast_json/schema/formats/custom_format.h +4 -0
- data/ext/fast_json/schema/formats/date.c +48 -0
- data/ext/fast_json/schema/formats/date.h +5 -0
- data/ext/fast_json/schema/formats/date_time.c +22 -0
- data/ext/fast_json/schema/formats/date_time.h +4 -0
- data/ext/fast_json/schema/formats/email.c +8 -0
- data/ext/fast_json/schema/formats/email.h +4 -0
- data/ext/fast_json/schema/formats/format.c +68 -0
- data/ext/fast_json/schema/formats/format.h +4 -0
- data/ext/fast_json/schema/formats/hostname.c +8 -0
- data/ext/fast_json/schema/formats/hostname.h +4 -0
- data/ext/fast_json/schema/formats/idn_email.c +8 -0
- data/ext/fast_json/schema/formats/idn_email.h +4 -0
- data/ext/fast_json/schema/formats/idn_hostname.c +8 -0
- data/ext/fast_json/schema/formats/idn_hostname.h +4 -0
- data/ext/fast_json/schema/formats/ipv4.c +8 -0
- data/ext/fast_json/schema/formats/ipv4.h +4 -0
- data/ext/fast_json/schema/formats/ipv6.c +8 -0
- data/ext/fast_json/schema/formats/ipv6.h +4 -0
- data/ext/fast_json/schema/formats/iri.c +8 -0
- data/ext/fast_json/schema/formats/iri.h +4 -0
- data/ext/fast_json/schema/formats/iri_reference.c +8 -0
- data/ext/fast_json/schema/formats/iri_reference.h +4 -0
- data/ext/fast_json/schema/formats/json_pointer.c +8 -0
- data/ext/fast_json/schema/formats/json_pointer.h +4 -0
- data/ext/fast_json/schema/formats/regex.c +27 -0
- data/ext/fast_json/schema/formats/regex.h +4 -0
- data/ext/fast_json/schema/formats/relative_json_pointer.c +57 -0
- data/ext/fast_json/schema/formats/relative_json_pointer.h +4 -0
- data/ext/fast_json/schema/formats/time.c +65 -0
- data/ext/fast_json/schema/formats/time.h +5 -0
- data/ext/fast_json/schema/formats/uri.c +8 -0
- data/ext/fast_json/schema/formats/uri.h +4 -0
- data/ext/fast_json/schema/formats/uri_reference.c +8 -0
- data/ext/fast_json/schema/formats/uri_reference.h +4 -0
- data/ext/fast_json/schema/formats/uri_template.c +8 -0
- data/ext/fast_json/schema/formats/uri_template.h +4 -0
- data/ext/fast_json/schema/formats/utils/addr_spec_parser.c +342 -0
- data/ext/fast_json/schema/formats/utils/addr_spec_parser.h +16 -0
- data/ext/fast_json/schema/formats/utils/hostname_parser.c +113 -0
- data/ext/fast_json/schema/formats/utils/hostname_parser.h +17 -0
- data/ext/fast_json/schema/formats/utils/ip_parser.c +126 -0
- data/ext/fast_json/schema/formats/utils/ip_parser.h +25 -0
- data/ext/fast_json/schema/formats/utils/json_pointer_parser.c +45 -0
- data/ext/fast_json/schema/formats/utils/json_pointer_parser.h +20 -0
- data/ext/fast_json/schema/formats/utils/uri_parser.c +605 -0
- data/ext/fast_json/schema/formats/utils/uri_parser.h +20 -0
- data/ext/fast_json/schema/formats/utils/uri_template_parser.c +235 -0
- data/ext/fast_json/schema/formats/utils/uri_template_parser.h +18 -0
- data/ext/fast_json/schema/formats/utils/utf8.c +73 -0
- data/ext/fast_json/schema/formats/utils/utf8.h +17 -0
- data/ext/fast_json/schema/if.c +31 -0
- data/ext/fast_json/schema/if.h +4 -0
- data/ext/fast_json/schema/is_valid.c +124 -0
- data/ext/fast_json/schema/is_valid.h +6 -0
- data/ext/fast_json/schema/keywords.c +220 -0
- data/ext/fast_json/schema/keywords.h +60 -0
- data/ext/fast_json/schema/nested_schemas.c +68 -0
- data/ext/fast_json/schema/nested_schemas.h +4 -0
- data/ext/fast_json/schema/not.c +11 -0
- data/ext/fast_json/schema/not.h +4 -0
- data/ext/fast_json/schema/one_of.c +23 -0
- data/ext/fast_json/schema/one_of.h +4 -0
- data/ext/fast_json/schema/path.c +44 -0
- data/ext/fast_json/schema/path.h +5 -0
- data/ext/fast_json/schema/properties_val.c +103 -0
- data/ext/fast_json/schema/properties_val.h +6 -0
- data/ext/fast_json/schema/ref.c +7 -0
- data/ext/fast_json/schema/ref.h +4 -0
- data/ext/fast_json/schema/ref_resolver.c +85 -0
- data/ext/fast_json/schema/ref_resolver.h +5 -0
- data/ext/fast_json/schema/schema.c +68 -0
- data/ext/fast_json/schema/schema_collection.c +29 -0
- data/ext/fast_json/schema/schema_collection.h +3 -0
- data/ext/fast_json/schema/types/compiled_schema.h +96 -0
- data/ext/fast_json/schema/types/context.h +27 -0
- data/ext/fast_json/schema/validate.c +63 -0
- data/ext/fast_json/schema/validate.h +19 -0
- data/ext/fast_json/schema/validate_array.c +130 -0
- data/ext/fast_json/schema/validate_array.h +4 -0
- data/ext/fast_json/schema/validate_bool.c +7 -0
- data/ext/fast_json/schema/validate_bool.h +4 -0
- data/ext/fast_json/schema/validate_integer.c +52 -0
- data/ext/fast_json/schema/validate_integer.h +4 -0
- data/ext/fast_json/schema/validate_null.c +7 -0
- data/ext/fast_json/schema/validate_null.h +4 -0
- data/ext/fast_json/schema/validate_number.c +62 -0
- data/ext/fast_json/schema/validate_number.h +4 -0
- data/ext/fast_json/schema/validate_object.c +159 -0
- data/ext/fast_json/schema/validate_object.h +4 -0
- data/ext/fast_json/schema/validate_string.c +32 -0
- data/ext/fast_json/schema/validate_string.h +4 -0
- data/ext/fast_json/schema/value_pointer_caster.h +9 -0
- data/fast_json-schema.gemspec +31 -0
- data/lib/fast_json/schema/error.rb +16 -0
- data/lib/fast_json/schema/version.rb +7 -0
- data/lib/fast_json/schema.rb +50 -0
- data/makefile +10 -0
- metadata +164 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
#include "keywords.h"
|
|
3
|
+
#include "compiled_schema.h"
|
|
4
|
+
#include "types/context.h"
|
|
5
|
+
#include "error.h"
|
|
6
|
+
#include "is_valid.h"
|
|
7
|
+
|
|
8
|
+
extern bool is_valid(VALUE, CompiledSchema *, VALUE, Context *);
|
|
9
|
+
|
|
10
|
+
static CompiledSchema *root_schema(VALUE self) {
|
|
11
|
+
CompiledSchema *compiled_schema;
|
|
12
|
+
VALUE compiled_schema_obj = rb_ivar_get(self, rb_intern("compiled_schema"));
|
|
13
|
+
|
|
14
|
+
return GetCompiledSchema(compiled_schema_obj, compiled_schema);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
VALUE rb_validate(VALUE self, VALUE data) {
|
|
18
|
+
if (!rb_block_given_p()) {
|
|
19
|
+
VALUE args[1] = { data };
|
|
20
|
+
|
|
21
|
+
RETURN_SIZED_ENUMERATOR(self, 1, args, 0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
CompiledSchema *schema = root_schema(self);
|
|
25
|
+
Context *context;
|
|
26
|
+
VALUE context_obj = create_context(&context);
|
|
27
|
+
|
|
28
|
+
schema->validation_function(self, schema, data, context);
|
|
29
|
+
|
|
30
|
+
RB_GC_GUARD(context_obj);
|
|
31
|
+
|
|
32
|
+
return Qnil;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
VALUE rb_valid(VALUE self, VALUE data) {
|
|
36
|
+
CompiledSchema *schema = root_schema(self);
|
|
37
|
+
Context *context;
|
|
38
|
+
VALUE context_obj = create_context(&context);
|
|
39
|
+
|
|
40
|
+
bool valid = is_valid(self, schema, data, context);
|
|
41
|
+
|
|
42
|
+
RB_GC_GUARD(context_obj);
|
|
43
|
+
|
|
44
|
+
return valid ? Qtrue : Qfalse;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
VALUE rb_compile(VALUE self) {
|
|
48
|
+
VALUE is_compiled = rb_ivar_get(self, rb_intern("compiled"));
|
|
49
|
+
|
|
50
|
+
if(is_compiled != Qtrue) compile_schema(self);
|
|
51
|
+
|
|
52
|
+
return self;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
void Init_schema() {
|
|
56
|
+
VALUE fast_json_class = rb_const_get(rb_cObject, rb_intern("FastJSON"));
|
|
57
|
+
VALUE schema_class = rb_const_get(fast_json_class, rb_intern("Schema"));
|
|
58
|
+
|
|
59
|
+
Init_keywords();
|
|
60
|
+
Init_error(schema_class);
|
|
61
|
+
Init_compiled_schema(schema_class);
|
|
62
|
+
Init_context();
|
|
63
|
+
Init_is_valid();
|
|
64
|
+
|
|
65
|
+
rb_define_method(schema_class, "compile", rb_compile, 0);
|
|
66
|
+
rb_define_method(schema_class, "validate", rb_validate, 1);
|
|
67
|
+
rb_define_method(schema_class, "valid?", rb_valid, 1);
|
|
68
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#include "schema_collection.h"
|
|
2
|
+
#include "compiled_schema.h"
|
|
3
|
+
#include "path.h"
|
|
4
|
+
|
|
5
|
+
extern CompiledSchema *create_compiled_schema(VALUE, schema_flag_t);
|
|
6
|
+
extern void compile(CompiledSchema *, VALUE, VALUE, VALUE);
|
|
7
|
+
|
|
8
|
+
void compile_schema_collection(VALUE *schema_member, VALUE ruby_schema_array, VALUE ref_data, VALUE path, VALUE custom_formats) {
|
|
9
|
+
long i;
|
|
10
|
+
VALUE compiled_schema_collection = rb_ary_new();
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* `ruby_schema_array` must be a non-empty array.
|
|
14
|
+
* Perhaps we should check if it's empty.
|
|
15
|
+
*/
|
|
16
|
+
for(i = 0; i < RARRAY_LEN(ruby_schema_array); i++) {
|
|
17
|
+
VALUE ruby_schema = rb_ary_entry(ruby_schema_array, i);
|
|
18
|
+
VALUE new_path = append_long_to_path(path, i);
|
|
19
|
+
|
|
20
|
+
CompiledSchema *compiled_schema = create_compiled_schema(new_path, EXPOSE_TO_RUBY);
|
|
21
|
+
VALUE compiled_schema_obj = WrapCompiledSchema(compiled_schema);
|
|
22
|
+
|
|
23
|
+
compile(compiled_schema, ruby_schema, ref_data, custom_formats);
|
|
24
|
+
|
|
25
|
+
rb_ary_push(compiled_schema_collection, compiled_schema_obj);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
*schema_member = compiled_schema_collection;
|
|
29
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
#include "types/context.h"
|
|
3
|
+
|
|
4
|
+
#define NO_FLAG 0
|
|
5
|
+
#define ROOT_SCHEMA (1 << 0)
|
|
6
|
+
#define EXPOSE_TO_RUBY (1 << 1)
|
|
7
|
+
|
|
8
|
+
#define IS_CHILD(compiled_schema) ((compiled_schema->flags & ROOT_SCHEMA) == 0)
|
|
9
|
+
#define INTERNAL_ONLY(compiled_schema) ((compiled_schema->flags & EXPOSE_TO_RUBY) == 0)
|
|
10
|
+
|
|
11
|
+
#ifndef FAST_JSON_SCHEMA_COMPILED_SCHEMA_TYPE
|
|
12
|
+
#define FAST_JSON_SCHEMA_COMPILED_SCHEMA_TYPE 1
|
|
13
|
+
|
|
14
|
+
typedef struct compiled_schema_struct CompiledSchema;
|
|
15
|
+
|
|
16
|
+
typedef void (*validation_function)(VALUE, CompiledSchema *, VALUE, Context *);
|
|
17
|
+
typedef void (*format_validation_function)(VALUE, CompiledSchema *, VALUE, Context *);
|
|
18
|
+
|
|
19
|
+
typedef unsigned char schema_flag_t;
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* TODO:
|
|
23
|
+
* Currently all the validation keywords are stored flat in this struct
|
|
24
|
+
* which is a waste of memory. I'm planning to use union for sustaining
|
|
25
|
+
* the data locality and reducing the amount of memory wasted.
|
|
26
|
+
*/
|
|
27
|
+
typedef struct compiled_schema_struct {
|
|
28
|
+
schema_flag_t flags;
|
|
29
|
+
VALUE path;
|
|
30
|
+
|
|
31
|
+
VALUE id_val;
|
|
32
|
+
VALUE ref_val;
|
|
33
|
+
VALUE recursiveAnchor_val;
|
|
34
|
+
VALUE recursiveRef_val;
|
|
35
|
+
|
|
36
|
+
CompiledSchema *ref_schema;
|
|
37
|
+
|
|
38
|
+
validation_function validation_function;
|
|
39
|
+
validation_function type_validation_function;
|
|
40
|
+
format_validation_function format_validation_function;
|
|
41
|
+
|
|
42
|
+
VALUE custom_format_callable_val;
|
|
43
|
+
VALUE custom_format_error_key_val;
|
|
44
|
+
|
|
45
|
+
VALUE const_val;
|
|
46
|
+
VALUE enum_val;
|
|
47
|
+
|
|
48
|
+
CompiledSchema *if_schema;
|
|
49
|
+
CompiledSchema *then_schema;
|
|
50
|
+
CompiledSchema *else_schema;
|
|
51
|
+
|
|
52
|
+
VALUE allOf_val;
|
|
53
|
+
VALUE anyOf_val;
|
|
54
|
+
VALUE oneOf_val;
|
|
55
|
+
CompiledSchema *not_schema;
|
|
56
|
+
|
|
57
|
+
VALUE multipleOf_val;
|
|
58
|
+
VALUE maximum_val;
|
|
59
|
+
VALUE exclusiveMaximum_val;
|
|
60
|
+
VALUE minimum_val;
|
|
61
|
+
VALUE exclusiveMinimum_val;
|
|
62
|
+
|
|
63
|
+
VALUE maxLength_val;
|
|
64
|
+
VALUE minLength_val;
|
|
65
|
+
VALUE pattern_val;
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
* `items` can be either a JSON schema or an array of valid JSON schemas.
|
|
69
|
+
*
|
|
70
|
+
* - `items_schema` is set if it's a JSON schema
|
|
71
|
+
* - `items_val` is set if it's an array of JSON schemas
|
|
72
|
+
*/
|
|
73
|
+
CompiledSchema *items_schema;
|
|
74
|
+
VALUE items_val;
|
|
75
|
+
CompiledSchema *additionalItems_schema;
|
|
76
|
+
CompiledSchema *contains_schema;
|
|
77
|
+
VALUE maxItems_val;
|
|
78
|
+
VALUE minItems_val;
|
|
79
|
+
VALUE uniqueItems_val;
|
|
80
|
+
VALUE maxContains_val;
|
|
81
|
+
VALUE minContains_val;
|
|
82
|
+
|
|
83
|
+
VALUE properties_val;
|
|
84
|
+
VALUE patternProperties_val;
|
|
85
|
+
CompiledSchema *propertyNames_schema;
|
|
86
|
+
CompiledSchema *additionalProperties_schema;
|
|
87
|
+
VALUE maxProperties_val;
|
|
88
|
+
VALUE minProperties_val;
|
|
89
|
+
VALUE required_val;
|
|
90
|
+
VALUE dependencies_val;
|
|
91
|
+
|
|
92
|
+
CompiledSchema **nested_schemas;
|
|
93
|
+
size_t nested_schemas_count;
|
|
94
|
+
} CompiledSchema;
|
|
95
|
+
|
|
96
|
+
#endif
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
|
|
3
|
+
#ifndef FAST_JSON_SCHEMA_CONTEXT_TYPE
|
|
4
|
+
#define FAST_JSON_SCHEMA_CONTEXT_TYPE 1
|
|
5
|
+
|
|
6
|
+
#define MAX_CONTEXT_DEPTH 1000
|
|
7
|
+
|
|
8
|
+
typedef struct context_struct {
|
|
9
|
+
VALUE path[MAX_CONTEXT_DEPTH];
|
|
10
|
+
int depth;
|
|
11
|
+
bool short_circuit_on_error;
|
|
12
|
+
} Context;
|
|
13
|
+
|
|
14
|
+
VALUE create_context(Context **out_context);
|
|
15
|
+
void Init_context(void);
|
|
16
|
+
|
|
17
|
+
#endif
|
|
18
|
+
|
|
19
|
+
#define INCR_CONTEXT(context) \
|
|
20
|
+
do { \
|
|
21
|
+
if(++context->depth > MAX_CONTEXT_DEPTH) \
|
|
22
|
+
rb_raise(rb_eRuntimeError, "Document is too deep"); \
|
|
23
|
+
} while(0);
|
|
24
|
+
|
|
25
|
+
#define DECR_CONTEXT(context) context->depth--;
|
|
26
|
+
|
|
27
|
+
#define ADD_TO_CONTEXT(context, value) context->path[context->depth] = value;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#include "validate.h"
|
|
2
|
+
#include "error.h"
|
|
3
|
+
|
|
4
|
+
void no_op_validate(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
void false_validate(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
9
|
+
yield_error(compiled_schema, data, context, "false_schema");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
void validate_by_data_type(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
13
|
+
if(RB_INTEGER_TYPE_P(data)) {
|
|
14
|
+
validate_integer(schema, compiled_schema, data, context);
|
|
15
|
+
} else if(RB_TYPE_P(data, T_FLOAT)) {
|
|
16
|
+
validate_number(schema, compiled_schema, data, context);
|
|
17
|
+
} else if(RB_TYPE_P(data, T_STRING)) {
|
|
18
|
+
validate_string(schema, compiled_schema, data, context);
|
|
19
|
+
} else if(RB_TYPE_P(data, T_HASH)) {
|
|
20
|
+
validate_object(schema, compiled_schema, data, context);
|
|
21
|
+
} else if(RB_TYPE_P(data, T_ARRAY)) {
|
|
22
|
+
validate_array(schema, compiled_schema, data, context);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static void validate_const(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
27
|
+
VALUE equal = rb_funcall(compiled_schema->const_val, rb_intern("=="), 1, data);
|
|
28
|
+
|
|
29
|
+
if(equal == Qfalse)
|
|
30
|
+
yield_error(compiled_schema, data, context, "const");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static void validate_enum(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
34
|
+
VALUE include = rb_funcall(compiled_schema->enum_val, rb_intern("include?"), 1, data);
|
|
35
|
+
|
|
36
|
+
if(include == Qfalse)
|
|
37
|
+
yield_error(compiled_schema, data, context, "enum");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
void validate(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
41
|
+
compiled_schema->type_validation_function(schema, compiled_schema, data, context);
|
|
42
|
+
|
|
43
|
+
if(compiled_schema->const_val != Qundef)
|
|
44
|
+
validate_const(schema, compiled_schema, data, context);
|
|
45
|
+
|
|
46
|
+
if(compiled_schema->enum_val != Qundef)
|
|
47
|
+
validate_enum(schema, compiled_schema, data, context);
|
|
48
|
+
|
|
49
|
+
if(compiled_schema->if_schema != NULL)
|
|
50
|
+
validate_if(schema, compiled_schema, data, context);
|
|
51
|
+
|
|
52
|
+
if(compiled_schema->not_schema != NULL)
|
|
53
|
+
validate_not(schema, compiled_schema, data, context);
|
|
54
|
+
|
|
55
|
+
if(compiled_schema->allOf_val != Qundef)
|
|
56
|
+
validate_all_of(schema, compiled_schema, data, context);
|
|
57
|
+
|
|
58
|
+
if(compiled_schema->anyOf_val != Qundef)
|
|
59
|
+
validate_any_of(schema, compiled_schema, data, context);
|
|
60
|
+
|
|
61
|
+
if(compiled_schema->oneOf_val != Qundef)
|
|
62
|
+
validate_one_of(schema, compiled_schema, data, context);
|
|
63
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
#include "compiled_schema.h"
|
|
3
|
+
#include "if.h"
|
|
4
|
+
#include "all_of.h"
|
|
5
|
+
#include "any_of.h"
|
|
6
|
+
#include "one_of.h"
|
|
7
|
+
#include "not.h"
|
|
8
|
+
#include "validate_array.h"
|
|
9
|
+
#include "validate_bool.h"
|
|
10
|
+
#include "validate_integer.h"
|
|
11
|
+
#include "validate_null.h"
|
|
12
|
+
#include "validate_number.h"
|
|
13
|
+
#include "validate_object.h"
|
|
14
|
+
#include "validate_string.h"
|
|
15
|
+
|
|
16
|
+
void no_op_validate(VALUE, CompiledSchema *, VALUE, Context *);
|
|
17
|
+
void false_validate(VALUE, CompiledSchema *, VALUE, Context *);
|
|
18
|
+
void validate_by_data_type(VALUE, CompiledSchema *, VALUE, Context *);
|
|
19
|
+
void validate(VALUE, CompiledSchema *, VALUE, Context *);
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#include "validate_array.h"
|
|
2
|
+
#include "error.h"
|
|
3
|
+
|
|
4
|
+
extern bool is_valid(VALUE, CompiledSchema *, VALUE, Context *);
|
|
5
|
+
|
|
6
|
+
static void validate_items(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
7
|
+
long i;
|
|
8
|
+
CompiledSchema *items_schema = compiled_schema->items_schema;
|
|
9
|
+
|
|
10
|
+
INCR_CONTEXT(context);
|
|
11
|
+
|
|
12
|
+
for(i = 0; i < RARRAY_LEN(data); i++) {
|
|
13
|
+
ADD_TO_CONTEXT(context, LONG2NUM(i));
|
|
14
|
+
|
|
15
|
+
items_schema->validation_function(schema, items_schema, rb_ary_entry(data, i), context);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
DECR_CONTEXT(context);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* Returns `true` if all the items in the array instance are validated.
|
|
23
|
+
* Returns `false` otherwise.
|
|
24
|
+
*/
|
|
25
|
+
static bool validate_with_multiple_items_schema(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
26
|
+
long i;
|
|
27
|
+
long data_length = RARRAY_LEN(data);
|
|
28
|
+
long items_val_length = RARRAY_LEN(compiled_schema->items_val);
|
|
29
|
+
long upper_bound = (items_val_length < data_length) ? items_val_length : data_length;
|
|
30
|
+
|
|
31
|
+
INCR_CONTEXT(context);
|
|
32
|
+
|
|
33
|
+
for(i = 0; i < upper_bound; i++) {
|
|
34
|
+
ADD_TO_CONTEXT(context, LONG2NUM(i));
|
|
35
|
+
|
|
36
|
+
CompiledSchema *relevant_schema;
|
|
37
|
+
VALUE relevant_schema_obj = rb_ary_entry(compiled_schema->items_val, i);
|
|
38
|
+
|
|
39
|
+
GetCompiledSchema(relevant_schema_obj, relevant_schema);
|
|
40
|
+
|
|
41
|
+
relevant_schema->validation_function(schema, relevant_schema, rb_ary_entry(data, i), context);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
DECR_CONTEXT(context);
|
|
45
|
+
|
|
46
|
+
return (data_length <= items_val_length);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static void validate_additional_items(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
50
|
+
long i = RARRAY_LEN(compiled_schema->items_val);
|
|
51
|
+
CompiledSchema *additionalItems_schema = compiled_schema->additionalItems_schema;
|
|
52
|
+
|
|
53
|
+
INCR_CONTEXT(context);
|
|
54
|
+
|
|
55
|
+
for(; i < RARRAY_LEN(data); i++) {
|
|
56
|
+
ADD_TO_CONTEXT(context, LONG2NUM(i));
|
|
57
|
+
|
|
58
|
+
additionalItems_schema->validation_function(schema, additionalItems_schema, rb_ary_entry(data, i), context);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
DECR_CONTEXT(context);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static void validate_contains(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
65
|
+
long i, valid_count = 0;
|
|
66
|
+
|
|
67
|
+
for(i = 0; i < RARRAY_LEN(data); i++) {
|
|
68
|
+
VALUE entry = rb_ary_entry(data, i);
|
|
69
|
+
|
|
70
|
+
bool valid = is_valid(schema, compiled_schema->contains_schema, entry, context);
|
|
71
|
+
|
|
72
|
+
if(valid)
|
|
73
|
+
valid_count++;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if(RB_INTEGER_TYPE_P(compiled_schema->maxContains_val)) {
|
|
77
|
+
if(valid_count > NUM2LONG(compiled_schema->maxContains_val))
|
|
78
|
+
yield_error(compiled_schema, data, context, "maxContains");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/*
|
|
82
|
+
* According to spec description, when the `minContains` keyword is missing, we must check
|
|
83
|
+
* if there is at least one valid item against the `contains` schema.
|
|
84
|
+
*
|
|
85
|
+
* If the `minContains` keyword exists, we must check if the number of valid items are
|
|
86
|
+
* greater than or equal to the `minContains` value.
|
|
87
|
+
*/
|
|
88
|
+
if(RB_INTEGER_TYPE_P(compiled_schema->minContains_val)) {
|
|
89
|
+
if(valid_count < NUM2LONG(compiled_schema->minContains_val))
|
|
90
|
+
yield_error(compiled_schema, data, context, "minContains");
|
|
91
|
+
} else {
|
|
92
|
+
if(valid_count == 0)
|
|
93
|
+
yield_error(compiled_schema->contains_schema, data, context, "contains");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
void validate_array(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
98
|
+
if(!RB_TYPE_P(data, T_ARRAY))
|
|
99
|
+
return yield_error(compiled_schema, data, context, "type_array");
|
|
100
|
+
|
|
101
|
+
if(compiled_schema->maxItems_val != Qundef) {
|
|
102
|
+
if(RARRAY_LEN(data) > NUM2LONG(compiled_schema->maxItems_val))
|
|
103
|
+
yield_error(compiled_schema, data, context, "maxItems");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if(compiled_schema->minItems_val != Qundef) {
|
|
107
|
+
if(RARRAY_LEN(data) < NUM2LONG(compiled_schema->minItems_val))
|
|
108
|
+
yield_error(compiled_schema, data, context, "minItems");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if(compiled_schema->uniqueItems_val == Qtrue) {
|
|
112
|
+
// I don't really want to deal with comparing array elements
|
|
113
|
+
VALUE unique_arr = rb_funcall(data, rb_intern("uniq"), 0);
|
|
114
|
+
|
|
115
|
+
if(RARRAY_LEN(unique_arr) < RARRAY_LEN(data))
|
|
116
|
+
yield_error(compiled_schema, data, context, "uniqueItems");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if(compiled_schema->items_schema != NULL) {
|
|
120
|
+
validate_items(schema, compiled_schema, data, context);
|
|
121
|
+
} else if(compiled_schema->items_val != Qundef) {
|
|
122
|
+
long all_validated = validate_with_multiple_items_schema(schema, compiled_schema, data, context);
|
|
123
|
+
|
|
124
|
+
if(!all_validated && compiled_schema->additionalItems_schema != NULL)
|
|
125
|
+
validate_additional_items(schema, compiled_schema, data, context);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if(compiled_schema->contains_schema != NULL)
|
|
129
|
+
validate_contains(schema, compiled_schema, data, context);
|
|
130
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#include "validate_integer.h"
|
|
2
|
+
#include "error.h"
|
|
3
|
+
|
|
4
|
+
void validate_integer(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
5
|
+
if(!RB_INTEGER_TYPE_P(data))
|
|
6
|
+
return yield_error(compiled_schema, data, context, "type_integer");
|
|
7
|
+
|
|
8
|
+
long data_c = NUM2LONG(data);
|
|
9
|
+
|
|
10
|
+
if(RB_INTEGER_TYPE_P(compiled_schema->multipleOf_val)) {
|
|
11
|
+
if(data_c % NUM2LONG(compiled_schema->multipleOf_val) != 0)
|
|
12
|
+
yield_error(compiled_schema, data, context, "multipleOf");
|
|
13
|
+
} else if(RB_TYPE_P(compiled_schema->multipleOf_val, T_FLOAT)) {
|
|
14
|
+
double multipleOf = NUM2DBL(compiled_schema->multipleOf_val);
|
|
15
|
+
double div = data_c / multipleOf;
|
|
16
|
+
|
|
17
|
+
if(div - (int)div != 0.0) // fmod() does not work here due to IEEE floating point arithmetics
|
|
18
|
+
yield_error(compiled_schema, data, context, "multipleOf");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if(RB_INTEGER_TYPE_P(compiled_schema->maximum_val)) {
|
|
22
|
+
if(data_c > NUM2LONG(compiled_schema->maximum_val))
|
|
23
|
+
yield_error(compiled_schema, data, context, "maximum");
|
|
24
|
+
} else if(RB_TYPE_P(compiled_schema->maximum_val, T_FLOAT)) {
|
|
25
|
+
if(data_c > NUM2DBL(compiled_schema->maximum_val))
|
|
26
|
+
yield_error(compiled_schema, data, context, "maximum");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if(RB_INTEGER_TYPE_P(compiled_schema->exclusiveMaximum_val)) {
|
|
30
|
+
if(data_c >= NUM2LONG(compiled_schema->exclusiveMaximum_val))
|
|
31
|
+
yield_error(compiled_schema, data, context, "exclusiveMaximum");
|
|
32
|
+
} else if(RB_TYPE_P(compiled_schema->exclusiveMaximum_val, T_FLOAT)) {
|
|
33
|
+
if(data_c >= NUM2DBL(compiled_schema->exclusiveMaximum_val))
|
|
34
|
+
yield_error(compiled_schema, data, context, "exclusiveMaximum");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if(RB_INTEGER_TYPE_P(compiled_schema->minimum_val)) {
|
|
38
|
+
if(data_c < NUM2LONG(compiled_schema->minimum_val))
|
|
39
|
+
yield_error(compiled_schema, data, context, "minimum");
|
|
40
|
+
} else if(RB_TYPE_P(compiled_schema->minimum_val, T_FLOAT)) {
|
|
41
|
+
if(data_c < NUM2DBL(compiled_schema->minimum_val))
|
|
42
|
+
yield_error(compiled_schema, data, context, "minimum");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if(RB_INTEGER_TYPE_P(compiled_schema->exclusiveMinimum_val)) {
|
|
46
|
+
if(data_c <= NUM2LONG(compiled_schema->exclusiveMinimum_val))
|
|
47
|
+
yield_error(compiled_schema, data, context, "exclusiveMinimum");
|
|
48
|
+
} else if(RB_TYPE_P(compiled_schema->exclusiveMinimum_val, T_FLOAT)) {
|
|
49
|
+
if(data_c <= NUM2DBL(compiled_schema->exclusiveMinimum_val))
|
|
50
|
+
yield_error(compiled_schema, data, context, "exclusiveMinimum");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#include "validate_number.h"
|
|
2
|
+
#include "error.h"
|
|
3
|
+
|
|
4
|
+
void validate_number(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
5
|
+
if(!RB_INTEGER_TYPE_P(data) && !RB_TYPE_P(data, T_FLOAT))
|
|
6
|
+
return yield_error(compiled_schema, data, context, "type_number");
|
|
7
|
+
|
|
8
|
+
double data_c;
|
|
9
|
+
|
|
10
|
+
if(!RB_INTEGER_TYPE_P(data)) {
|
|
11
|
+
data_c = NUM2DBL(data);
|
|
12
|
+
} else {
|
|
13
|
+
data_c = NUM2LONG(data);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
if(RB_INTEGER_TYPE_P(compiled_schema->multipleOf_val)) {
|
|
18
|
+
long multipleOf = NUM2LONG(compiled_schema->multipleOf_val);
|
|
19
|
+
double div = data_c / multipleOf;
|
|
20
|
+
|
|
21
|
+
if(div - (int)div != 0.0) // fmod() does not work here due to IEEE floating point arithmetics
|
|
22
|
+
yield_error(compiled_schema, data, context, "multipleOf");
|
|
23
|
+
} else if(RB_TYPE_P(compiled_schema->multipleOf_val, T_FLOAT)) {
|
|
24
|
+
double multipleOf = NUM2DBL(compiled_schema->multipleOf_val);
|
|
25
|
+
double div = data_c / multipleOf;
|
|
26
|
+
|
|
27
|
+
if(div - (int)div != 0.0) // fmod() does not work here due to IEEE floating point arithmetics
|
|
28
|
+
yield_error(compiled_schema, data, context, "multipleOf");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if(RB_INTEGER_TYPE_P(compiled_schema->maximum_val)) {
|
|
32
|
+
if(data_c > NUM2LONG(compiled_schema->maximum_val))
|
|
33
|
+
yield_error(compiled_schema, data, context, "maximum");
|
|
34
|
+
} else if(RB_TYPE_P(compiled_schema->maximum_val, T_FLOAT)) {
|
|
35
|
+
if(data_c > NUM2DBL(compiled_schema->maximum_val))
|
|
36
|
+
yield_error(compiled_schema, data, context, "maximum");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if(RB_INTEGER_TYPE_P(compiled_schema->exclusiveMaximum_val)) {
|
|
40
|
+
if(data_c >= NUM2LONG(compiled_schema->exclusiveMaximum_val))
|
|
41
|
+
yield_error(compiled_schema, data, context, "exclusiveMaximum");
|
|
42
|
+
} else if(RB_TYPE_P(compiled_schema->exclusiveMaximum_val, T_FLOAT)) {
|
|
43
|
+
if(data_c >= NUM2DBL(compiled_schema->exclusiveMaximum_val))
|
|
44
|
+
yield_error(compiled_schema, data, context, "exclusiveMaximum");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if(RB_INTEGER_TYPE_P(compiled_schema->minimum_val)) {
|
|
48
|
+
if(data_c < NUM2LONG(compiled_schema->minimum_val))
|
|
49
|
+
yield_error(compiled_schema, data, context, "minimum");
|
|
50
|
+
} else if(RB_TYPE_P(compiled_schema->minimum_val, T_FLOAT)) {
|
|
51
|
+
if(data_c < NUM2DBL(compiled_schema->minimum_val))
|
|
52
|
+
yield_error(compiled_schema, data, context, "minimum");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if(RB_INTEGER_TYPE_P(compiled_schema->exclusiveMinimum_val)) {
|
|
56
|
+
if(data_c <= NUM2LONG(compiled_schema->exclusiveMinimum_val))
|
|
57
|
+
yield_error(compiled_schema, data, context, "exclusiveMinimum");
|
|
58
|
+
} else if(RB_TYPE_P(compiled_schema->exclusiveMinimum_val, T_FLOAT)) {
|
|
59
|
+
if(data_c <= NUM2DBL(compiled_schema->exclusiveMinimum_val))
|
|
60
|
+
yield_error(compiled_schema, data, context, "exclusiveMinimum");
|
|
61
|
+
}
|
|
62
|
+
}
|