diff options
Diffstat (limited to 'include/jsoncons/encode_traits.hpp')
-rw-r--r-- | include/jsoncons/encode_traits.hpp | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/include/jsoncons/encode_traits.hpp b/include/jsoncons/encode_traits.hpp new file mode 100644 index 0000000..ae981af --- /dev/null +++ b/include/jsoncons/encode_traits.hpp @@ -0,0 +1,378 @@ +// 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_ENCODE_TRAITS_HPP +#define JSONCONS_ENCODE_TRAITS_HPP + +#include <string> +#include <tuple> +#include <array> +#include <memory> +#include <type_traits> // std::enable_if, std::true_type, std::false_type +#include <jsoncons/json_visitor.hpp> +#include <jsoncons/json_decoder.hpp> +#include <jsoncons/json_options.hpp> +#include <jsoncons/json_encoder.hpp> +#include <jsoncons/json_type_traits.hpp> +#include <jsoncons/conv_error.hpp> + +namespace jsoncons { + + // encode_traits + + template <class T, class CharT, class Enable = void> + struct encode_traits + { + template <class Json> + static void encode(const T& val, + basic_json_visitor<CharT>& encoder, + const Json& proto, + std::error_code& ec) + { + encode(std::integral_constant<bool, type_traits::is_stateless<typename Json::allocator_type>::value>(), + val, encoder, proto, ec); + } + private: + template <class Json> + static void encode(std::true_type, + const T& val, + basic_json_visitor<CharT>& encoder, + const Json& /*proto*/, + std::error_code& ec) + { + auto j = json_type_traits<Json,T>::to_json(val); + j.dump(encoder, ec); + } + template <class Json> + static void encode(std::false_type, + const T& val, + basic_json_visitor<CharT>& encoder, + const Json& proto, + std::error_code& ec) + { + auto j = json_type_traits<Json,T>::to_json(val, proto.get_allocator()); + j.dump(encoder, ec); + } + }; + + // specializations + + // bool + template <class T, class CharT> + struct encode_traits<T,CharT, + typename std::enable_if<type_traits::is_bool<T>::value + >::type> + { + template <class Json> + static void encode(const T& val, + basic_json_visitor<CharT>& encoder, + const Json&, + std::error_code& ec) + { + encoder.bool_value(val,semantic_tag::none,ser_context(),ec); + } + }; + + // uint + template <class T, class CharT> + struct encode_traits<T,CharT, + typename std::enable_if<type_traits::is_u8_u16_u32_or_u64<T>::value + >::type> + { + template <class Json> + static void encode(const T& val, + basic_json_visitor<CharT>& encoder, + const Json&, + std::error_code& ec) + { + encoder.uint64_value(val,semantic_tag::none,ser_context(),ec); + } + }; + + // int + template <class T, class CharT> + struct encode_traits<T,CharT, + typename std::enable_if<type_traits::is_i8_i16_i32_or_i64<T>::value + >::type> + { + template <class Json> + static void encode(const T& val, + basic_json_visitor<CharT>& encoder, + const Json&, + std::error_code& ec) + { + encoder.int64_value(val,semantic_tag::none,ser_context(),ec); + } + }; + + // float or double + template <class T, class CharT> + struct encode_traits<T,CharT, + typename std::enable_if<type_traits::is_float_or_double<T>::value + >::type> + { + template <class Json> + static void encode(const T& val, + basic_json_visitor<CharT>& encoder, + const Json&, + std::error_code& ec) + { + encoder.double_value(val,semantic_tag::none,ser_context(),ec); + } + }; + + // string + template <class T, class CharT> + struct encode_traits<T,CharT, + typename std::enable_if<type_traits::is_basic_string<T>::value && + std::is_same<typename T::value_type,CharT>::value + >::type> + { + template <class Json> + static void encode(const T& val, + basic_json_visitor<CharT>& encoder, + const Json&, + std::error_code& ec) + { + encoder.string_value(val,semantic_tag::none,ser_context(),ec); + } + }; + template <class T, class CharT> + struct encode_traits<T,CharT, + typename std::enable_if<type_traits::is_basic_string<T>::value && + !std::is_same<typename T::value_type,CharT>::value + >::type> + { + template <class Json> + static void encode(const T& val, + basic_json_visitor<CharT>& encoder, + const Json&, + std::error_code& ec) + { + std::basic_string<CharT> s; + unicode_traits::convert(val.data(), val.size(), s); + encoder.string_value(s,semantic_tag::none,ser_context(),ec); + } + }; + + // std::pair + + template <class T1, class T2, class CharT> + struct encode_traits<std::pair<T1, T2>, CharT> + { + using value_type = std::pair<T1, T2>; + + template <class Json> + static void encode(const value_type& val, + basic_json_visitor<CharT>& encoder, + const Json& proto, + std::error_code& ec) + { + encoder.begin_array(2,semantic_tag::none,ser_context(),ec); + if (ec) return; + encode_traits<T1,CharT>::encode(val.first, encoder, proto, ec); + if (ec) return; + encode_traits<T2,CharT>::encode(val.second, encoder, proto, ec); + if (ec) return; + encoder.end_array(ser_context(),ec); + } + }; + + // std::tuple + + namespace detail + { + template<size_t Pos, std::size_t Size, class Json, class Tuple> + struct json_serialize_tuple_helper + { + using char_type = typename Json::char_type; + using element_type = typename std::tuple_element<Size-Pos, Tuple>::type; + using next = json_serialize_tuple_helper<Pos-1, Size, Json, Tuple>; + + static void encode(const Tuple& tuple, + basic_json_visitor<char_type>& encoder, + const Json& proto, + std::error_code& ec) + { + encode_traits<element_type,char_type>::encode(std::get<Size-Pos>(tuple), encoder, proto, ec); + if (ec) return; + next::encode(tuple, encoder, proto, ec); + } + }; + + template<size_t Size, class Json, class Tuple> + struct json_serialize_tuple_helper<0, Size, Json, Tuple> + { + using char_type = typename Json::char_type; + static void encode(const Tuple&, + basic_json_visitor<char_type>&, + const Json&, + std::error_code&) + { + } + }; + } // namespace detail + + + template <class CharT, typename... E> + struct encode_traits<std::tuple<E...>, CharT> + { + using value_type = std::tuple<E...>; + static constexpr std::size_t size = sizeof...(E); + + template <class Json> + static void encode(const value_type& val, + basic_json_visitor<CharT>& encoder, + const Json& proto, + std::error_code& ec) + { + using helper = jsoncons::detail::json_serialize_tuple_helper<size, size, Json, std::tuple<E...>>; + encoder.begin_array(size,semantic_tag::none,ser_context(),ec); + if (ec) return; + helper::encode(val, encoder, proto, ec); + if (ec) return; + encoder.end_array(ser_context(),ec); + } + }; + + // vector like + template <class T, class CharT> + struct encode_traits<T,CharT, + typename std::enable_if<!is_json_type_traits_declared<T>::value && + type_traits::is_list_like<T>::value && + !type_traits::is_typed_array<T>::value + >::type> + { + using value_type = typename T::value_type; + + template <class Json> + static void encode(const T& val, + basic_json_visitor<CharT>& encoder, + const Json& proto, + std::error_code& ec) + { + encoder.begin_array(val.size(),semantic_tag::none,ser_context(),ec); + if (ec) return; + for (auto it = std::begin(val); it != std::end(val); ++it) + { + encode_traits<value_type,CharT>::encode(*it, encoder, proto, ec); + if (ec) return; + } + encoder.end_array(ser_context(), ec); + } + }; + + template <class T, class CharT> + struct encode_traits<T,CharT, + typename std::enable_if<!is_json_type_traits_declared<T>::value && + type_traits::is_list_like<T>::value && + type_traits::is_typed_array<T>::value + >::type> + { + using value_type = typename T::value_type; + + template <class Json> + static void encode(const T& val, + basic_json_visitor<CharT>& encoder, + const Json&, + std::error_code& ec) + { + encoder.typed_array(jsoncons::span<const value_type>(val), semantic_tag::none, ser_context(), ec); + } + }; + + // std::array + + template <class T, class CharT, std::size_t N> + struct encode_traits<std::array<T,N>,CharT> + { + using value_type = typename std::array<T,N>::value_type; + + template <class Json> + static void encode(const std::array<T, N>& val, + basic_json_visitor<CharT>& encoder, + const Json& proto, + std::error_code& ec) + { + encoder.begin_array(val.size(),semantic_tag::none,ser_context(),ec); + if (ec) return; + for (auto it = std::begin(val); it != std::end(val); ++it) + { + encode_traits<value_type,CharT>::encode(*it, encoder, proto, ec); + if (ec) return; + } + encoder.end_array(ser_context(),ec); + } + }; + + // map like + + template <class T, class CharT> + struct encode_traits<T,CharT, + typename std::enable_if<!is_json_type_traits_declared<T>::value && + type_traits::is_map_like<T>::value && + type_traits::is_constructible_from_const_pointer_and_size<typename T::key_type>::value + >::type> + { + using mapped_type = typename T::mapped_type; + using value_type = typename T::value_type; + using key_type = typename T::key_type; + + template <class Json> + static void encode(const T& val, + basic_json_visitor<CharT>& encoder, + const Json& proto, + std::error_code& ec) + { + encoder.begin_object(val.size(), semantic_tag::none, ser_context(), ec); + if (ec) return; + for (auto it = std::begin(val); it != std::end(val); ++it) + { + encoder.key(it->first); + encode_traits<mapped_type,CharT>::encode(it->second, encoder, proto, ec); + if (ec) return; + } + encoder.end_object(ser_context(), ec); + if (ec) return; + } + }; + + template <class T, class CharT> + struct encode_traits<T,CharT, + typename std::enable_if<!is_json_type_traits_declared<T>::value && + type_traits::is_map_like<T>::value && + std::is_integral<typename T::key_type>::value + >::type> + { + using mapped_type = typename T::mapped_type; + using value_type = typename T::value_type; + using key_type = typename T::key_type; + + template <class Json> + static void encode(const T& val, + basic_json_visitor<CharT>& encoder, + const Json& proto, + std::error_code& ec) + { + encoder.begin_object(val.size(), semantic_tag::none, ser_context(), ec); + if (ec) return; + for (auto it = std::begin(val); it != std::end(val); ++it) + { + std::basic_string<typename Json::char_type> s; + jsoncons::detail::from_integer(it->first,s); + encoder.key(s); + encode_traits<mapped_type,CharT>::encode(it->second, encoder, proto, ec); + if (ec) return; + } + encoder.end_object(ser_context(), ec); + if (ec) return; + } + }; + +} // jsoncons + +#endif + |