// Copyright 2017 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_DECODE_TRAITS_HPP #define JSONCONS_DECODE_TRAITS_HPP #include #include #include #include #include // std::enable_if, std::true_type, std::false_type #include #include #include #include #include #include namespace jsoncons { // decode_traits template struct decode_traits { template static T decode(basic_staj_cursor& cursor, json_decoder& decoder, std::error_code& ec) { decoder.reset(); cursor.read_to(decoder, ec); if (ec) { JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column())); } else if (!decoder.is_valid()) { JSONCONS_THROW(ser_error(conv_errc::conversion_failed, cursor.context().line(), cursor.context().column())); } return decoder.get_result().template as(); } }; // specializations // primitive template struct decode_traits::value >::type> { template static T decode(basic_staj_cursor& cursor, json_decoder&, std::error_code& ec) { T v = cursor.current().template get(ec); return v; } }; // string template struct decode_traits::value && std::is_same::value >::type> { template static T decode(basic_staj_cursor& cursor, json_decoder&, std::error_code& ec) { T v = cursor.current().template get(ec); return v; } }; template struct decode_traits::value && !std::is_same::value >::type> { template static T decode(basic_staj_cursor& cursor, json_decoder&, std::error_code& ec) { auto val = cursor.current().template get>(ec); T s; if (!ec) { unicode_traits::convert(val.data(), val.size(), s); } return s; } }; // std::pair template struct decode_traits, CharT> { template static std::pair decode(basic_staj_cursor& cursor, json_decoder& decoder, std::error_code& ec) { using value_type = std::pair; cursor.array_expected(ec); if (ec) { return value_type{}; } if (cursor.current().event_type() != staj_event_type::begin_array) { ec = conv_errc::not_pair; return value_type(); } cursor.next(ec); // skip past array if (ec) { return value_type(); } T1 v1 = decode_traits::decode(cursor, decoder, ec); if (ec) {return value_type();} cursor.next(ec); if (ec) {return value_type();} T2 v2 = decode_traits::decode(cursor, decoder, ec); if (ec) {return value_type();} cursor.next(ec); if (cursor.current().event_type() != staj_event_type::end_array) { ec = conv_errc::not_pair; return value_type(); } return std::make_pair(v1, v2); } }; // vector like template struct decode_traits::value && type_traits::is_list_like::value && type_traits::is_back_insertable::value && !type_traits::is_typed_array::value >::type> { using value_type = typename T::value_type; template static T decode(basic_staj_cursor& cursor, json_decoder& decoder, std::error_code& ec) { T v; cursor.array_expected(ec); if (ec) { return T{}; } if (cursor.current().event_type() != staj_event_type::begin_array) { ec = conv_errc::not_vector; return v; } cursor.next(ec); while (cursor.current().event_type() != staj_event_type::end_array && !ec) { v.push_back(decode_traits::decode(cursor, decoder, ec)); if (ec) {return T{};} cursor.next(ec); } return v; } }; template struct typed_array_visitor : public default_json_visitor { T& v_; int level_; public: using value_type = typename T::value_type; typed_array_visitor(T& v) : default_json_visitor(false,conv_errc::not_vector), v_(v), level_(0) { } private: bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override { if (++level_ != 1) { ec = conv_errc::not_vector; return false; } return true; } bool visit_begin_array(std::size_t size, semantic_tag, const ser_context&, std::error_code& ec) override { if (++level_ != 1) { ec = conv_errc::not_vector; return false; } if (size > 0) { reserve_storage(typename std::integral_constant::value>::type(), v_, size); } return true; } bool visit_end_array(const ser_context&, std::error_code& ec) override { if (level_ != 1) { ec = conv_errc::not_vector; return false; } return false; } bool visit_uint64(uint64_t value, semantic_tag, const ser_context&, std::error_code&) override { v_.push_back(static_cast(value)); return true; } bool visit_int64(int64_t value, semantic_tag, const ser_context&, std::error_code&) override { v_.push_back(static_cast(value)); return true; } bool visit_half(uint16_t value, semantic_tag, const ser_context&, std::error_code&) override { return visit_half_(typename std::integral_constant::value>::type(), value); } bool visit_half_(std::true_type, uint16_t value) { v_.push_back(static_cast(value)); return true; } bool visit_half_(std::false_type, uint16_t value) { v_.push_back(static_cast(binary::decode_half(value))); return true; } bool visit_double(double value, semantic_tag, const ser_context&, std::error_code&) override { v_.push_back(static_cast(value)); return true; } bool visit_typed_array(const jsoncons::span& data, semantic_tag, const ser_context&, std::error_code&) override { v_ = std::vector(data.begin(),data.end()); return false; } static void reserve_storage(std::true_type, T& v, std::size_t new_cap) { v.reserve(new_cap); } static void reserve_storage(std::false_type, T&, std::size_t) { } }; template struct decode_traits::value && type_traits::is_list_like::value && type_traits::is_back_insertable_byte_container::value && type_traits::is_typed_array::value >::type> { using value_type = typename T::value_type; template static T decode(basic_staj_cursor& cursor, json_decoder&, std::error_code& ec) { cursor.array_expected(ec); if (ec) { return T{}; } switch (cursor.current().event_type()) { case staj_event_type::byte_string_value: { auto bytes = cursor.current().template get(ec); if (!ec) { T v; if (cursor.current().size() > 0) { reserve_storage(typename std::integral_constant::value>::type(), v, cursor.current().size()); } for (auto ch : bytes) { v.push_back(static_cast(ch)); } cursor.next(ec); return v; } else { return T{}; } } case staj_event_type::begin_array: { T v; if (cursor.current().size() > 0) { reserve_storage(typename std::integral_constant::value>::type(), v, cursor.current().size()); } typed_array_visitor visitor(v); cursor.read_to(visitor, ec); return v; } default: { ec = conv_errc::not_vector; return T{}; } } } static void reserve_storage(std::true_type, T& v, std::size_t new_cap) { v.reserve(new_cap); } static void reserve_storage(std::false_type, T&, std::size_t) { } }; template struct decode_traits::value && type_traits::is_list_like::value && type_traits::is_back_insertable::value && !type_traits::is_back_insertable_byte_container::value && type_traits::is_typed_array::value >::type> { using value_type = typename T::value_type; template static T decode(basic_staj_cursor& cursor, json_decoder&, std::error_code& ec) { cursor.array_expected(ec); if (ec) { return T{}; } switch (cursor.current().event_type()) { case staj_event_type::begin_array: { T v; if (cursor.current().size() > 0) { reserve_storage(typename std::integral_constant::value>::type(), v, cursor.current().size()); } typed_array_visitor visitor(v); cursor.read_to(visitor, ec); return v; } default: { ec = conv_errc::not_vector; return T{}; } } } static void reserve_storage(std::true_type, T& v, std::size_t new_cap) { v.reserve(new_cap); } static void reserve_storage(std::false_type, T&, std::size_t) { } }; // set like template struct decode_traits::value && type_traits::is_list_like::value && !type_traits::is_back_insertable::value && type_traits::is_insertable::value >::type> { using value_type = typename T::value_type; template static T decode(basic_staj_cursor& cursor, json_decoder& decoder, std::error_code& ec) { T v; cursor.array_expected(ec); if (ec) { return T{}; } if (cursor.current().event_type() != staj_event_type::begin_array) { ec = conv_errc::not_vector; return v; } if (cursor.current().size() > 0) { reserve_storage(typename std::integral_constant::value>::type(), v, cursor.current().size()); } cursor.next(ec); while (cursor.current().event_type() != staj_event_type::end_array && !ec) { v.insert(decode_traits::decode(cursor, decoder, ec)); if (ec) {return T{};} cursor.next(ec); if (ec) {return T{};} } return v; } static void reserve_storage(std::true_type, T& v, std::size_t new_cap) { v.reserve(new_cap); } static void reserve_storage(std::false_type, T&, std::size_t) { } }; // std::array template struct decode_traits,CharT> { using value_type = typename std::array::value_type; template static std::array decode(basic_staj_cursor& cursor, json_decoder& decoder, std::error_code& ec) { std::array v; cursor.array_expected(ec); if (ec) { v.fill(T()); return v; } v.fill(T{}); if (cursor.current().event_type() != staj_event_type::begin_array) { ec = conv_errc::not_vector; return v; } cursor.next(ec); for (std::size_t i = 0; i < N && cursor.current().event_type() != staj_event_type::end_array && !ec; ++i) { v[i] = decode_traits::decode(cursor, decoder, ec); if (ec) {return v;} cursor.next(ec); if (ec) {return v;} } return v; } }; // map like template struct decode_traits::value && type_traits::is_map_like::value && type_traits::is_constructible_from_const_pointer_and_size::value >::type> { using mapped_type = typename T::mapped_type; using value_type = typename T::value_type; using key_type = typename T::key_type; template static T decode(basic_staj_cursor& cursor, json_decoder& decoder, std::error_code& ec) { T val; if (cursor.current().event_type() != staj_event_type::begin_object) { ec = conv_errc::not_map; return val; } if (cursor.current().size() > 0) { reserve_storage(typename std::integral_constant::value>::type(), val, cursor.current().size()); } cursor.next(ec); while (cursor.current().event_type() != staj_event_type::end_object && !ec) { if (cursor.current().event_type() != staj_event_type::key) { ec = json_errc::expected_key; return val; } auto key = cursor.current().template get(ec); if (ec) return val; cursor.next(ec); if (ec) return val; val.emplace(std::move(key),decode_traits::decode(cursor, decoder, ec)); if (ec) {return val;} cursor.next(ec); if (ec) {return val;} } return val; } static void reserve_storage(std::true_type, T& v, std::size_t new_cap) { v.reserve(new_cap); } static void reserve_storage(std::false_type, T&, std::size_t) { } }; template struct decode_traits::value && type_traits::is_map_like::value && std::is_integral::value >::type> { using mapped_type = typename T::mapped_type; using value_type = typename T::value_type; using key_type = typename T::key_type; template static T decode(basic_staj_cursor& cursor, json_decoder& decoder, std::error_code& ec) { T val; if (cursor.current().event_type() != staj_event_type::begin_object) { ec = conv_errc::not_map; return val; } if (cursor.current().size() > 0) { reserve_storage(typename std::integral_constant::value>::type(), val, cursor.current().size()); } cursor.next(ec); while (cursor.current().event_type() != staj_event_type::end_object && !ec) { if (cursor.current().event_type() != staj_event_type::key) { ec = json_errc::expected_key; return val; } auto s = cursor.current().template get>(ec); if (ec) return val; key_type n{0}; auto r = jsoncons::detail::to_integer(s.data(), s.size(), n); if (r.ec != jsoncons::detail::to_integer_errc()) { ec = json_errc::invalid_number; return val; } cursor.next(ec); if (ec) return val; val.emplace(n, decode_traits::decode(cursor, decoder, ec)); if (ec) {return val;} cursor.next(ec); if (ec) {return val;} } return val; } static void reserve_storage(std::true_type, T& v, std::size_t new_cap) { v.reserve(new_cap); } static void reserve_storage(std::false_type, T&, std::size_t) { } }; } // jsoncons #endif