#pragma once #include #include #include #include "ki/pclass/Value.h" #include "ki/util/BitTypes.h" #include "ki/pclass/EnumType.h" #include #include #include namespace ki { namespace pclass { namespace detail { /** * Determines whether a type can be assigned to a * nlohmann::json object. */ template struct is_json_assignable : std::false_type {}; /** * All fundamental types can be assigned to a json object. */ template struct is_json_assignable< SrcT, typename std::enable_if::value>::type > : std::true_type {}; /** * std::string can be assigned to a json object. */ template <> struct is_json_assignable : std::true_type {}; /** * std::u16string can be assigned to a json object. */ template <> struct is_json_assignable : std::true_type {}; /** * value_caster specialization for the generic case of casting * any json-assignable value to a json object. */ template struct value_caster< SrcT, nlohmann::json, typename std::enable_if::value>::type > : value_caster_impl { nlohmann::json cast_value(const SrcT &value) const override { return value; } }; /** * value_caster specialization for casting bit integers (bi and bui) * to a json object. */ template struct value_caster< BitInteger, nlohmann::json > : value_caster_impl, nlohmann::json> { using type = typename std::conditional< Unsigned, typename bits::uint_type, typename bits::int_type >::type; nlohmann::json cast_value( const BitInteger &value) const override { return static_cast(value); } }; /** * value_caster specialization for casting enum to bit integer types * (bi and bui). */ template struct value_caster< SrcT, BitInteger, typename std::enable_if::value>::type > : value_caster_impl> { using underlying_type = typename std::underlying_type::type; BitInteger cast_value(const SrcT &value) const override { return static_cast(value); } }; /** * value_caster specialization for casting enums to a json object. */ template struct value_caster< SrcT, nlohmann::json, typename std::enable_if::value>::type > : value_caster_impl { using underlying_type = typename std::underlying_type::type; nlohmann::json cast_value(const SrcT &value) const override { return static_cast(value); } }; template struct string_cast_t { using type = T; }; /** * Writing a int8_t or uint8_t value to a stream will * write a ASCII character, rather than an integer, so * we cast to int16_t/uint16_t before writing. */ template <> struct string_cast_t { using type = int16_t; }; template <> struct string_cast_t { using type = uint16_t; }; template <> struct string_cast_t { using type = int16_t; }; /** * Enums should be written as 32-bit integers. */ template struct string_cast_t< T, typename std::enable_if::value>::type > { using type = enum_value_t; }; /** * A utility to enforce that a template parameter has a minimum * value. */ template struct minimum { static constexpr uint8_t value = N; }; template struct minimum< N, MinN, typename std::enable_if::type > { static constexpr uint8_t value = MinN; }; /** * BitIntegers should be written as the most suitable integer type * based on signedness and number of bits. */ template struct string_cast_t> { using type = typename BitInteger< minimum::value, Unsigned>::type; }; /** * Caster implementation for casting any type to string * via std::ostringstream. */ template struct value_caster< SrcT, std::string, typename std::enable_if::value>::type > : value_caster_impl { std::string cast_value(const SrcT &value) const override { std::ostringstream oss; auto casted_value = static_cast< typename string_cast_t::type>(value); oss << casted_value; return oss.str(); } }; /** * Caster implementation for casting floating point integers * to string via std::ostringstream. */ template struct value_caster< SrcT, std::string, typename std::enable_if::value>::type > : value_caster_impl { std::string cast_value(const SrcT &value) const override { std::ostringstream oss; oss << std::setprecision(std::numeric_limits::max_digits10) << value; return oss.str(); } }; /** * Caster implementation for casting std::string to std::u16string * via std::wstring_convert. */ template <> struct value_caster : value_caster_impl { std::u16string cast_value(const std::string &value) const override { #if _MSC_VER >= 1900 std::wstring_convert, int16_t> convert; auto converted_string = convert.from_bytes(value.data()); return std::u16string( reinterpret_cast(converted_string.data()), converted_string.size() ); #else std::wstring_convert, char16_t> convert; return convert.from_bytes(value.data()); #endif } }; /** * Caster implementation for casting std::u16string to std::string * via std::wstring_convert. */ template <> struct value_caster : value_caster_impl { std::string cast_value(const std::u16string &value) const override { #if _MSC_VER >= 1900 std::wstring_convert, int16_t> convert; auto *p = reinterpret_cast(value.data()); return convert.to_bytes(p, p + value.size()); #else std::wstring_convert, char16_t> convert; return convert.to_bytes(value); #endif } }; /** * Caster implementation for casting from string to any type * via std::istringstream. */ template struct value_caster< std::string, DestT, typename std::enable_if::value>::type > : value_caster_impl { DestT cast_value(const std::string &value) const override { typename string_cast_t::type casted_value; std::istringstream iss(value); iss >> casted_value; return static_cast(casted_value); } }; /** * Caster implementation for casting from json to any * primitive type. */ template struct value_caster : value_caster_impl { DestT cast_value(const nlohmann::json &value) const override { return value; } }; /** * Caster implementation for casting from json to * bit integers (bi and bui) */ template struct value_caster> : value_caster_impl> { using type = typename BitInteger::type; BitInteger cast_value(const nlohmann::json &value) const override { return BitInteger( static_cast(value) ); } }; /** * Caster implementation for casting from json to a * std::string. */ template <> struct value_caster : value_caster_impl { std::string cast_value(const nlohmann::json &value) const override { return value; } }; /** * A utility to call ValueCaster::declare with * bi and bui as the destination type. * * N is automatically decremented until it reaches 0. */ template struct bit_integer_declarer { static void declare() { bit_integer_declarer::declare(); ValueCaster::declare>(); ValueCaster::declare>(); } }; /** * Specialization for bit_integer_declarer. * Stop decrementing N when it reaches 0. */ template struct bit_integer_declarer { static void declare() {} }; /** * Utility class used by TypeSystem to declare casters for each * primitive type. */ template struct caster_declarer { static void declare() { // These casters are required for JsonSerializer and // XmlSerializer to work. ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); } }; /** * caster_declarer specialization for all integral types. * Integers can cast to other integer types, as well as floating point * integers, std::string and nlohmann::json. */ template struct caster_declarer< T, typename std::enable_if::value>::type > { static void declare() { ValueCaster::declare(); bit_integer_declarer::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare>(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare>(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); } }; /** * caster_declarer specialization for all floating point types. * Floating point integers can cast to all integer types, as well as * std::string and nlohmann::json. */ template struct caster_declarer< T, typename std::enable_if::value>::type > { static void declare() { ValueCaster::declare(); bit_integer_declarer::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare>(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare>(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); } }; /** * caster_declarer specialization for enum types. * Enums can be cast to any integer type, as well as std::string, * and nlohmann::json. */ template struct caster_declarer< T, typename std::enable_if::value>::type > { static void declare() { ValueCaster::declare(); bit_integer_declarer::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare>(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare>(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); } }; /** * caster_declarer specialization for string. * Strings can be cast to UTF-16 strings, and json objects. */ template <> struct caster_declarer { static void declare() { ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); } }; /** * caster_declarer specialization for UTF-16 strings. * UTF-16 strings can be cast to strings, and json objects. */ template <> struct caster_declarer { static void declare() { ValueCaster::declare(); ValueCaster::declare(); ValueCaster::declare(); } }; } } }