/* * Copyright (C) 2017 Charybdis Development Team * Copyright (C) 2017 Jason Volk * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice is present in all copies. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #pragma once #define HAVE_IRCD_JSON_PARSE_H #define IRCD_MEMBERS(_vals_...) \ static constexpr const char *_member_(const size_t i) \ { \ constexpr const char *const val[] \ { \ _vals_ \ }; \ \ return val[i]; \ } namespace ircd { namespace json { struct basic_parse { }; template struct parse :basic_parse ,std::tuple { using tuple_type = std::tuple; static constexpr size_t size() { return std::tuple_size(); } parse() = default; template parse(R &r, const json::object &obj); }; template template parse::parse(R &r, const json::object &object) { std::for_each(std::begin(object), std::end(object), [this, &r] (auto &&member) { at(r, member.first, [&member] (auto&& target) { using target_type = decltype(target); using cast_type = typename std::remove_reference::type; try { target = lex_cast(member.second); } catch(const bad_lex_cast &e) { throw parse_error("member \"%s\" must convert to '%s'", member.first, typeid(target_type).name()); } }); }); } template using tuple_type = typename parse::tuple_type; template using tuple_size = std::tuple_size>; template using tuple_element = typename std::tuple_element>::type; template constexpr auto & tuple(const parse &o) { return static_cast(o); } template constexpr auto & tuple(parse &o) { return static_cast(o); } template constexpr auto size(const parse &t) { return t.size(); } template constexpr auto & get(const parse &t) { return std::get(t); } template constexpr auto & get(parse &t) { return std::get(t); } template constexpr const char * reflect(const parse &t) { return t._member_(i); } template constexpr typename std::enable_if::value, void>::type for_each(const parse &t, function&& f) {} template constexpr typename std::enable_if::value, void>::type for_each(parse &t, function&& f) {} template constexpr typename std::enable_if::value, void>::type for_each(const parse &t, function&& f) { using type = tuple_element; f(reflect(t), static_cast(get(t))); for_each(t, std::forward(f)); } template constexpr typename std::enable_if::value, void>::type for_each(parse &t, function&& f) { using type = tuple_element; f(reflect(t), static_cast(get(t))); for_each(t, std::forward(f)); } template constexpr typename std::enable_if<(i < 0), void>::type rfor_each(const parse &t, function&& f) {} template constexpr typename std::enable_if<(i < 0), void>::type rfor_each(parse &t, function&& f) {} template() - 1> constexpr typename std::enable_if(), void>::type rfor_each(const parse &t, function&& f) { using type = tuple_element; f(reflect(t), static_cast(get(t))); rfor_each(t, std::forward(f)); } template() - 1> constexpr typename std::enable_if(), void>::type rfor_each(parse &t, function&& f) { using type = tuple_element; f(reflect(t), static_cast(get(t))); rfor_each(t, std::forward(f)); } template constexpr typename std::enable_if::value, bool>::type until(const parse &t, function&& f) { return true; } template constexpr typename std::enable_if::value, bool>::type until(parse &t, function&& f) { return true; } template constexpr typename std::enable_if::value, bool>::type until(const parse &t, function&& f) { using type = tuple_element; const auto &value(static_cast(get(t))); return f(reflect(t), value)? until(t, std::forward(f)): false; } template constexpr typename std::enable_if::value, bool>::type until(parse &t, function&& f) { using type = tuple_element; auto &value(static_cast(get(t))); return f(reflect(t), value)? until(t, std::forward(f)): false; } template constexpr typename std::enable_if<(i < 0), bool>::type runtil(const parse &t, function&& f) { return true; } template constexpr typename std::enable_if<(i < 0), bool>::type runtil(parse &t, function&& f) { return true; } template() - 1> constexpr typename std::enable_if::value, bool>::type runtil(const parse &t, function&& f) { using type = tuple_element; const auto &value(static_cast(get(t))); return f(reflect(t), value)? runtil(t, std::forward(f)): false; } template() - 1> constexpr typename std::enable_if::value, bool>::type runtil(parse &t, function&& f) { using type = tuple_element; auto &value(static_cast(get(t))); return f(reflect(t), value)? runtil(t, std::forward(f)): false; } template constexpr size_t indexof(parse&& t, const string_view &name) { size_t ret(0); const auto res(until(t, [&ret, &name] (const string_view &key, auto&& member) { if(key == name) return false; ++ret; return true; })); return !res? ret : throw std::out_of_range("parse has no member with that name"); } template constexpr bool at(parse&& t, const string_view &name, function&& f) { return until(t, [&name, &f] (const string_view &key, auto&& member) { if(key != name) return true; f(member); return false; }); } template constexpr void keys(parse&& t, const std::function &f) { for_each(t, [&f] (const char *const key, auto&& member) { f(key); }); } template constexpr void values(parse&& t, function&& f) { for_each(t, [&f] (const char *const key, auto&& member) { f(member); }); } } // namespace json } // namespace ircd