// Copyright 2013 Daniel Parker // Distributed under the Boost license, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // See https://github.com/danielaparker/jsoncons for latest version #ifndef JSONCONS_JSON_TYPE_TRAITS_HPP #define JSONCONS_JSON_TYPE_TRAITS_HPP #include #include #include #include #include #include #include #include #include // std::swap #include // std::numeric_limits #include // std::enable_if #include // std::iterator_traits, std::input_iterator_tag #include #include #include #include #include #include #include #include #include #include // std::bitset #include #include #if defined(JSONCONS_HAS_STD_VARIANT) #include #endif namespace jsoncons { template struct is_json_type_traits_declared : public std::false_type {}; #if !defined(JSONCONS_NO_DEPRECATED) template using is_json_type_traits_impl = is_json_type_traits_declared; #endif // json_type_traits template struct unimplemented : std::false_type {}; template struct json_type_traits { using allocator_type = typename Json::allocator_type; static constexpr bool is_compatible = false; static constexpr bool is(const Json&) noexcept { return false; } static T as(const Json&) { static_assert(unimplemented::value, "as not implemented"); } static Json to_json(const T&, const allocator_type& = allocator_type()) { static_assert(unimplemented::value, "to_json not implemented"); } }; namespace detail { template using traits_can_convert_t = decltype(json_type_traits::can_convert(Json())); template using has_can_convert = type_traits::is_detected; template struct invoke_can_convert { template static typename std::enable_if::value,bool>::type can_convert(const Json& j) noexcept { return json_type_traits::can_convert(j); } template static typename std::enable_if::value,bool>::type can_convert(const Json& j) noexcept { return json_type_traits::is(j); } }; // is_json_type_traits_unspecialized template struct is_json_type_traits_unspecialized : std::false_type {}; // is_json_type_traits_unspecialized template struct is_json_type_traits_unspecialized::is_compatible>::value>::type > : std::true_type {}; // is_compatible_array_type template struct is_compatible_array_type : std::false_type {}; template struct is_compatible_array_type::value && type_traits::is_list_like::value && !is_json_type_traits_unspecialized::value_type>::value >::type> : std::true_type {}; } // namespace detail // is_json_type_traits_specialized template struct is_json_type_traits_specialized : std::false_type {}; template struct is_json_type_traits_specialized::value >::type> : std::true_type {}; template struct json_type_traits::type*> { using char_type = typename Json::char_type; using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_string(); } static const char_type* as(const Json& j) { return j.as_cstring(); } template static Json to_json(const char_type* s, Args&&... args) { return Json(s, semantic_tag::none, std::forward(args)...); } }; template struct json_type_traits::type*> { using char_type = typename Json::char_type; using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_string(); } template static Json to_json(const char_type* s, Args&&... args) { return Json(s, semantic_tag::none, std::forward(args)...); } }; // integer template struct json_type_traits::value >::type> { using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.template is_integer(); } static T as(const Json& j) { return j.template as_integer(); } static Json to_json(T val, allocator_type alloc = allocator_type()) { return Json(val, semantic_tag::none, alloc); } }; template struct json_type_traits::value >::type> { using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_double(); } static T as(const Json& j) { return static_cast(j.as_double()); } static Json to_json(T val, allocator_type = allocator_type()) { return Json(val, semantic_tag::none); } }; template struct json_type_traits { using json_object = typename Json::object; using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_object(); } static Json to_json(const json_object& o, const allocator_type& = allocator_type()) { return Json(o,semantic_tag::none); } }; template struct json_type_traits { using json_array = typename Json::array; using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_array(); } static Json to_json(const json_array& a, const allocator_type& = allocator_type()) { return Json(a, semantic_tag::none); } }; template struct json_type_traits { using allocator_type = typename Json::allocator_type; static bool is(const Json&) noexcept { return true; } static Json as(Json j) { return j; } static Json to_json(const Json& val, allocator_type = allocator_type()) { return val; } }; template struct json_type_traits { using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_null(); } static typename jsoncons::null_type as(const Json& j) { if (!j.is_null()) { JSONCONS_THROW(conv_error(conv_errc::not_jsoncons_null_type)); } return jsoncons::null_type(); } static Json to_json(jsoncons::null_type, allocator_type = allocator_type()) { return Json::null(); } }; template struct json_type_traits { using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_bool(); } static bool as(const Json& j) { return j.as_bool(); } static Json to_json(bool val, allocator_type = allocator_type()) { return Json(val, semantic_tag::none); } }; template struct json_type_traits::const_reference>::value, std::vector::const_reference, void>::type>::value>::type> { using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_bool(); } static bool as(const Json& j) { return j.as_bool(); } static Json to_json(bool val, allocator_type = allocator_type()) { return Json(val, semantic_tag::none); } }; template struct json_type_traits::reference> { using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_bool(); } static bool as(const Json& j) { return j.as_bool(); } static Json to_json(bool val, allocator_type = allocator_type()) { return Json(val, semantic_tag::none); } }; template struct json_type_traits::value && type_traits::is_basic_string::value && std::is_same::value>::type> { using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_string(); } static T as(const Json& j) { return T(j.as_string()); } static Json to_json(const T& val) { return Json(val, semantic_tag::none); } static Json to_json(const T& val, const allocator_type& alloc) { return Json(val, semantic_tag::none, alloc); } }; template struct json_type_traits::value && type_traits::is_basic_string::value && !std::is_same::value>::type> { using char_type = typename Json::char_type; using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_string(); } static T as(const Json& j) { auto s = j.as_string(); T val; unicode_traits::convert(s.data(), s.size(), val); return val; } static Json to_json(const T& val) { std::basic_string s; unicode_traits::convert(val.data(), val.size(), s); return Json(s, semantic_tag::none); } static Json to_json(const T& val, const allocator_type& alloc) { std::basic_string s; unicode_traits::convert(val.data(), val.size(), s); return Json(s, semantic_tag::none, alloc); } }; template struct json_type_traits::value && type_traits::is_basic_string_view::value && std::is_same::value>::type> { using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_string_view(); } static T as(const Json& j) { return T(j.as_string_view().data(),j.as_string_view().size()); } static Json to_json(const T& val) { return Json(val, semantic_tag::none); } static Json to_json(const T& val, const allocator_type& alloc) { return Json(val, semantic_tag::none, alloc); } }; // array back insertable template struct json_type_traits::value && jsoncons::detail::is_compatible_array_type::value && type_traits::is_back_insertable::value >::type> { typedef typename std::iterator_traits::value_type value_type; using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { bool result = j.is_array(); if (result) { for (auto e : j.array_range()) { if (!e.template is()) { result = false; break; } } } return result; } // array back insertable non-byte container template static typename std::enable_if::value,Container>::type as(const Json& j) { if (j.is_array()) { T result; visit_reserve_(typename std::integral_constant::value>::type(),result,j.size()); for (const auto& item : j.array_range()) { result.push_back(item.template as()); } return result; } else { JSONCONS_THROW(conv_error(conv_errc::not_vector)); } } // array back insertable byte container template static typename std::enable_if::value,Container>::type as(const Json& j) { converter convert; std::error_code ec; if (j.is_array()) { T result; visit_reserve_(typename std::integral_constant::value>::type(),result,j.size()); for (const auto& item : j.array_range()) { result.push_back(item.template as()); } return result; } else if (j.is_byte_string_view()) { auto v = convert.from(j.as_byte_string_view(),j.tag(), ec); if (ec) { JSONCONS_THROW(conv_error(ec)); } return v; } else if (j.is_string()) { auto v = convert.from(j.as_string_view(),j.tag(), ec); if (ec) { JSONCONS_THROW(conv_error(ec)); } return v; } else { JSONCONS_THROW(conv_error(conv_errc::not_vector)); } } template static typename std::enable_if::value,Json>::type to_json(const T& val) { Json j(json_array_arg); auto first = std::begin(val); auto last = std::end(val); std::size_t size = std::distance(first,last); j.reserve(size); for (auto it = first; it != last; ++it) { j.push_back(*it); } return j; } template static typename std::enable_if::value,Json>::type to_json(const T& val, const allocator_type& alloc) { Json j(json_array_arg, alloc); auto first = std::begin(val); auto last = std::end(val); std::size_t size = std::distance(first, last); j.reserve(size); for (auto it = first; it != last; ++it) { j.push_back(*it); } return j; } template static typename std::enable_if::value,Json>::type to_json(const T& val) { Json j(byte_string_arg, val); return j; } template static typename std::enable_if::value,Json>::type to_json(const T& val, const allocator_type& alloc) { Json j(byte_string_arg, val, semantic_tag::none, alloc); return j; } static void visit_reserve_(std::true_type, T& v, std::size_t size) { v.reserve(size); } static void visit_reserve_(std::false_type, T&, std::size_t) { } }; // array, not back insertable but insertable template struct json_type_traits::value && jsoncons::detail::is_compatible_array_type::value && !type_traits::is_back_insertable::value && type_traits::is_insertable::value>::type> { typedef typename std::iterator_traits::value_type value_type; using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { bool result = j.is_array(); if (result) { for (auto e : j.array_range()) { if (!e.template is()) { result = false; break; } } } return result; } static T as(const Json& j) { if (j.is_array()) { T result; for (const auto& item : j.array_range()) { result.insert(item.template as()); } return result; } else { JSONCONS_THROW(conv_error(conv_errc::not_vector)); } } static Json to_json(const T& val) { Json j(json_array_arg); auto first = std::begin(val); auto last = std::end(val); std::size_t size = std::distance(first,last); j.reserve(size); for (auto it = first; it != last; ++it) { j.push_back(*it); } return j; } static Json to_json(const T& val, const allocator_type& alloc) { Json j(json_array_arg, alloc); auto first = std::begin(val); auto last = std::end(val); std::size_t size = std::distance(first, last); j.reserve(size); for (auto it = first; it != last; ++it) { j.push_back(*it); } return j; } }; // array not back insertable or insertable, but front insertable template struct json_type_traits::value && jsoncons::detail::is_compatible_array_type::value && !type_traits::is_back_insertable::value && !type_traits::is_insertable::value && type_traits::is_front_insertable::value>::type> { typedef typename std::iterator_traits::value_type value_type; using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { bool result = j.is_array(); if (result) { for (auto e : j.array_range()) { if (!e.template is()) { result = false; break; } } } return result; } static T as(const Json& j) { if (j.is_array()) { T result; auto it = j.array_range().rbegin(); auto end = j.array_range().rend(); for (; it != end; ++it) { result.push_front((*it).template as()); } return result; } else { JSONCONS_THROW(conv_error(conv_errc::not_vector)); } } static Json to_json(const T& val) { Json j(json_array_arg); auto first = std::begin(val); auto last = std::end(val); std::size_t size = std::distance(first,last); j.reserve(size); for (auto it = first; it != last; ++it) { j.push_back(*it); } return j; } static Json to_json(const T& val, const allocator_type& alloc) { Json j(json_array_arg, alloc); auto first = std::begin(val); auto last = std::end(val); std::size_t size = std::distance(first, last); j.reserve(size); for (auto it = first; it != last; ++it) { j.push_back(*it); } return j; } }; // std::array template struct json_type_traits> { using allocator_type = typename Json::allocator_type; using value_type = E; static bool is(const Json& j) noexcept { bool result = j.is_array() && j.size() == N; if (result) { for (auto e : j.array_range()) { if (!e.template is()) { result = false; break; } } } return result; } static std::array as(const Json& j) { std::array buff; if (j.size() != N) { JSONCONS_THROW(conv_error(conv_errc::not_array)); } for (std::size_t i = 0; i < N; i++) { buff[i] = j[i].template as(); } return buff; } static Json to_json(const std::array& val) { Json j(json_array_arg); j.reserve(N); for (auto it = val.begin(); it != val.end(); ++it) { j.push_back(*it); } return j; } static Json to_json(const std::array& val, const allocator_type& alloc) { Json j(json_array_arg, alloc); j.reserve(N); for (auto it = val.begin(); it != val.end(); ++it) { j.push_back(*it); } return j; } }; // map like template struct json_type_traits::value && type_traits::is_map_like::value && type_traits::is_constructible_from_const_pointer_and_size::value && is_json_type_traits_specialized::value>::type > { using mapped_type = typename T::mapped_type; using value_type = typename T::value_type; using key_type = typename T::key_type; using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { bool result = j.is_object(); for (auto member : j.object_range()) { if (!member.value().template is()) { result = false; } } return result; } static T as(const Json& j) { if (!j.is_object()) { JSONCONS_THROW(conv_error(conv_errc::not_map)); } T result; for (const auto& item : j.object_range()) { result.emplace(key_type(item.key().data(),item.key().size()), item.value().template as()); } return result; } static Json to_json(const T& val) { Json j(json_object_arg, val.begin(), val.end()); return j; } static Json to_json(const T& val, const allocator_type& alloc) { Json j(json_object_arg, val.begin(), val.end(), alloc); return j; } }; template struct json_type_traits::value && type_traits::is_map_like::value && !type_traits::is_constructible_from_const_pointer_and_size::value && is_json_type_traits_specialized::value && is_json_type_traits_specialized::value>::type > { using mapped_type = typename T::mapped_type; using value_type = typename T::value_type; using key_type = typename T::key_type; using allocator_type = typename Json::allocator_type; static bool is(const Json& val) noexcept { if (!val.is_object()) return false; for (const auto& item : val.object_range()) { Json j(item.key()); if (!j.template is()) { return false; } if (!item.value().template is()) { return false; } } return true; } static T as(const Json& val) { T result; for (const auto& item : val.object_range()) { Json j(item.key()); auto key = json_type_traits::as(j); result.emplace(std::move(key), item.value().template as()); } return result; } static Json to_json(const T& val) { Json j(json_object_arg); j.reserve(val.size()); for (const auto& item : val) { auto temp = json_type_traits::to_json(item.first); typename Json::key_type key; temp.dump(key); j.try_emplace(std::move(key), item.second); } return j; } static Json to_json(const T& val, const allocator_type& alloc) { Json j(json_object_arg, semantic_tag::none, alloc); j.reserve(val.size()); for (const auto& item : val) { auto temp = json_type_traits::to_json(item.first, alloc); typename Json::key_type key(alloc); temp.dump(key); j.try_emplace(std::move(key), item.second, alloc); } return j; } }; namespace tuple_detail { template struct json_tuple_helper { using element_type = typename std::tuple_element::type; using next = json_tuple_helper; static bool is(const Json& j) noexcept { if (j[Size-Pos].template is()) { return next::is(j); } else { return false; } } static void as(Tuple& tuple, const Json& j) { std::get(tuple) = j[Size-Pos].template as(); next::as(tuple, j); } static void to_json(const Tuple& tuple, Json& j) { j.push_back(json_type_traits::to_json(std::get(tuple))); next::to_json(tuple, j); } }; template struct json_tuple_helper<0, Size, Json, Tuple> { static bool is(const Json&) noexcept { return true; } static void as(Tuple&, const Json&) { } static void to_json(const Tuple&, Json&) { } }; } // namespace detail template struct json_type_traits> { private: using helper = tuple_detail::json_tuple_helper>; public: using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return helper::is(j); } static std::tuple as(const Json& j) { std::tuple buff; helper::as(buff, j); return buff; } static Json to_json(const std::tuple& val) { Json j(json_array_arg); j.reserve(sizeof...(E)); helper::to_json(val, j); return j; } static Json to_json(const std::tuple& val, const allocator_type& alloc) { Json j(json_array_arg, alloc); j.reserve(sizeof...(E)); helper::to_json(val, j); return j; } }; template struct json_type_traits> { public: using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_array() && j.size() == 2; } static std::pair as(const Json& j) { return std::make_pair(j[0].template as(),j[1].template as()); } static Json to_json(const std::pair& val) { Json j(json_array_arg); j.reserve(2); j.push_back(val.first); j.push_back(val.second); return j; } static Json to_json(const std::pair& val, const allocator_type& alloc) { Json j(json_array_arg, alloc); j.reserve(2); j.push_back(val.first); j.push_back(val.second); return j; } }; template struct json_type_traits::value>::type> { public: using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_byte_string(); } static T as(const Json& j) { return j.template as_byte_string(); } static Json to_json(const T& val, const allocator_type& alloc = allocator_type()) { return Json(byte_string_arg, val, semantic_tag::none, alloc); } }; template struct json_type_traits, typename std::enable_if>::value && !std::is_polymorphic::value >::type> { static bool is(const Json& j) noexcept { return j.is_null() || j.template is(); } static std::shared_ptr as(const Json& j) { return j.is_null() ? std::shared_ptr(nullptr) : std::make_shared(j.template as()); } static Json to_json(const std::shared_ptr& ptr) { if (ptr.get() != nullptr) { Json j(*ptr); return j; } else { return Json::null(); } } }; template struct json_type_traits, typename std::enable_if>::value && !std::is_polymorphic::value >::type> { static bool is(const Json& j) noexcept { return j.is_null() || j.template is(); } static std::unique_ptr as(const Json& j) { return j.is_null() ? std::unique_ptr(nullptr) : jsoncons::make_unique(j.template as()); } static Json to_json(const std::unique_ptr& ptr) { if (ptr.get() != nullptr) { Json j(*ptr); return j; } else { return Json::null(); } } }; template struct json_type_traits, typename std::enable_if>::value>::type> { public: static bool is(const Json& j) noexcept { return j.is_null() || j.template is(); } static jsoncons::optional as(const Json& j) { return j.is_null() ? jsoncons::optional() : jsoncons::optional(j.template as()); } static Json to_json(const jsoncons::optional& val) { return val.has_value() ? Json(*val) : Json::null(); } }; template struct json_type_traits { using allocator_type = typename Json::allocator_type; public: static bool is(const Json& j) noexcept { return j.is_byte_string_view(); } static byte_string_view as(const Json& j) { return j.as_byte_string_view(); } static Json to_json(const byte_string_view& val, const allocator_type& alloc = allocator_type()) { return Json(byte_string_arg, val, semantic_tag::none, alloc); } }; // basic_bigint template struct json_type_traits> { public: using char_type = typename Json::char_type; static bool is(const Json& j) noexcept { switch (j.type()) { case json_type::string_value: return jsoncons::detail::is_base10(j.as_string_view().data(), j.as_string_view().length()); case json_type::int64_value: case json_type::uint64_value: return true; default: return false; } } static basic_bigint as(const Json& j) { switch (j.type()) { case json_type::string_value: if (!jsoncons::detail::is_base10(j.as_string_view().data(), j.as_string_view().length())) { JSONCONS_THROW(conv_error(conv_errc::not_bigint)); } return basic_bigint::from_string(j.as_string_view().data(), j.as_string_view().length()); case json_type::half_value: case json_type::double_value: return basic_bigint(j.template as()); case json_type::int64_value: return basic_bigint(j.template as()); case json_type::uint64_value: return basic_bigint(j.template as()); default: JSONCONS_THROW(conv_error(conv_errc::not_bigint)); } } static Json to_json(const basic_bigint& val) { std::basic_string s; val.write_string(s); return Json(s,semantic_tag::bigint); } }; // std::valarray template struct json_type_traits> { using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { bool result = j.is_array(); if (result) { for (auto e : j.array_range()) { if (!e.template is()) { result = false; break; } } } return result; } static std::valarray as(const Json& j) { if (j.is_array()) { std::valarray v(j.size()); for (std::size_t i = 0; i < j.size(); ++i) { v[i] = j[i].template as(); } return v; } else { JSONCONS_THROW(conv_error(conv_errc::not_array)); } } static Json to_json(const std::valarray& val) { Json j(json_array_arg); auto first = std::begin(val); auto last = std::end(val); std::size_t size = std::distance(first,last); j.reserve(size); for (auto it = first; it != last; ++it) { j.push_back(*it); } return j; } static Json to_json(const std::valarray& val, const allocator_type& alloc) { Json j(json_array_arg, alloc); auto first = std::begin(val); auto last = std::end(val); std::size_t size = std::distance(first,last); j.reserve(size); for (auto it = first; it != last; ++it) { j.push_back(*it); } return j; } }; #if defined(JSONCONS_HAS_STD_VARIANT) namespace variant_detail { template typename std::enable_if, bool>::type is_variant(const Json& /*j*/) { return false; } template typename std::enable_if, bool>::type is_variant(const Json& j) { if (j.template is()) { return true; } else { return is_variant(j); } } template typename std::enable_if, Variant>::type as_variant(const Json& /*j*/) { JSONCONS_THROW(conv_error(conv_errc::not_variant)); } template typename std::enable_if, Variant>::type as_variant(const Json& j) { if (j.template is()) { Variant var(j.template as()); return var; } else { return as_variant(j); } } template struct variant_to_json_visitor { Json& j_; variant_to_json_visitor(Json& j) : j_(j) {} template void operator()(const T& value) const { j_ = value; } }; } // namespace variant_detail template struct json_type_traits> { public: using variant_type = typename std::variant; using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return variant_detail::is_variant<0,Json,variant_type, VariantTypes...>(j); } static std::variant as(const Json& j) { return variant_detail::as_variant<0,Json,variant_type, VariantTypes...>(j); } static Json to_json(const std::variant& var) { Json j(json_array_arg); variant_detail::variant_to_json_visitor visitor(j); std::visit(visitor, var); return j; } static Json to_json(const std::variant& var, const allocator_type& alloc) { Json j(json_array_arg, alloc); variant_detail::variant_to_json_visitor visitor(j); std::visit(visitor, var); return j; } }; #endif // std::chrono::duration template struct json_type_traits> { using duration_type = std::chrono::duration; using allocator_type = typename Json::allocator_type; static constexpr int64_t nanos_in_milli = 1000000; static constexpr int64_t nanos_in_second = 1000000000; static constexpr int64_t millis_in_second = 1000; static bool is(const Json& j) noexcept { return (j.tag() == semantic_tag::epoch_second || j.tag() == semantic_tag::epoch_milli || j.tag() == semantic_tag::epoch_nano); } static duration_type as(const Json& j) { return from_json_(j); } static Json to_json(const duration_type& val, allocator_type = allocator_type()) { return to_json_(val); } template static typename std::enable_if>::value, duration_type>::type from_json_(const Json& j) { if (j.is_int64() || j.is_uint64() || j.is_double()) { auto count = j.template as(); switch (j.tag()) { case semantic_tag::epoch_second: return duration_type(count); case semantic_tag::epoch_milli: return duration_type(count == 0 ? 0 : count/millis_in_second); case semantic_tag::epoch_nano: return duration_type(count == 0 ? 0 : count/nanos_in_second); default: return duration_type(count); } } else if (j.is_string()) { switch (j.tag()) { case semantic_tag::epoch_second: { auto count = j.template as(); return duration_type(count); } case semantic_tag::epoch_milli: { auto sv = j.as_string_view(); bigint n = bigint::from_string(sv.data(), sv.length()); if (n != 0) { n = n / millis_in_second; } return duration_type(static_cast(n)); } case semantic_tag::epoch_nano: { auto sv = j.as_string_view(); bigint n = bigint::from_string(sv.data(), sv.length()); if (n != 0) { n = n / nanos_in_second; } return duration_type(static_cast(n)); } default: { auto count = j.template as(); return duration_type(count); } } } else { return duration_type(); } } template static typename std::enable_if::value, duration_type>::type from_json_(const Json& j) { if (j.is_int64() || j.is_uint64()) { auto count = j.template as(); switch (j.tag()) { case semantic_tag::epoch_second: return duration_type(count*millis_in_second); case semantic_tag::epoch_milli: return duration_type(count); case semantic_tag::epoch_nano: return duration_type(count == 0 ? 0 : count/nanos_in_milli); default: return duration_type(count); } } else if (j.is_double()) { auto count = j.template as(); switch (j.tag()) { case semantic_tag::epoch_second: return duration_type(static_cast(count * millis_in_second)); case semantic_tag::epoch_milli: return duration_type(static_cast(count)); case semantic_tag::epoch_nano: return duration_type(count == 0 ? 0 : static_cast(count / nanos_in_milli)); default: return duration_type(static_cast(count)); } } else if (j.is_string()) { switch (j.tag()) { case semantic_tag::epoch_second: { auto count = j.template as(); return duration_type(count*millis_in_second); } case semantic_tag::epoch_milli: { auto sv = j.as_string_view(); Rep n{0}; auto result = jsoncons::detail::to_integer_decimal(sv.data(), sv.size(), n); if (!result) { return duration_type(); } return duration_type(n); } case semantic_tag::epoch_nano: { auto sv = j.as_string_view(); bigint n = bigint::from_string(sv.data(), sv.length()); if (n != 0) { n = n / nanos_in_milli; } return duration_type(static_cast(n)); } default: { auto count = j.template as(); return duration_type(count); } } } else { return duration_type(); } } template static typename std::enable_if::value, duration_type>::type from_json_(const Json& j) { if (j.is_int64() || j.is_uint64() || j.is_double()) { auto count = j.template as(); switch (j.tag()) { case semantic_tag::epoch_second: return duration_type(count*nanos_in_second); case semantic_tag::epoch_milli: return duration_type(count*nanos_in_milli); case semantic_tag::epoch_nano: return duration_type(count); default: return duration_type(count); } } else if (j.is_double()) { auto count = j.template as(); switch (j.tag()) { case semantic_tag::epoch_second: return duration_type(static_cast(count * nanos_in_second)); case semantic_tag::epoch_milli: return duration_type(static_cast(count * nanos_in_milli)); case semantic_tag::epoch_nano: return duration_type(static_cast(count)); default: return duration_type(static_cast(count)); } } else if (j.is_string()) { auto count = j.template as(); switch (j.tag()) { case semantic_tag::epoch_second: return duration_type(count*nanos_in_second); case semantic_tag::epoch_milli: return duration_type(count*nanos_in_milli); case semantic_tag::epoch_nano: return duration_type(count); default: return duration_type(count); } } else { return duration_type(); } } template static typename std::enable_if>::value,Json>::type to_json_(const duration_type& val) { return Json(val.count(), semantic_tag::epoch_second); } template static typename std::enable_if::value,Json>::type to_json_(const duration_type& val) { return Json(val.count(), semantic_tag::epoch_milli); } template static typename std::enable_if::value,Json>::type to_json_(const duration_type& val) { return Json(val.count(), semantic_tag::epoch_nano); } }; // std::nullptr_t template struct json_type_traits { using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { return j.is_null(); } static std::nullptr_t as(const Json& j) { if (!j.is_null()) { JSONCONS_THROW(conv_error(conv_errc::not_nullptr)); } return nullptr; } static Json to_json(const std::nullptr_t&, allocator_type = allocator_type()) { return Json::null(); } }; // std::bitset struct null_back_insertable_byte_container { using value_type = uint8_t; void push_back(value_type) { } }; template struct json_type_traits> { using allocator_type = typename Json::allocator_type; static bool is(const Json& j) noexcept { if (j.is_byte_string()) { return true; } else if (j.is_string()) { jsoncons::string_view sv = j.as_string_view(); null_back_insertable_byte_container cont; auto result = decode_base16(sv.begin(), sv.end(), cont); return result.ec == conv_errc::success ? true : false; } return false; } static std::bitset as(const Json& j) { if (j.template is()) { auto bits = j.template as(); std::bitset bs = static_cast(bits); return bs; } else if (j.is_byte_string() || j.is_string()) { std::bitset bs; std::vector bits; if (j.is_byte_string()) { bits = j.template as>(); } else { jsoncons::string_view sv = j.as_string_view(); auto result = decode_base16(sv.begin(), sv.end(), bits); if (result.ec != conv_errc::success) { JSONCONS_THROW(conv_error(conv_errc::not_bitset)); } } std::uint8_t byte = 0; std::uint8_t mask = 0; std::size_t pos = 0; for (std::size_t i = 0; i < N; ++i) { if (mask == 0) { if (pos >= bits.size()) { JSONCONS_THROW(conv_error(conv_errc::not_bitset)); } byte = bits.at(pos++); mask = 0x80; } if (byte & mask) { bs[i] = 1; } mask = static_cast(mask >> 1); } return bs; } else { JSONCONS_THROW(conv_error(conv_errc::not_bitset)); } } static Json to_json(const std::bitset& val, const allocator_type& alloc = allocator_type()) { std::vector bits; uint8_t byte = 0; uint8_t mask = 0x80; for (std::size_t i = 0; i < N; ++i) { if (val[i]) { byte |= mask; } mask = static_cast(mask >> 1); if (mask == 0) { bits.push_back(byte); byte = 0; mask = 0x80; } } // Encode remainder if (mask != 0x80) { bits.push_back(byte); } Json j(byte_string_arg, bits, semantic_tag::base16, alloc); return j; } }; } // jsoncons #endif