libcruft-util/json/constraint/type.cpp

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) << " }";
}