129 lines
4.2 KiB
C++
129 lines
4.2 KiB
C++
|
/*
|
||
|
* 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) << " }";
|
||
|
}
|