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,23 @@
|
|
|
1
|
+
#include "all_of.h"
|
|
2
|
+
#include "error.h"
|
|
3
|
+
|
|
4
|
+
extern bool is_valid(VALUE, CompiledSchema *, VALUE, Context *);
|
|
5
|
+
|
|
6
|
+
void validate_all_of(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
7
|
+
long i, valid_count = 0;
|
|
8
|
+
|
|
9
|
+
for(i = 0; i < RARRAY_LEN(compiled_schema->allOf_val); i++) {
|
|
10
|
+
VALUE child_compiled_schema_obj = rb_ary_entry(compiled_schema->allOf_val, i);
|
|
11
|
+
|
|
12
|
+
CompiledSchema *child_compiled_schema;
|
|
13
|
+
GetCompiledSchema(child_compiled_schema_obj, child_compiled_schema);
|
|
14
|
+
|
|
15
|
+
bool valid = is_valid(schema, child_compiled_schema, data, context);
|
|
16
|
+
|
|
17
|
+
if(valid)
|
|
18
|
+
valid_count++;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if(valid_count != RARRAY_LEN(compiled_schema->allOf_val))
|
|
22
|
+
yield_error(compiled_schema, data, context, "allOf");
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#include "any_of.h"
|
|
2
|
+
#include "error.h"
|
|
3
|
+
|
|
4
|
+
extern bool is_valid(VALUE, CompiledSchema *, VALUE, Context *);
|
|
5
|
+
|
|
6
|
+
void validate_any_of(VALUE schema, CompiledSchema *compiled_schema, VALUE data, Context *context) {
|
|
7
|
+
long i;
|
|
8
|
+
|
|
9
|
+
for(i = 0; i < RARRAY_LEN(compiled_schema->anyOf_val); i++) {
|
|
10
|
+
VALUE child_compiled_schema_obj = rb_ary_entry(compiled_schema->anyOf_val, i);
|
|
11
|
+
|
|
12
|
+
CompiledSchema *child_compiled_schema;
|
|
13
|
+
GetCompiledSchema(child_compiled_schema_obj, child_compiled_schema);
|
|
14
|
+
|
|
15
|
+
bool valid = is_valid(schema, child_compiled_schema, data, context);
|
|
16
|
+
|
|
17
|
+
if(valid)
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
yield_error(compiled_schema, data, context, "anyOf");
|
|
22
|
+
}
|
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
#include "compiled_schema.h"
|
|
2
|
+
#include "keywords.h"
|
|
3
|
+
#include "validate.h"
|
|
4
|
+
#include "path.h"
|
|
5
|
+
#include "value_pointer_caster.h"
|
|
6
|
+
#include "properties_val.h"
|
|
7
|
+
#include "schema_collection.h"
|
|
8
|
+
#include "ref.h"
|
|
9
|
+
#include "ref_resolver.h"
|
|
10
|
+
#include "nested_schemas.h"
|
|
11
|
+
#include "formats/format.h"
|
|
12
|
+
|
|
13
|
+
#define ASSIGN_ANY_VALUE_TO_COMPILED_SCHEMA(keyword) \
|
|
14
|
+
do { \
|
|
15
|
+
VALUE keyword##_val = rb_hash_lookup2(ruby_schema, keyword##_str, Qundef); \
|
|
16
|
+
\
|
|
17
|
+
if(keyword##_val != Qundef) \
|
|
18
|
+
compiled_schema->keyword##_val = keyword##_val; \
|
|
19
|
+
} while(0);
|
|
20
|
+
|
|
21
|
+
#define ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_1(keyword, type) \
|
|
22
|
+
do { \
|
|
23
|
+
VALUE keyword##_val = rb_hash_aref(ruby_schema, keyword##_str); \
|
|
24
|
+
\
|
|
25
|
+
if(RB_TYPE_P(keyword##_val, type)) \
|
|
26
|
+
compiled_schema->keyword##_val = keyword##_val; \
|
|
27
|
+
} while(0);
|
|
28
|
+
|
|
29
|
+
#define ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_2(keyword, type_1, type_2) \
|
|
30
|
+
do { \
|
|
31
|
+
VALUE keyword##_val = rb_hash_aref(ruby_schema, keyword##_str); \
|
|
32
|
+
\
|
|
33
|
+
if(RB_TYPE_P(keyword##_val, type_1) || \
|
|
34
|
+
RB_TYPE_P(keyword##_val, type_2)) \
|
|
35
|
+
compiled_schema->keyword##_val = keyword##_val; \
|
|
36
|
+
} while(0);
|
|
37
|
+
|
|
38
|
+
#define ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(keyword, type_1, type_2, type_3) \
|
|
39
|
+
do { \
|
|
40
|
+
VALUE keyword##_val = rb_hash_aref(ruby_schema, keyword##_str); \
|
|
41
|
+
\
|
|
42
|
+
if(RB_TYPE_P(keyword##_val, type_1) || \
|
|
43
|
+
RB_TYPE_P(keyword##_val, type_2) || \
|
|
44
|
+
RB_TYPE_P(keyword##_val, type_3)) \
|
|
45
|
+
compiled_schema->keyword##_val = keyword##_val; \
|
|
46
|
+
} while(0);
|
|
47
|
+
|
|
48
|
+
#define ASSIGN_SCHEMA_TO_COMPILED_SCHEMA(keyword) \
|
|
49
|
+
do { \
|
|
50
|
+
VALUE keyword##_val = rb_hash_aref(ruby_schema, keyword##_str); \
|
|
51
|
+
\
|
|
52
|
+
if(RB_TYPE_P(keyword##_val, T_HASH) || \
|
|
53
|
+
RB_TYPE_P(keyword##_val, T_FALSE) || \
|
|
54
|
+
RB_TYPE_P(keyword##_val, T_TRUE)) \
|
|
55
|
+
{ \
|
|
56
|
+
VALUE child_path = new_path(compiled_schema->path, keyword##_str); \
|
|
57
|
+
CompiledSchema *child_schema = create_compiled_schema(child_path, NO_FLAG); \
|
|
58
|
+
compiled_schema->keyword##_schema = child_schema; \
|
|
59
|
+
\
|
|
60
|
+
compile(child_schema, keyword##_val, ref_data, custom_formats); \
|
|
61
|
+
} \
|
|
62
|
+
} while(0);
|
|
63
|
+
|
|
64
|
+
#define ASSIGN_SCHEMA_COLLECTION_TO_COMPILED_SCHEMA(keyword) \
|
|
65
|
+
do { \
|
|
66
|
+
VALUE keyword##_val = rb_hash_lookup2(ruby_schema, keyword##_str, Qundef); \
|
|
67
|
+
\
|
|
68
|
+
if(RB_TYPE_P(keyword##_val, T_ARRAY)) { \
|
|
69
|
+
VALUE child_path = new_path(compiled_schema->path, keyword##_str); \
|
|
70
|
+
compile_schema_collection(&(compiled_schema->keyword##_val), keyword##_val, ref_data, child_path, custom_formats); \
|
|
71
|
+
} \
|
|
72
|
+
} while(0);
|
|
73
|
+
|
|
74
|
+
#define COMPACT_VALUE(keyword) \
|
|
75
|
+
do { \
|
|
76
|
+
if(compiled_schema->keyword##_val != Qundef) \
|
|
77
|
+
compiled_schema->keyword##_val = rb_gc_location(compiled_schema->keyword##_val); \
|
|
78
|
+
} while(0);
|
|
79
|
+
|
|
80
|
+
#define COMPACT_CHILD_SCHEMA(keyword) \
|
|
81
|
+
do { \
|
|
82
|
+
if(compiled_schema->keyword##_schema != NULL) \
|
|
83
|
+
compact_compiled_schema(compiled_schema->keyword##_schema); \
|
|
84
|
+
} while(0);
|
|
85
|
+
|
|
86
|
+
#define MARK_VALUE(keyword) \
|
|
87
|
+
do { \
|
|
88
|
+
if(compiled_schema->keyword##_val != Qundef) \
|
|
89
|
+
rb_gc_mark(compiled_schema->keyword##_val); \
|
|
90
|
+
} while(0);
|
|
91
|
+
|
|
92
|
+
#define MARK_CHILD_SCHEMA(keyword) \
|
|
93
|
+
do { \
|
|
94
|
+
if(compiled_schema->keyword##_schema != NULL) \
|
|
95
|
+
mark_compiled_schema(compiled_schema->keyword##_schema); \
|
|
96
|
+
} while(0);
|
|
97
|
+
|
|
98
|
+
#define FREE_CHILD_SCHEMA(keyword) \
|
|
99
|
+
do { \
|
|
100
|
+
if(compiled_schema->keyword##_schema != NULL) \
|
|
101
|
+
free_compiled_schema(compiled_schema->keyword##_schema); \
|
|
102
|
+
} while(0);
|
|
103
|
+
|
|
104
|
+
VALUE compiled_schema_class;
|
|
105
|
+
|
|
106
|
+
/*
|
|
107
|
+
* Here I mark all the values even if they are immediate values like integers or other
|
|
108
|
+
* values which should be already marked by the schema hash object provided while creating
|
|
109
|
+
* the `FastJSON::Schema` instance but it's better to be safe than sorry.
|
|
110
|
+
*/
|
|
111
|
+
static void mark_compiled_schema(CompiledSchema *compiled_schema) {
|
|
112
|
+
rb_gc_mark(compiled_schema->path);
|
|
113
|
+
|
|
114
|
+
MARK_VALUE(id);
|
|
115
|
+
MARK_VALUE(ref);
|
|
116
|
+
MARK_VALUE(recursiveAnchor);
|
|
117
|
+
MARK_VALUE(recursiveRef);
|
|
118
|
+
|
|
119
|
+
MARK_VALUE(const);
|
|
120
|
+
MARK_VALUE(enum);
|
|
121
|
+
|
|
122
|
+
MARK_VALUE(multipleOf);
|
|
123
|
+
MARK_VALUE(maximum);
|
|
124
|
+
MARK_VALUE(exclusiveMaximum);
|
|
125
|
+
MARK_VALUE(minimum);
|
|
126
|
+
MARK_VALUE(exclusiveMinimum);
|
|
127
|
+
|
|
128
|
+
MARK_VALUE(maxLength);
|
|
129
|
+
MARK_VALUE(minLength);
|
|
130
|
+
MARK_VALUE(pattern);
|
|
131
|
+
|
|
132
|
+
MARK_VALUE(custom_format_callable);
|
|
133
|
+
MARK_VALUE(custom_format_error_key);
|
|
134
|
+
|
|
135
|
+
MARK_VALUE(items); // This will mark the `items_val` not the `items_schema`.
|
|
136
|
+
MARK_VALUE(maxItems);
|
|
137
|
+
MARK_VALUE(minItems);
|
|
138
|
+
MARK_VALUE(uniqueItems);
|
|
139
|
+
MARK_VALUE(maxContains);
|
|
140
|
+
MARK_VALUE(minContains);
|
|
141
|
+
|
|
142
|
+
MARK_VALUE(properties);
|
|
143
|
+
MARK_VALUE(patternProperties);
|
|
144
|
+
MARK_VALUE(maxProperties);
|
|
145
|
+
MARK_VALUE(minProperties);
|
|
146
|
+
MARK_VALUE(required);
|
|
147
|
+
MARK_VALUE(dependencies);
|
|
148
|
+
|
|
149
|
+
MARK_CHILD_SCHEMA(if);
|
|
150
|
+
MARK_CHILD_SCHEMA(then);
|
|
151
|
+
MARK_CHILD_SCHEMA(else);
|
|
152
|
+
|
|
153
|
+
MARK_VALUE(allOf);
|
|
154
|
+
MARK_VALUE(anyOf);
|
|
155
|
+
MARK_VALUE(oneOf);
|
|
156
|
+
MARK_CHILD_SCHEMA(not);
|
|
157
|
+
|
|
158
|
+
MARK_CHILD_SCHEMA(items);
|
|
159
|
+
MARK_CHILD_SCHEMA(contains);
|
|
160
|
+
MARK_CHILD_SCHEMA(additionalItems);
|
|
161
|
+
|
|
162
|
+
MARK_CHILD_SCHEMA(propertyNames);
|
|
163
|
+
MARK_CHILD_SCHEMA(additionalProperties);
|
|
164
|
+
|
|
165
|
+
for(size_t i = 0; i < compiled_schema->nested_schemas_count; i++)
|
|
166
|
+
mark_compiled_schema(compiled_schema->nested_schemas[i]);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
static void rb_mark_compiled_schema(void *ptr) {
|
|
170
|
+
CompiledSchema *compiled_schema = (CompiledSchema *)ptr;
|
|
171
|
+
|
|
172
|
+
if(INTERNAL_ONLY(compiled_schema)) return;
|
|
173
|
+
|
|
174
|
+
mark_compiled_schema(compiled_schema);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
static void free_compiled_schema(CompiledSchema *compiled_schema) {
|
|
178
|
+
for(size_t i = 0; i < compiled_schema->nested_schemas_count; i++)
|
|
179
|
+
free_compiled_schema(compiled_schema->nested_schemas[i]);
|
|
180
|
+
|
|
181
|
+
if(compiled_schema->nested_schemas != NULL)
|
|
182
|
+
xfree(compiled_schema->nested_schemas);
|
|
183
|
+
|
|
184
|
+
FREE_CHILD_SCHEMA(if);
|
|
185
|
+
FREE_CHILD_SCHEMA(then);
|
|
186
|
+
FREE_CHILD_SCHEMA(else);
|
|
187
|
+
|
|
188
|
+
FREE_CHILD_SCHEMA(not);
|
|
189
|
+
|
|
190
|
+
FREE_CHILD_SCHEMA(items);
|
|
191
|
+
FREE_CHILD_SCHEMA(contains);
|
|
192
|
+
FREE_CHILD_SCHEMA(additionalItems);
|
|
193
|
+
|
|
194
|
+
FREE_CHILD_SCHEMA(propertyNames);
|
|
195
|
+
FREE_CHILD_SCHEMA(additionalProperties);
|
|
196
|
+
|
|
197
|
+
xfree(compiled_schema);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/*
|
|
201
|
+
* This gets called by the Ruby GC for each `FastJSON::Schema::CompiledSchema` instance.
|
|
202
|
+
* As we are also wrapping the child compiled schemas(they are internal) into Ruby instances
|
|
203
|
+
* to pass them between Ruby methods, the pointer we receive here can refer to a child compiled
|
|
204
|
+
* schema which is needed by its parent.
|
|
205
|
+
* In that case, we shouldn't free the memory block addressed by that pointer and let the root compiled
|
|
206
|
+
* schema to handle freeing them.
|
|
207
|
+
*/
|
|
208
|
+
static void rb_free_compiled_schema(void *ptr) {
|
|
209
|
+
CompiledSchema *compiled_schema = (CompiledSchema *)ptr;
|
|
210
|
+
|
|
211
|
+
if(INTERNAL_ONLY(compiled_schema)) return;
|
|
212
|
+
|
|
213
|
+
free_compiled_schema(compiled_schema);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/*
|
|
217
|
+
* Here I am re-assigning all the values including the immediate ones which can not be
|
|
218
|
+
* compacted as they are located in stack but there is no harm re-assigning them.
|
|
219
|
+
*/
|
|
220
|
+
static void compact_compiled_schema(CompiledSchema *compiled_schema) {
|
|
221
|
+
compiled_schema->path = rb_gc_location(compiled_schema->path);
|
|
222
|
+
|
|
223
|
+
COMPACT_VALUE(id);
|
|
224
|
+
COMPACT_VALUE(ref);
|
|
225
|
+
COMPACT_VALUE(recursiveAnchor);
|
|
226
|
+
COMPACT_VALUE(recursiveRef);
|
|
227
|
+
|
|
228
|
+
COMPACT_VALUE(const);
|
|
229
|
+
COMPACT_VALUE(enum);
|
|
230
|
+
|
|
231
|
+
COMPACT_VALUE(multipleOf);
|
|
232
|
+
COMPACT_VALUE(maximum);
|
|
233
|
+
COMPACT_VALUE(exclusiveMaximum);
|
|
234
|
+
COMPACT_VALUE(minimum);
|
|
235
|
+
COMPACT_VALUE(exclusiveMinimum);
|
|
236
|
+
|
|
237
|
+
COMPACT_VALUE(maxLength);
|
|
238
|
+
COMPACT_VALUE(minLength);
|
|
239
|
+
COMPACT_VALUE(pattern);
|
|
240
|
+
|
|
241
|
+
COMPACT_VALUE(custom_format_callable);
|
|
242
|
+
COMPACT_VALUE(custom_format_error_key);
|
|
243
|
+
|
|
244
|
+
COMPACT_VALUE(items); // This will compact the `items_val` not `items_schema`.
|
|
245
|
+
COMPACT_VALUE(maxItems);
|
|
246
|
+
COMPACT_VALUE(minItems);
|
|
247
|
+
COMPACT_VALUE(uniqueItems);
|
|
248
|
+
COMPACT_VALUE(maxContains);
|
|
249
|
+
COMPACT_VALUE(minContains);
|
|
250
|
+
|
|
251
|
+
COMPACT_VALUE(properties);
|
|
252
|
+
COMPACT_VALUE(patternProperties);
|
|
253
|
+
COMPACT_VALUE(maxProperties);
|
|
254
|
+
COMPACT_VALUE(minProperties);
|
|
255
|
+
COMPACT_VALUE(required);
|
|
256
|
+
COMPACT_VALUE(dependencies);
|
|
257
|
+
|
|
258
|
+
COMPACT_CHILD_SCHEMA(if);
|
|
259
|
+
COMPACT_CHILD_SCHEMA(then);
|
|
260
|
+
COMPACT_CHILD_SCHEMA(else);
|
|
261
|
+
|
|
262
|
+
COMPACT_VALUE(allOf);
|
|
263
|
+
COMPACT_VALUE(anyOf);
|
|
264
|
+
COMPACT_VALUE(oneOf);
|
|
265
|
+
COMPACT_CHILD_SCHEMA(not);
|
|
266
|
+
|
|
267
|
+
COMPACT_CHILD_SCHEMA(items);
|
|
268
|
+
COMPACT_CHILD_SCHEMA(contains);
|
|
269
|
+
COMPACT_CHILD_SCHEMA(additionalItems);
|
|
270
|
+
|
|
271
|
+
COMPACT_CHILD_SCHEMA(propertyNames);
|
|
272
|
+
COMPACT_CHILD_SCHEMA(additionalProperties);
|
|
273
|
+
|
|
274
|
+
for(size_t i = 0; i < compiled_schema->nested_schemas_count; i++)
|
|
275
|
+
compact_compiled_schema(compiled_schema->nested_schemas[i]);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
static void rb_compact_compiled_schema(void *ptr) {
|
|
279
|
+
CompiledSchema *compiled_schema = (CompiledSchema *)ptr;
|
|
280
|
+
|
|
281
|
+
if(INTERNAL_ONLY(compiled_schema)) return;
|
|
282
|
+
|
|
283
|
+
compact_compiled_schema(compiled_schema);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const rb_data_type_t compiled_schema_type = {
|
|
287
|
+
"Schema::CompiledSchema",
|
|
288
|
+
{
|
|
289
|
+
rb_mark_compiled_schema,
|
|
290
|
+
rb_free_compiled_schema,
|
|
291
|
+
0,
|
|
292
|
+
rb_compact_compiled_schema
|
|
293
|
+
},
|
|
294
|
+
0,
|
|
295
|
+
0,
|
|
296
|
+
0,
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
static VALUE alloc_compiled_schema(VALUE klass) {
|
|
300
|
+
CompiledSchema *compiled_schema;
|
|
301
|
+
VALUE object = TypedData_Make_Struct(klass, CompiledSchema, &compiled_schema_type, compiled_schema);
|
|
302
|
+
|
|
303
|
+
return object;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
CompiledSchema *create_compiled_schema(VALUE path, schema_flag_t flags) {
|
|
307
|
+
CompiledSchema *compiled_schema = ALLOC(CompiledSchema);
|
|
308
|
+
|
|
309
|
+
compiled_schema->flags = flags;
|
|
310
|
+
|
|
311
|
+
compiled_schema->path = path;
|
|
312
|
+
|
|
313
|
+
compiled_schema->id_val = Qundef;
|
|
314
|
+
compiled_schema->ref_val = Qundef;
|
|
315
|
+
compiled_schema->recursiveAnchor_val = Qundef;
|
|
316
|
+
compiled_schema->recursiveRef_val = Qundef;
|
|
317
|
+
|
|
318
|
+
compiled_schema->ref_schema = NULL;
|
|
319
|
+
|
|
320
|
+
compiled_schema->const_val = Qundef;
|
|
321
|
+
compiled_schema->enum_val = Qundef;
|
|
322
|
+
|
|
323
|
+
compiled_schema->if_schema = NULL;
|
|
324
|
+
compiled_schema->then_schema = NULL;
|
|
325
|
+
compiled_schema->else_schema = NULL;
|
|
326
|
+
|
|
327
|
+
compiled_schema->allOf_val = Qundef;
|
|
328
|
+
compiled_schema->anyOf_val = Qundef;
|
|
329
|
+
compiled_schema->oneOf_val = Qundef;
|
|
330
|
+
compiled_schema->not_schema = NULL;
|
|
331
|
+
|
|
332
|
+
compiled_schema->multipleOf_val = Qundef;
|
|
333
|
+
compiled_schema->maximum_val = Qundef;
|
|
334
|
+
compiled_schema->exclusiveMaximum_val = Qundef;
|
|
335
|
+
compiled_schema->minimum_val = Qundef;
|
|
336
|
+
compiled_schema->exclusiveMinimum_val = Qundef;
|
|
337
|
+
|
|
338
|
+
compiled_schema->maxLength_val = Qundef;
|
|
339
|
+
compiled_schema->minLength_val = Qundef;
|
|
340
|
+
compiled_schema->pattern_val = Qundef;
|
|
341
|
+
|
|
342
|
+
compiled_schema->custom_format_callable_val = Qundef;
|
|
343
|
+
compiled_schema->custom_format_error_key_val = Qundef;
|
|
344
|
+
|
|
345
|
+
compiled_schema->items_schema = NULL;
|
|
346
|
+
compiled_schema->items_val = Qundef;
|
|
347
|
+
compiled_schema->additionalItems_schema = NULL;
|
|
348
|
+
compiled_schema->contains_schema = NULL;
|
|
349
|
+
compiled_schema->maxItems_val = Qundef;
|
|
350
|
+
compiled_schema->minItems_val = Qundef;
|
|
351
|
+
compiled_schema->uniqueItems_val = Qundef;
|
|
352
|
+
compiled_schema->maxContains_val = Qundef;
|
|
353
|
+
compiled_schema->minContains_val = Qundef;
|
|
354
|
+
|
|
355
|
+
compiled_schema->properties_val = Qundef;
|
|
356
|
+
compiled_schema->patternProperties_val = Qundef;
|
|
357
|
+
compiled_schema->propertyNames_schema = NULL;
|
|
358
|
+
compiled_schema->additionalProperties_schema = NULL;
|
|
359
|
+
compiled_schema->maxProperties_val = Qundef;
|
|
360
|
+
compiled_schema->minProperties_val = Qundef;
|
|
361
|
+
compiled_schema->required_val = Qundef;
|
|
362
|
+
compiled_schema->dependencies_val = Qundef;
|
|
363
|
+
|
|
364
|
+
compiled_schema->nested_schemas = NULL;
|
|
365
|
+
compiled_schema->nested_schemas_count = 0;
|
|
366
|
+
|
|
367
|
+
return compiled_schema;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
static validation_function type_validation_function(VALUE ruby_schema) {
|
|
371
|
+
VALUE type_val = rb_hash_aref(ruby_schema, type_str);
|
|
372
|
+
|
|
373
|
+
if(!RB_TYPE_P(type_val, T_STRING)) return validate_by_data_type;
|
|
374
|
+
|
|
375
|
+
char *type_str = StringValuePtr(type_val);
|
|
376
|
+
|
|
377
|
+
if(strcmp(type_str, "null") == 0) {
|
|
378
|
+
return validate_null;
|
|
379
|
+
} else if(strcmp(type_str, "boolean") == 0) {
|
|
380
|
+
return validate_bool;
|
|
381
|
+
} else if(strcmp(type_str, "string") == 0) {
|
|
382
|
+
return validate_string;
|
|
383
|
+
} else if(strcmp(type_str, "integer") == 0) {
|
|
384
|
+
return validate_integer;
|
|
385
|
+
} else if(strcmp(type_str, "number") == 0) {
|
|
386
|
+
return validate_number;
|
|
387
|
+
} else if(strcmp(type_str, "array") == 0) {
|
|
388
|
+
return validate_array;
|
|
389
|
+
} else if(strcmp(type_str, "object") == 0) {
|
|
390
|
+
return validate_object;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return no_op_validate;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
void compile(CompiledSchema *compiled_schema, VALUE ruby_schema, VALUE ref_data, VALUE custom_formats) {
|
|
397
|
+
// Embed compiled schema into Ruby Hash for ref resolution
|
|
398
|
+
register_schema_for_ref_resolution(compiled_schema, ref_data);
|
|
399
|
+
|
|
400
|
+
compiled_schema->validation_function = no_op_validate;
|
|
401
|
+
|
|
402
|
+
if(ruby_schema == Qfalse)
|
|
403
|
+
compiled_schema->validation_function = false_validate;
|
|
404
|
+
|
|
405
|
+
if(!RB_TYPE_P(ruby_schema, T_HASH))
|
|
406
|
+
return;
|
|
407
|
+
|
|
408
|
+
if(RHASH_SIZE(ruby_schema) == 0) {
|
|
409
|
+
compiled_schema->validation_function = no_op_validate;
|
|
410
|
+
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
compiled_schema->validation_function = validate;
|
|
415
|
+
|
|
416
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_1(id, T_STRING);
|
|
417
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_1(ref, T_STRING);
|
|
418
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_1(recursiveAnchor, T_STRING);
|
|
419
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_1(recursiveRef, T_STRING);
|
|
420
|
+
|
|
421
|
+
ASSIGN_ANY_VALUE_TO_COMPILED_SCHEMA(const);
|
|
422
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_1(enum, T_ARRAY);
|
|
423
|
+
|
|
424
|
+
ASSIGN_SCHEMA_TO_COMPILED_SCHEMA(if);
|
|
425
|
+
ASSIGN_SCHEMA_TO_COMPILED_SCHEMA(then);
|
|
426
|
+
ASSIGN_SCHEMA_TO_COMPILED_SCHEMA(else);
|
|
427
|
+
|
|
428
|
+
ASSIGN_SCHEMA_COLLECTION_TO_COMPILED_SCHEMA(allOf);
|
|
429
|
+
ASSIGN_SCHEMA_COLLECTION_TO_COMPILED_SCHEMA(anyOf);
|
|
430
|
+
ASSIGN_SCHEMA_COLLECTION_TO_COMPILED_SCHEMA(oneOf);
|
|
431
|
+
ASSIGN_SCHEMA_TO_COMPILED_SCHEMA(not);
|
|
432
|
+
|
|
433
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(multipleOf, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
434
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(maximum, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
435
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(exclusiveMaximum, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
436
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(minimum, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
437
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(exclusiveMinimum, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
438
|
+
|
|
439
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(maxLength, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
440
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(minLength, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
441
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_1(pattern, T_STRING);
|
|
442
|
+
|
|
443
|
+
ASSIGN_SCHEMA_TO_COMPILED_SCHEMA(items);
|
|
444
|
+
ASSIGN_SCHEMA_COLLECTION_TO_COMPILED_SCHEMA(items);
|
|
445
|
+
ASSIGN_SCHEMA_TO_COMPILED_SCHEMA(additionalItems);
|
|
446
|
+
ASSIGN_SCHEMA_TO_COMPILED_SCHEMA(contains);
|
|
447
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(maxItems, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
448
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(minItems, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
449
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_2(uniqueItems, T_TRUE, T_FALSE);
|
|
450
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(maxContains, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
451
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(minContains, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
452
|
+
|
|
453
|
+
ASSIGN_SCHEMA_TO_COMPILED_SCHEMA(propertyNames);
|
|
454
|
+
ASSIGN_SCHEMA_TO_COMPILED_SCHEMA(additionalProperties);
|
|
455
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(maxProperties, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
456
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_3(minProperties, T_FIXNUM, T_BIGNUM, T_FLOAT);
|
|
457
|
+
ASSIGN_TYPED_VALUE_TO_COMPILED_SCHEMA_1(required, T_ARRAY);
|
|
458
|
+
|
|
459
|
+
compile_properties_val(compiled_schema, ruby_schema, ref_data, custom_formats);
|
|
460
|
+
compile_pattern_properties_val(compiled_schema, ruby_schema, ref_data, custom_formats);
|
|
461
|
+
compile_dependencies_val(compiled_schema, ruby_schema, ref_data, custom_formats);
|
|
462
|
+
|
|
463
|
+
compile_nested_schemas(compiled_schema, ruby_schema, ref_data, custom_formats);
|
|
464
|
+
|
|
465
|
+
VALUE format_val = rb_hash_aref(ruby_schema, format_str);
|
|
466
|
+
set_format_validation_function_for_compiled_schema(compiled_schema, format_val, custom_formats);
|
|
467
|
+
|
|
468
|
+
compiled_schema->type_validation_function = type_validation_function(ruby_schema);
|
|
469
|
+
|
|
470
|
+
if(compiled_schema->ref_val != Qundef)
|
|
471
|
+
compiled_schema->validation_function = validate_ref;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
void compile_schema(VALUE self) {
|
|
475
|
+
VALUE ruby_schema = rb_ivar_get(self, rb_intern("@ruby_schema"));
|
|
476
|
+
VALUE ref_data = rb_hash_new();
|
|
477
|
+
|
|
478
|
+
/*
|
|
479
|
+
* Before running the compilation logic, we have to wrap the CompiledSchema struct into a
|
|
480
|
+
* Ruby object and keep it in the stack. Otherwise, we can't mark the intermediary objects,
|
|
481
|
+
* created and assigned to that struct to prevent them from being freed by the GC if it runs
|
|
482
|
+
* while compiling the schema.
|
|
483
|
+
*/
|
|
484
|
+
schema_flag_t flags = ROOT_SCHEMA | EXPOSE_TO_RUBY;
|
|
485
|
+
CompiledSchema *compiled_schema = create_compiled_schema(root_path_str, flags);
|
|
486
|
+
VALUE compiled_schema_obj = WrapCompiledSchema(compiled_schema);
|
|
487
|
+
|
|
488
|
+
VALUE custom_formats = rb_ivar_get(self, rb_intern("@custom_formats"));
|
|
489
|
+
|
|
490
|
+
compile(compiled_schema, ruby_schema, ref_data, custom_formats);
|
|
491
|
+
resolve_refs(compiled_schema, ref_data);
|
|
492
|
+
|
|
493
|
+
rb_ivar_set(self, rb_intern("compiled_schema"), compiled_schema_obj);
|
|
494
|
+
rb_ivar_set(self, rb_intern("compiled"), Qtrue);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
void Init_compiled_schema(VALUE schema_class) {
|
|
498
|
+
compiled_schema_class = rb_define_class_under(schema_class, "CompiledSchema", rb_cObject);
|
|
499
|
+
|
|
500
|
+
rb_define_alloc_func(compiled_schema_class, alloc_compiled_schema);
|
|
501
|
+
|
|
502
|
+
rb_gc_register_address(&compiled_schema_class);
|
|
503
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#include "types/compiled_schema.h"
|
|
2
|
+
|
|
3
|
+
extern VALUE compiled_schema_class;
|
|
4
|
+
extern const rb_data_type_t compiled_schema_type;
|
|
5
|
+
|
|
6
|
+
#define GetCompiledSchema(compiled_schema_obj, compiled_schema) TypedData_Get_Struct((compiled_schema_obj), CompiledSchema, &compiled_schema_type, (compiled_schema))
|
|
7
|
+
#define WrapCompiledSchema(compiled_schema) TypedData_Wrap_Struct(compiled_schema_class, &compiled_schema_type, compiled_schema)
|
|
8
|
+
|
|
9
|
+
void compile_schema(VALUE);
|
|
10
|
+
void Init_compiled_schema(VALUE);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#include "types/context.h"
|
|
2
|
+
#include "keywords.h"
|
|
3
|
+
|
|
4
|
+
static VALUE context_class;
|
|
5
|
+
|
|
6
|
+
static void mark_context(void *ptr) {
|
|
7
|
+
Context *context = (Context *)ptr;
|
|
8
|
+
int i;
|
|
9
|
+
|
|
10
|
+
for(i = 0; i <= context->depth; i++) {
|
|
11
|
+
rb_gc_mark_movable(context->path[i]);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static void compact_context(void *ptr) {
|
|
16
|
+
Context *context = (Context *)ptr;
|
|
17
|
+
int i;
|
|
18
|
+
|
|
19
|
+
for(i = 0; i <= context->depth; i++) {
|
|
20
|
+
context->path[i] = rb_gc_location(context->path[i]);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static void free_context(void *ptr) {
|
|
25
|
+
xfree(ptr);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static size_t context_size(const void *ptr) {
|
|
29
|
+
return sizeof(Context);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static const rb_data_type_t context_type = {
|
|
33
|
+
"Schema::Context",
|
|
34
|
+
{
|
|
35
|
+
mark_context,
|
|
36
|
+
free_context,
|
|
37
|
+
context_size,
|
|
38
|
+
compact_context
|
|
39
|
+
},
|
|
40
|
+
0,
|
|
41
|
+
0,
|
|
42
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
static VALUE alloc_context(VALUE klass) {
|
|
46
|
+
Context *context;
|
|
47
|
+
VALUE object = TypedData_Make_Struct(klass, Context, &context_type, context);
|
|
48
|
+
int i;
|
|
49
|
+
|
|
50
|
+
for(i = 0; i < MAX_CONTEXT_DEPTH; i++) {
|
|
51
|
+
context->path[i] = Qnil;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
context->depth = 0;
|
|
55
|
+
context->path[0] = root_path_str;
|
|
56
|
+
context->short_circuit_on_error = false;
|
|
57
|
+
|
|
58
|
+
return object;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
VALUE create_context(Context **out_context) {
|
|
62
|
+
VALUE wrapper = rb_class_new_instance(0, NULL, context_class);
|
|
63
|
+
Context *context;
|
|
64
|
+
|
|
65
|
+
TypedData_Get_Struct(wrapper, Context, &context_type, context);
|
|
66
|
+
|
|
67
|
+
*out_context = context;
|
|
68
|
+
|
|
69
|
+
return wrapper;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
void Init_context(void) {
|
|
73
|
+
context_class = rb_class_new(rb_cObject);
|
|
74
|
+
|
|
75
|
+
rb_define_alloc_func(context_class, alloc_context);
|
|
76
|
+
|
|
77
|
+
rb_gc_register_address(&context_class);
|
|
78
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#include "error.h"
|
|
2
|
+
#include "path.h"
|
|
3
|
+
#include "is_valid.h"
|
|
4
|
+
|
|
5
|
+
static VALUE error_class;
|
|
6
|
+
|
|
7
|
+
void yield_error(CompiledSchema *compiled_schema, VALUE data, Context *context, const char *type) {
|
|
8
|
+
if(context->short_circuit_on_error)
|
|
9
|
+
rb_throw_obj(short_circuit_tag, Qfalse);
|
|
10
|
+
|
|
11
|
+
VALUE args[4];
|
|
12
|
+
args[0] = compiled_schema->path;
|
|
13
|
+
args[1] = data;
|
|
14
|
+
args[2] = to_path(context->path, context->depth);
|
|
15
|
+
args[3] = rb_str_new_cstr(type);
|
|
16
|
+
|
|
17
|
+
VALUE error = rb_class_new_instance(4, args, error_class);
|
|
18
|
+
|
|
19
|
+
rb_yield(error);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
void Init_error(VALUE schema_class) {
|
|
23
|
+
error_class = rb_const_get(schema_class, rb_intern("Error"));
|
|
24
|
+
|
|
25
|
+
rb_gc_register_address(&error_class);
|
|
26
|
+
}
|