Sourcemeta Core 0.0.0
Loading...
Searching...
No Matches
jsonschema_vocabularies.h
1#ifndef SOURCEMETA_CORE_JSONSCHEMA_VOCABULARIES_H_
2#define SOURCEMETA_CORE_JSONSCHEMA_VOCABULARIES_H_
3
4#ifndef SOURCEMETA_CORE_JSONSCHEMA_EXPORT
5#include <sourcemeta/core/jsonschema_export.h>
6#endif
7
8#include <sourcemeta/core/json.h>
9
10#include <bitset> // std::bitset
11#include <cassert> // assert
12#include <cstdint> // std::uint32_t, std::size_t
13#include <format> // std::formatter, std::format_context, std::format_parse_context, std::format_to
14#include <optional> // std::optional
15#include <ostream> // std::ostream
16#include <sstream> // std::ostringstream
17#include <stdexcept> // std::out_of_range
18#include <string_view> // std::string_view
19#include <unordered_map> // std::unordered_map
20#include <unordered_set> // std::unordered_set
21#include <utility> // std::pair
22#include <variant> // std::variant
23#include <vector> // std::vector
24
25namespace sourcemeta::core {
26
30struct SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaVocabularies {
32 enum class Known : std::uint8_t {
33 // Pre-vocabulary dialects (treated as vocabularies)
35 JSON_SCHEMA_DRAFT_0 = 0,
39 JSON_SCHEMA_DRAFT_1 = 2,
43 JSON_SCHEMA_DRAFT_2 = 4,
62 // 2019-09 vocabularies
64 JSON_SCHEMA_2019_09_CORE = 14,
66 JSON_SCHEMA_2019_09_APPLICATOR = 15,
68 JSON_SCHEMA_2019_09_VALIDATION = 16,
70 JSON_SCHEMA_2019_09_META_DATA = 17,
72 JSON_SCHEMA_2019_09_FORMAT = 18,
74 JSON_SCHEMA_2019_09_CONTENT = 19,
76 JSON_SCHEMA_2019_09_HYPER_SCHEMA = 20,
77 // 2020-12 vocabularies
79 JSON_SCHEMA_2020_12_CORE = 21,
81 JSON_SCHEMA_2020_12_APPLICATOR = 22,
83 JSON_SCHEMA_2020_12_UNEVALUATED = 23,
85 JSON_SCHEMA_2020_12_VALIDATION = 24,
87 JSON_SCHEMA_2020_12_META_DATA = 25,
89 JSON_SCHEMA_2020_12_FORMAT_ANNOTATION = 26,
91 JSON_SCHEMA_2020_12_FORMAT_ASSERTION = 27,
93 JSON_SCHEMA_2020_12_CONTENT = 28,
94 // OpenAPI
95 // https://spec.openapis.org/oas/v3.1.0.html#fixed-fields-19
97 OPENAPI_3_1_BASE = 29,
98 // https://spec.openapis.org/oas/v3.2.0.html#base-vocabulary
100 OPENAPI_3_2_BASE = 30,
101 // Sourcemeta
103 SOURCEMETA_EXTENSION_V1 = 31
104 };
105
106 // NOTE: Must be kept in sync with the Known enum above
108 static constexpr std::size_t KNOWN_VOCABULARY_COUNT = 32;
109
112 using URI = std::variant<Known, sourcemeta::core::JSON::String>;
113
116 using URIView = std::variant<Known, std::string_view>;
117
118public:
119 SchemaVocabularies() = default;
121 SchemaVocabularies(const SchemaVocabularies &) = default;
123 SchemaVocabularies(SchemaVocabularies &&) noexcept = default;
124 auto operator=(const SchemaVocabularies &) -> SchemaVocabularies & = default;
125 auto operator=(SchemaVocabularies &&) noexcept
126 -> SchemaVocabularies & = default;
127 ~SchemaVocabularies() = default;
128
130 SchemaVocabularies(
131 std::initializer_list<std::pair<sourcemeta::core::JSON::String, bool>>
132 init);
133
135 SchemaVocabularies(std::initializer_list<std::pair<Known, bool>> init);
136
138 [[nodiscard]] auto
139 contains(const sourcemeta::core::JSON::String &uri) const noexcept -> bool;
140
142 [[nodiscard]] auto contains(Known vocabulary) const noexcept -> bool;
143
145 [[nodiscard]] auto
146 contains_any(std::initializer_list<Known> vocabularies) const noexcept
147 -> bool;
148
150 auto insert(const sourcemeta::core::JSON::String &uri, bool required) noexcept
151 -> void;
152
154 auto insert(Known vocabulary, bool required) noexcept -> void;
155
157 [[nodiscard]] auto
158 get(const sourcemeta::core::JSON::String &uri) const noexcept
159 -> std::optional<bool>;
160
162 [[nodiscard]] auto get(Known vocabulary) const noexcept
163 -> std::optional<bool>;
164
166 [[nodiscard]] auto size() const noexcept -> std::size_t;
167
169 [[nodiscard]] auto empty() const noexcept -> bool;
170
172 [[nodiscard]] auto has_unknown() const noexcept -> bool;
173
175 template <typename Callback>
176 auto for_each(const Callback &callback) const -> void {
177 for (std::size_t index = 0; index < KNOWN_VOCABULARY_COUNT; ++index) {
178 if (this->required_known_[index]) {
179 callback(URI{static_cast<Known>(index)}, true);
180 } else if (this->optional_known_[index]) {
181 callback(URI{static_cast<Known>(index)}, false);
182 }
183 }
184
185 if (this->unknown_.has_value()) {
186 for (const auto &[uri, required] : this->unknown_.value()) {
187 callback(URI{uri}, required);
188 }
189 }
190 }
191
194 auto throw_if_any_unsupported(const std::unordered_set<URI> &supported,
195 const char *message) const -> void;
196
197private:
198 // Invariant: required_known and optional_known must be mutually exclusive
199 // A vocabulary can be either required (true) OR optional (false), never both
200#ifdef _MSC_VER
201#pragma warning(push)
202#pragma warning(disable : 4251)
203#endif
204 std::bitset<KNOWN_VOCABULARY_COUNT> required_known_{};
205 std::bitset<KNOWN_VOCABULARY_COUNT> optional_known_{};
206 // Lazily initialized only when unknown (non-official) vocabularies are used
207 std::optional<std::unordered_map<sourcemeta::core::JSON::String, bool>>
208 unknown_{std::nullopt};
209#ifdef _MSC_VER
210#pragma warning(pop)
211#endif
212};
213
215SOURCEMETA_CORE_JSONSCHEMA_EXPORT auto
216operator<<(std::ostream &stream, SchemaVocabularies::Known vocabulary)
217 -> std::ostream &;
218
220SOURCEMETA_CORE_JSONSCHEMA_EXPORT auto
221operator<<(std::ostream &stream, const SchemaVocabularies::URI &vocabulary)
222 -> std::ostream &;
223
224} // namespace sourcemeta::core
225
227template <> struct std::formatter<sourcemeta::core::SchemaVocabularies::Known> {
228 constexpr auto parse(std::format_parse_context &context)
229 -> decltype(context.begin()) {
230 return context.begin();
231 }
232
233 auto format(const sourcemeta::core::SchemaVocabularies::Known value,
234 std::format_context &context) const -> decltype(context.out()) {
235 std::ostringstream stream;
236 stream << value;
237 return std::format_to(context.out(), "{}", stream.str());
238 }
239};
240
241template <> struct std::formatter<sourcemeta::core::SchemaVocabularies::URI> {
242 constexpr auto parse(std::format_parse_context &context)
243 -> decltype(context.begin()) {
244 return context.begin();
245 }
246
247 auto format(const sourcemeta::core::SchemaVocabularies::URI &value,
248 std::format_context &context) const -> decltype(context.out()) {
249 std::ostringstream stream;
250 stream << value;
251 return std::format_to(context.out(), "{}", stream.str());
252 }
253};
255
256#endif
Definition json_value.h:39
auto has_unknown() const noexcept -> bool
Check if there are any unknown vocabularies.
Known
Every vocabulary that this implementation recognises out of the box.
Definition jsonschema_vocabularies.h:32
auto size() const noexcept -> std::size_t
Get the number of vocabularies (required + optional + custom).
std::variant< Known, sourcemeta::core::JSON::String > URI
Definition jsonschema_vocabularies.h:112
auto contains_any(std::initializer_list< Known > vocabularies) const noexcept -> bool
Check if any of the given known vocabularies are enabled.
auto get(const sourcemeta::core::JSON::String &uri) const noexcept -> std::optional< bool >
Get vocabulary status by URI.
auto empty() const noexcept -> bool
Check if there are no vocabularies.
auto for_each(const Callback &callback) const -> void
Iterate over every vocabulary, along with whether it is required.
Definition jsonschema_vocabularies.h:176
SchemaVocabularies(SchemaVocabularies &&) noexcept=default
Move a vocabulary set.
std::variant< Known, std::string_view > URIView
Definition jsonschema_vocabularies.h:116
auto throw_if_any_unsupported(const std::unordered_set< URI > &supported, const char *message) const -> void
auto insert(const sourcemeta::core::JSON::String &uri, bool required) noexcept -> void
Insert a vocabulary with its required/optional status.
static constexpr std::size_t KNOWN_VOCABULARY_COUNT
How many vocabularies this implementation recognises out of the box.
Definition jsonschema_vocabularies.h:108
SchemaVocabularies(const SchemaVocabularies &)=default
Copy a vocabulary set.
auto contains(const sourcemeta::core::JSON::String &uri) const noexcept -> bool
Check if a vocabulary is enabled.
@ JSON_SCHEMA_DRAFT_4
The Draft 4 validation base dialect.
Definition jsonschema_types.h:72
@ JSON_SCHEMA_DRAFT_3
The Draft 3 validation base dialect.
Definition jsonschema_types.h:76
@ JSON_SCHEMA_DRAFT_7
The Draft 7 validation base dialect.
Definition jsonschema_types.h:64
@ JSON_SCHEMA_DRAFT_6
The Draft 6 validation base dialect.
Definition jsonschema_types.h:68
@ JSON_SCHEMA_DRAFT_0_HYPER
The Draft 0 hyper-schema base dialect.
Definition jsonschema_types.h:84
@ JSON_SCHEMA_DRAFT_4_HYPER
The Draft 4 hyper-schema base dialect.
Definition jsonschema_types.h:74
@ JSON_SCHEMA_DRAFT_3_HYPER
The Draft 3 hyper-schema base dialect.
Definition jsonschema_types.h:78
@ JSON_SCHEMA_DRAFT_7_HYPER
The Draft 7 hyper-schema base dialect.
Definition jsonschema_types.h:66
@ JSON_SCHEMA_DRAFT_2_HYPER
The Draft 2 hyper-schema base dialect.
Definition jsonschema_types.h:80
@ JSON_SCHEMA_DRAFT_6_HYPER
The Draft 6 hyper-schema base dialect.
Definition jsonschema_types.h:70
@ JSON_SCHEMA_DRAFT_1_HYPER
The Draft 1 hyper-schema base dialect.
Definition jsonschema_types.h:82