json/schema: modularise the validator objects

This commit is contained in:
Danny Robson 2018-07-11 19:28:13 +10:00
parent 8ea762bff8
commit c07ce50908
19 changed files with 963 additions and 4 deletions

View File

@ -298,6 +298,21 @@ list (
json/flat.hpp
json/schema.cpp
json/schema.hpp
json/schema/fwd.hpp
json/schema/base.cpp
json/schema/base.hpp
json/schema/combine.cpp
json/schema/combine.hpp
json/schema/except.hpp
json/schema/introspection.hpp
json/schema/length.cpp
json/schema/length.hpp
json/schema/inequality.cpp
json/schema/inequality.hpp
json/schema/properties.cpp
json/schema/properties.hpp
json/schema/type.cpp
json/schema/type.hpp
json/tree.cpp
json/tree.hpp
json2/fwd.hpp

View File

@ -538,3 +538,31 @@ json::schema::validate (json::tree::node &data,
auto schema_object = json::tree::parse (util::view(schema_data).cast<const char*> ());
validate (data, schema_object->as_object ());
}
///////////////////////////////////////////////////////////////////////////////
#include "schema/except.hpp"
#include "schema/base.hpp"
#include "../io.hpp"
#include "../view.hpp"
#include <map>
json::schema::validator::validator(std::experimental::filesystem::path const &path):
validator (*json::tree::parse (path))
{ ; }
json::schema::validator::validator (json::tree::node const &definition):
m_base (definition)
{ ; }
bool
json::schema::validator::validate (json::tree::node &data) const
{
std::vector<util::json::schema::constraint::failure> res;
m_base.validate (std::back_inserter(res), data);
return res.empty ();
}

View File

@ -18,12 +18,27 @@
#define __UTIL_JSON_SCHEMA_HPP
#include "fwd.hpp"
#include "schema/combine.hpp"
#include <experimental/filesystem>
///////////////////////////////////////////////////////////////////////////////
namespace json::schema {
class validator {
public:
validator (json::tree::node const &definition);
validator (std::experimental::filesystem::path const&);
bool validate (json::tree::node &data) const;
private:
std::string m_version;
util::json::schema::constraint::combine m_base;
};
// Validate the json tree using the provide schema object or path.
//
// Note that the data object being validated may be altered in the process

39
json/schema/base.cpp Normal file
View File

@ -0,0 +1,39 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#include "base.hpp"
#include "type.hpp"
#include "length.hpp"
#include "inequality.hpp"
#include "properties.hpp"
using util::json::schema::constraint::base;
///////////////////////////////////////////////////////////////////////////////
std::unique_ptr<base>
base::instantiate (std::string const &name, ::json::tree::node const &def)
{
if (name == "type") return std::make_unique<type> (def);
if (name == "minLength") return std::make_unique<min_length> (def);
if (name == "maxLength") return std::make_unique<max_length> (def);
if (name == "minimum") return std::make_unique<minimum> (def);
if (name == "maximum") return std::make_unique<maximum> (def);
if (name == "properties") return std::make_unique<properties> (def);
throw unknown_constraint (name);
}

51
json/schema/base.hpp Normal file
View File

@ -0,0 +1,51 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "except.hpp"
#include <string>
#include <vector>
#include <iosfwd>
namespace util::json::schema::constraint {
struct failure {
constraint::base const &rule;
::json::tree::node const &target;
};
class base {
public:
using output_container = std::vector<failure>;
using output_iterator = std::back_insert_iterator<output_container>;
virtual ~base () = default;
virtual output_iterator validate (output_iterator res, ::json::tree::node &) const noexcept = 0;
virtual std::ostream& describe (std::ostream&) const = 0;
static std::unique_ptr<base> instantiate (std::string const &name, ::json::tree::node const&);
};
inline std::ostream&
operator<< (std::ostream &os, base const &obj)
{
return obj.describe (os);
}
}

78
json/schema/combine.cpp Normal file
View File

@ -0,0 +1,78 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#include "combine.hpp"
#include "../tree.hpp"
#include "../../iterator.hpp"
using util::json::schema::constraint::combine;
///////////////////////////////////////////////////////////////////////////////
combine::combine (::json::tree::node const &def)
{
for (auto const &[key,val]: def.as_object ()) {
if (key == "$schema") {
m_version = val->as_string ();
continue;
}
if (key == "default") {
m_default = val->clone ();
continue;
}
m_constraints.push_back (instantiate (key, *val));
}
}
///////////////////////////////////////////////////////////////////////////////
combine::output_iterator
combine::validate (output_iterator res, ::json::tree::node &data) const noexcept
{
for (auto const &i: m_constraints)
res = i->validate (res, data);
return res;
}
///////////////////////////////////////////////////////////////////////////////
std::ostream&
combine::describe (std::ostream &os) const
{
return os << "{ combine: [ ";
for (auto const &i: m_constraints)
os << *i << ", ";
return os << " ] }";
}
///////////////////////////////////////////////////////////////////////////////
bool
combine::has_default (void) const
{
return !!m_default;
}
//-----------------------------------------------------------------------------
std::unique_ptr<::json::tree::node>
combine::default_value (void) const
{
return m_default->clone ();
}

52
json/schema/combine.hpp Normal file
View File

@ -0,0 +1,52 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "base.hpp"
#include "../tree.hpp"
#include <memory>
#include <vector>
///////////////////////////////////////////////////////////////////////////////
namespace util::json::schema::constraint {
class combine final : public base {
public:
combine (::json::tree::node const &def);
combine (combine const&) = delete;
combine& operator= (combine const&) = delete;
combine (combine &&) = default;
combine& operator= (combine &&) = default;
virtual ~combine () = default;
output_iterator validate (output_iterator res, ::json::tree::node &) const noexcept override;
std::ostream& describe (std::ostream&) const override;
bool has_default (void) const;
std::unique_ptr<::json::tree::node> default_value (void) const;
private:
std::string m_version;
std::unique_ptr<::json::tree::node> m_default;
std::vector<std::unique_ptr<base>> m_constraints;
};
}

64
json/schema/except.hpp Normal file
View File

@ -0,0 +1,64 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "fwd.hpp"
#include "introspection.hpp"
#include "../fwd.hpp"
#include <exception>
///////////////////////////////////////////////////////////////////////////////
namespace util::json::schema {
class error : public std::exception { };
template <typename T>
class constraint_error : public error {
public:
virtual ~constraint_error () = default;
constraint_error (::json::tree::node const &_def):
def (_def)
{ ; }
char const* what (void) const noexcept override
{
return util::type_name_v<T>;
}
::json::tree::node const &def;
};
class unknown_constraint : public error {
public:
unknown_constraint (std::string const &name):
m_name (name)
{ ; }
virtual ~unknown_constraint () = default;
char const* what (void) const noexcept override
{
return m_name.c_str ();
}
private:
std::string m_name;
};
}

30
json/schema/fwd.hpp Normal file
View File

@ -0,0 +1,30 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
namespace util::json::schema::constraint {
struct failure;
class base;
class type;
class combine;
template <typename> class length;
template <template <typename> class> class inequality;
class properties;
}

View File

@ -0,0 +1,75 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#include "inequality.hpp"
#include "../tree.hpp"
using util::json::schema::constraint::inequality;
///////////////////////////////////////////////////////////////////////////////
template <template <typename> class ComparatorT>
inequality<ComparatorT>::inequality (::json::tree::node const &def)
{
if (!def.is_number ())
throw constraint_error<inequality> (def);
auto const &val = def.as_number ();
switch (val.repr ()) {
case ::json::tree::number::UINT: m_value = val.uint (); break;
case ::json::tree::number::SINT: m_value = val.sint (); break;
case ::json::tree::number::REAL: m_value = val.real (); break;
}
}
///////////////////////////////////////////////////////////////////////////////
template <template <typename> class ComparatorT>
typename inequality<ComparatorT>::output_iterator
inequality<ComparatorT>::validate (util::json::schema::constraint::base::output_iterator res,
::json::tree::node &target) const noexcept
{
if (!target.is_number ()) {
return *res++ = failure { .rule = *this, .target = target };
}
// HACK: this shouldn't be casting to double for the comparison, but it
// greatly simplifies the logic.
auto const &value = target.as_number ();
std::visit([&,this] (auto const &inner) noexcept {
if (!ComparatorT<double>{} (value.as<double> (), inner))
*res++ = failure { .rule = *this, .target = target };
}, m_value);
return res;
}
///////////////////////////////////////////////////////////////////////////////
template <template <typename> class ComparatorT>
std::ostream&
inequality<ComparatorT>::describe (std::ostream &os) const
{
os << "{ " << util::type_name_v<inequality> << ": ";
std::visit ([&os] (auto const &i) -> void { os << i; }, m_value);
return os << " }";
}
///////////////////////////////////////////////////////////////////////////////
template class util::json::schema::constraint::inequality<std::less_equal>;
template class util::json::schema::constraint::inequality<std::greater_equal>;

View File

@ -0,0 +1,49 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "base.hpp"
#include "../tree.hpp"
#include <functional>
#include <variant>
///////////////////////////////////////////////////////////////////////////////
namespace util::json::schema::constraint {
template <template <typename> class ComparatorT>
class inequality final : public base {
public:
inequality (::json::tree::node const&);
virtual ~inequality () = default;
output_iterator validate (output_iterator, ::json::tree::node &target) const noexcept override;
std::ostream& describe (std::ostream&) const override;
private:
using uint_t = ::json::tree::number::uint_t;
using sint_t = ::json::tree::number::sint_t;
using real_t = ::json::tree::number::real_t;
std::variant<uint_t,sint_t,real_t> m_value;
};
using minimum = inequality<std::greater_equal>;
using maximum = inequality<std::less_equal>;
}

View File

@ -0,0 +1,35 @@
#pragma once
#include "../../introspection.hpp"
#include "fwd.hpp"
namespace util {
#define SCHEMA_INTROSPECTION(K) \
namespace detail { \
struct type_name_cruft_json_schema_constraint_##K { \
static constexpr const char value[] = #K; \
}; \
} \
\
template <> \
struct type_name<::util::json::schema::constraint::K> : \
public detail::type_name_cruft_json_schema_constraint_##K \
{ };
template <template <typename> class OperatorT>
struct type_name<::util::json::schema::constraint::inequality<OperatorT>> {
static constexpr const char value[] = "inequality";
};
template <typename OperatorT>
struct type_name<::util::json::schema::constraint::length<OperatorT>> {
static constexpr const char value[] = "length";
};
MAP0(SCHEMA_INTROSPECTION, type, combine, properties)
#undef SCHEMA_INTROSPECTION
}

83
json/schema/length.cpp Normal file
View File

@ -0,0 +1,83 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#include "length.hpp"
#include "../tree.hpp"
using util::json::schema::constraint::length;
///////////////////////////////////////////////////////////////////////////////
namespace {
template <typename ComparatorT>
struct field_name { };
template <>
struct field_name<std::greater_equal<std::size_t>> {
static constexpr char const *const value = "minLength";
};
template <>
struct field_name<std::less_equal<std::size_t>> {
static constexpr char const *const value = "maxLength";
};
template <typename ComparatorT>
static constexpr auto field_name_v = field_name<ComparatorT>::value;
}
///////////////////////////////////////////////////////////////////////////////
template <typename ComparatorT>
length<ComparatorT>::length(::json::tree::node const &def):
m_length(def.as<std::size_t> ())
{ ; }
///////////////////////////////////////////////////////////////////////////////
template <typename ComparatorT>
typename length<ComparatorT>::output_iterator
length<ComparatorT>::validate (output_iterator res, ::json::tree::node &target) const noexcept
{
if (!target.is_string ()) {
return *res++ = failure { .rule = *this, .target = target };
}
auto const &val = target.as_string ();
if (!ComparatorT{}(val.size (), m_length))
*res++ = failure { .rule = *this, .target = target };
return res;
}
///////////////////////////////////////////////////////////////////////////////
template <typename ComparatorT>
std::ostream&
length<ComparatorT>::describe (std::ostream &os) const
{
return os << "{ " << ::field_name_v<ComparatorT> << ": " << m_length << " }";
}
///////////////////////////////////////////////////////////////////////////////
template class util::json::schema::constraint::length<std::less_equal<std::size_t>>;
template class util::json::schema::constraint::length<std::greater_equal<std::size_t>>;

42
json/schema/length.hpp Normal file
View File

@ -0,0 +1,42 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "base.hpp"
#include <functional>
///////////////////////////////////////////////////////////////////////////////
namespace util::json::schema::constraint {
template <typename ComparatorT>
class length final : public base {
public:
length (::json::tree::node const&);
virtual ~length () = default;
output_iterator validate (output_iterator, ::json::tree::node &target) const noexcept override;
std::ostream& describe (std::ostream&) const override;
private:
std::size_t m_length;
};
using max_length = length<std::less_equal<std::size_t>>;
using min_length = length<std::greater_equal<std::size_t>>;
}

View File

@ -0,0 +1,81 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#include "properties.hpp"
#include "../tree.hpp"
using util::json::schema::constraint::properties;
///////////////////////////////////////////////////////////////////////////////
properties::properties (::json::tree::node const &def)
{
if (!def.is_object ())
throw constraint_error<properties> (def);
for (auto const &[key,val]: def.as_object ()) {
m_properties.emplace (key, *val);
}
}
///////////////////////////////////////////////////////////////////////////////
properties::output_iterator
properties::validate (output_iterator res, ::json::tree::node &target) const noexcept
{
if (!target.is_object ())
return *res++ = { .rule = *this, .target = target };
auto &obj = target.as_object ();
// validate the keys that are present against the property schemas
for (const auto &[key,val]: obj) {
auto const pos = m_properties.find (key);
if (pos == m_properties.end ())
continue;
res = pos->second.validate (res, *val);
}
// check if there's a key in the schema that isn't present but has a default
for (auto const &[key,doc]: m_properties) {
if (!doc.has_default ())
continue;
auto pos = obj.find (key);
if (pos == obj.end ())
obj.insert (key, doc.default_value ());
}
return res;
}
///////////////////////////////////////////////////////////////////////////////
std::ostream&
properties::describe (std::ostream &os) const
{
os << "{ properties: [ ";
for (auto const &[key,val]: m_properties) {
os << key << ": ";
val.describe (os);
os << ", ";
}
return os << " ] }";
}

View File

@ -0,0 +1,40 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "base.hpp"
#include "combine.hpp"
#include <map>
#include <string>
#include <memory>
///////////////////////////////////////////////////////////////////////////////
namespace util::json::schema::constraint {
class properties : public base {
public:
properties (::json::tree::node const&);
virtual ~properties () = default;
output_iterator validate (output_iterator, ::json::tree::node &target) const noexcept override;
std::ostream& describe (std::ostream&) const override;
private:
std::map<std::string,combine> m_properties;
};
}

128
json/schema/type.cpp Normal file
View File

@ -0,0 +1,128 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#include "type.hpp"
#include "except.hpp"
#include "../../parse.hpp"
using util::json::schema::constraint::type;
///////////////////////////////////////////////////////////////////////////////
template <>
util::json::schema::constraint::type::type_t
util::parse<util::json::schema::constraint::type::type_t> (util::view<const char*> str)
{
if (str == "integer") return ::util::json::schema::constraint::type::INTEGER;
if (str == "number") return ::util::json::schema::constraint::type::NUMBER;
if (str == "string") return ::util::json::schema::constraint::type::STRING;
if (str == "object") return ::util::json::schema::constraint::type::OBJECT;
if (str == "array") return ::util::json::schema::constraint::type::ARRAY;
if (str == "boolean") return ::util::json::schema::constraint::type::BOOLEAN;
if (str == "null") return ::util::json::schema::constraint::type::NONE;
throw std::invalid_argument (std::string (str.begin (), str.end ()));
}
///////////////////////////////////////////////////////////////////////////////
namespace util::json::schema::constraint {
std::string const&
to_string (type::type_t t)
{
switch (t) {
case type::INTEGER: { static std::string s_name = "integer"; return s_name; }
case type::NUMBER: { static std::string s_name = "number"; return s_name; }
case type::STRING: { static std::string s_name = "string"; return s_name; }
case type::OBJECT: { static std::string s_name = "object"; return s_name; }
case type::ARRAY: { static std::string s_name = "array"; return s_name; }
case type::BOOLEAN: { static std::string s_name = "boolean"; return s_name; }
case type::NONE: { static std::string s_name = "none"; return s_name; }
}
unreachable ();
}
}
static type::type_t
valid_types (::json::tree::node const &def)
{
if (def.is_string ()) {
return util::parse<type::type_t> (def.as_string ());
} else if (def.is_array ()) {
std::underlying_type_t<type::type_t> accum = 0;
for (auto const &i: def.as_array ())
accum |= util::parse<type::type_t> (i.as_string ());
return type::type_t (accum);
} else {
throw util::json::schema::constraint_error<type> (def);
}
}
///////////////////////////////////////////////////////////////////////////////
type::type (::json::tree::node const &def):
m_type (valid_types (def))
{ ; }
///////////////////////////////////////////////////////////////////////////////
static bool
is_valid (type::type_t t, ::json::tree::node const &target) noexcept
{
switch (target.type ()) {
case ::json::tree::STRING: return t & type::STRING;
case ::json::tree::OBJECT: return t & type::OBJECT;
case ::json::tree::ARRAY: return t & type::ARRAY;
case ::json::tree::BOOLEAN: return t & type::BOOLEAN;
case ::json::tree::NONE: return t & type::NONE;
case ::json::tree::NUMBER:
if (t & type::NUMBER)
return true;
switch (target.as_number ().repr ()) {
case ::json::tree::number::UINT:
case ::json::tree::number::SINT:
return t & type::INTEGER;
case ::json::tree::number::REAL:
return false;
}
}
unreachable ();
}
type::output_iterator
type::validate (output_iterator res, ::json::tree::node &target) const noexcept
{
if (!is_valid (m_type, target))
*res++ = failure { .rule = *this, .target = target };
return res;
}
std::ostream&
type::describe (std::ostream &os) const
{
return os << "{type: " << to_string (m_type) << " }";
}

47
json/schema/type.hpp Normal file
View File

@ -0,0 +1,47 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "base.hpp"
#include "../tree.hpp"
///////////////////////////////////////////////////////////////////////////////
namespace util::json::schema::constraint {
class type final : public base {
public:
enum type_t {
INTEGER = 1 << 0,
NUMBER = 1 << 1,
STRING = 1 << 2,
OBJECT = 1 << 3,
ARRAY = 1 << 4,
BOOLEAN = 1 << 5,
NONE = 1 << 6,
};
type (::json::tree::node const &definition);
virtual ~type () = default;
output_iterator validate (output_iterator, ::json::tree::node &target) const noexcept override;
std::ostream& describe (std::ostream&) const override;
private:
type_t const m_type;
};
}

View File

@ -19,6 +19,8 @@
#include "json/schema.hpp"
#include "json/tree.hpp"
#include "json/schema/except.hpp"
#include "io.hpp"
#include <experimental/filesystem>
@ -47,15 +49,20 @@ main (int argc, char **argv) {
}
try {
const util::mapped_file schema_src (argv[ARG_SCHEMA]);
const util::mapped_file input_src (argv[ARG_INPUT]);
auto schema = json::tree::parse (util::view{schema_src}.cast<const char*>());
auto input = json::tree::parse (util::view{input_src} .cast<const char*>());
json::schema::validator schema (argv[ARG_SCHEMA]);
auto input = json::tree::parse (util::view{input_src} .cast<const char*>());
json::schema::validate (*input, schema->as_object ());
if (!schema.validate (*input)) {
std::cerr << "fail\n";
return EXIT_FAILURE;
}
std::cout << *input << '\n';
} catch (util::json::schema::error const &x) {
std::cerr << "schema: " << x.what () << '\n';
return EXIT_FAILURE;
} catch (const json::error &e) {
std::cerr << "error: " << e.what () << '\n';
return EXIT_FAILURE;