/* * 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 */ #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::view 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 (def.as_string ()); } else if (def.is_array ()) { std::underlying_type_t accum = 0; for (auto const &i: def.as_array ()) accum |= util::parse (i.as_string ()); return type::type_t (accum); } else { throw util::json::schema::constraint_error (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) << " }"; }