0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-30 17:34:04 +01:00
construct/include/ircd/json/tuple/set.h

231 lines
4.5 KiB
C++

// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
//
// 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<class dst,
class src>
inline typename std::enable_if
<
std::is_base_of<json::string, dst>() &&
std::is_convertible<src, ircd::string_view>(),
void>::type
_assign(dst &d,
src&& s)
{
d = json::string(string_view(std::forward<src>(s)));
}
template<class dst,
class src>
inline typename std::enable_if
<
!std::is_base_of<json::string, dst>() &&
std::is_convertible<src, dst>() &&
!ircd::json::is_tuple<dst>() &&
!std::is_same<bool, dst>(),
void>::type
_assign(dst &d,
src&& s)
{
d = std::forward<src>(s);
}
template<class dst,
class src>
inline typename std::enable_if
<
!std::is_base_of<json::string, dst>() &&
std::is_convertible<src, dst>() &&
!ircd::json::is_tuple<dst>() &&
std::is_same<bool, dst>(),
void>::type
_assign(dst &d,
src&& s)
{
static const is_zero test{};
d = !test(std::forward<src>(s));
}
template<class dst,
class src>
inline typename std::enable_if
<
std::is_arithmetic<dst>() &&
std::is_base_of<std::string_view, typename std::remove_reference<src>::type>() &&
!std::is_base_of<ircd::byte_view<ircd::string_view>, typename std::remove_reference<src>::type>(),
void>::type
_assign(dst &d,
src&& s)
try
{
d = lex_cast<dst>(std::forward<src>(s));
}
catch(const bad_lex_cast &e)
{
throw parse_error
{
"cannot convert '%s' to '%s'",
demangle<src>(),
demangle<dst>()
};
}
template<class dst,
class src>
inline typename std::enable_if
<
std::is_arithmetic<dst>() &&
std::is_base_of<ircd::byte_view<ircd::string_view>, typename std::remove_reference<src>::type>(),
void>::type
_assign(dst &d,
src&& s)
{
assert(!s.empty());
d = byte_view<dst>(std::forward<src>(s));
}
template<class dst,
class src>
inline typename std::enable_if
<
std::is_base_of<std::string_view, dst>() &&
std::is_trivial<typename std::remove_reference<src>::type>() &&
std::is_standard_layout<typename std::remove_reference<src>::type>(),
void>::type
_assign(dst &d,
src&& s)
{
d = byte_view<string_view>(std::forward<src>(s));
}
template<class dst,
class src>
inline typename std::enable_if
<
ircd::json::is_tuple<dst>() &&
std::is_assignable<dst, src>(),
void>::type
_assign(dst &d,
src&& s)
{
d = std::forward<src>(s);
}
template<class dst,
class src>
inline typename std::enable_if
<
ircd::json::is_tuple<dst>() &&
!std::is_assignable<dst, src>() &&
std::is_constructible<dst, src>(),
void>::type
_assign(dst &d,
src&& s)
{
d = dst{std::forward<src>(s)};
}
template<class dst,
class src>
inline typename std::enable_if
<
ircd::json::is_tuple<dst>() &&
!std::is_assignable<dst, src>() &&
!std::is_constructible<dst, src>(),
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<class V,
class... T>
inline tuple<T...> &
set(tuple<T...> &t,
const string_view &key,
V&& val)
try
{
at(t, key, [&key, &val]
(auto &target)
{
_assign(target, std::forward<V>(val));
});
return t;
}
catch(const std::exception &e)
{
throw parse_error
{
"failed to set member '%s' (from %s): %s",
key,
demangle<V>(),
e.what()
};
}
template<class... T>
inline tuple<T...> &
set(tuple<T...> &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.serial)
set(t, key, string_view{value});
else 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