// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 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. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_IRCD_JSON_TUPLE_SET_H namespace ircd { namespace json { template typename std::enable_if < std::is_base_of() && std::is_convertible(), void>::type _assign(dst &d, src&& s) { d = unquote(string_view{std::forward(s)}); } template typename std::enable_if < !std::is_base_of() && std::is_convertible() && !ircd::json::is_tuple() && !std::is_same(), void>::type _assign(dst &d, src&& s) { d = std::forward(s); } template typename std::enable_if < !std::is_base_of() && std::is_convertible() && !ircd::json::is_tuple() && std::is_same(), void>::type _assign(dst &d, src&& s) { static const is_zero test{}; d = !test(std::forward(s)); } template typename std::enable_if < std::is_arithmetic() && std::is_base_of::type>() && !std::is_base_of, typename std::remove_reference::type>(), void>::type _assign(dst &d, src&& s) try { d = lex_cast(std::forward(s)); } catch(const bad_lex_cast &e) { throw parse_error { "cannot convert '%s' to '%s'", demangle(), demangle() }; } template typename std::enable_if < std::is_arithmetic() && std::is_base_of, typename std::remove_reference::type>(), void>::type _assign(dst &d, src&& s) { assert(!s.empty()); d = byte_view(std::forward(s)); } template typename std::enable_if < std::is_base_of() && std::is_pod::type>(), void>::type _assign(dst &d, src&& s) { d = byte_view(std::forward(s)); } template typename std::enable_if < ircd::json::is_tuple() && std::is_assignable(), void>::type _assign(dst &d, src&& s) { d = std::forward(s); } template typename std::enable_if < ircd::json::is_tuple() && !std::is_assignable() && std::is_constructible(), void>::type _assign(dst &d, src&& s) { d = dst{std::forward(s)}; } template typename std::enable_if < ircd::json::is_tuple() && !std::is_assignable() && !std::is_constructible(), void>::type #ifdef __clang__ //__attribute__((unavailable("Unhandled assignment to json::tuple property"))) #else __attribute__((error("Unhandled assignment to json::tuple property"))) #endif _assign(dst &d, src&& s) { } template tuple & set(tuple &t, const string_view &key, V&& val) try { at(t, key, [&key, &val] (auto &target) { _assign(target, std::forward(val)); }); return t; } catch(const std::exception &e) { throw parse_error { "failed to set member '%s' (from %s): %s", key, demangle(), e.what() }; } template tuple & set(tuple &t, const string_view &key, const json::value &value) { switch(type(value)) { case type::STRING: case type::LITERAL: { set(t, key, string_view{value}); break; } case type::NUMBER: { if(value.floats) set(t, key, value.floating); else set(t, key, value.integer); break; } case type::OBJECT: case type::ARRAY: { if(unlikely(!value.serial)) throw print_error { "Type %s must be JSON to be used by tuple member '%s'", reflect(type(value)), key }; set(t, key, string_view{value}); break; } } return t; } } // namespace json } // namespace ircd