// ArduinoJson - arduinojson.org // Copyright Benoit Blanchon 2014-2018 // MIT License #pragma once #include #include // for uint8_t #include "Data/JsonVariantContent.hpp" #include "Data/JsonVariantDefault.hpp" #include "Data/JsonVariantType.hpp" #include "JsonVariantBase.hpp" #include "RawJson.hpp" #include "Serialization/JsonPrintable.hpp" #include "TypeTraits/EnableIf.hpp" #include "TypeTraits/IsChar.hpp" #include "TypeTraits/IsFloatingPoint.hpp" #include "TypeTraits/IsIntegral.hpp" #include "TypeTraits/IsSame.hpp" #include "TypeTraits/IsSignedIntegral.hpp" #include "TypeTraits/IsUnsignedIntegral.hpp" #include "TypeTraits/RemoveConst.hpp" #include "TypeTraits/RemoveReference.hpp" namespace ArduinoJson { // Forward declarations. class JsonArray; class JsonObject; // A variant that can be a any value serializable to a JSON value. // // It can be set to: // - a boolean // - a char, short, int or a long (signed or unsigned) // - a string (const char*) // - a reference to a JsonArray or JsonObject class JsonVariant : public Internals::JsonVariantBase { template friend class Internals::JsonSerializer; public: // Creates an uninitialized JsonVariant JsonVariant() : _type(Internals::JSON_UNDEFINED) {} // Create a JsonVariant containing a boolean value. // It will be serialized as "true" or "false" in JSON. JsonVariant(bool value) { using namespace Internals; _type = JSON_BOOLEAN; _content.asInteger = static_cast(value); } // Create a JsonVariant containing a floating point value. // JsonVariant(double value); // JsonVariant(float value); template JsonVariant(T value, typename Internals::EnableIf< Internals::IsFloatingPoint::value>::type * = 0) { using namespace Internals; _type = JSON_FLOAT; _content.asFloat = static_cast(value); } template DEPRECATED("Second argument is not supported anymore") JsonVariant(T value, uint8_t, typename Internals::EnableIf< Internals::IsFloatingPoint::value>::type * = 0) { using namespace Internals; _type = JSON_FLOAT; _content.asFloat = static_cast(value); } // Create a JsonVariant containing an integer value. // JsonVariant(char) // JsonVariant(signed short) // JsonVariant(signed int) // JsonVariant(signed long) // JsonVariant(signed char) template JsonVariant( T value, typename Internals::EnableIf::value || Internals::IsSame::value>::type * = 0) { using namespace Internals; if (value >= 0) { _type = JSON_POSITIVE_INTEGER; _content.asInteger = static_cast(value); } else { _type = JSON_NEGATIVE_INTEGER; _content.asInteger = static_cast(-value); } } // JsonVariant(unsigned short) // JsonVariant(unsigned int) // JsonVariant(unsigned long) template JsonVariant(T value, typename Internals::EnableIf< Internals::IsUnsignedIntegral::value>::type * = 0) { using namespace Internals; _type = JSON_POSITIVE_INTEGER; _content.asInteger = static_cast(value); } // Create a JsonVariant containing a string. // JsonVariant(const char*); // JsonVariant(const signed char*); // JsonVariant(const unsigned char*); template JsonVariant( const TChar *value, typename Internals::EnableIf::value>::type * = 0) { _type = Internals::JSON_STRING; _content.asString = reinterpret_cast(value); } // Create a JsonVariant containing an unparsed string JsonVariant(Internals::RawJsonString value) { _type = Internals::JSON_UNPARSED; _content.asString = value; } // Create a JsonVariant containing a reference to an array. // CAUTION: we are lying about constness, because the array can be modified if // the variant is converted back to a JsonArray& JsonVariant(const JsonArray &array); // Create a JsonVariant containing a reference to an object. // CAUTION: we are lying about constness, because the object can be modified // if the variant is converted back to a JsonObject& JsonVariant(const JsonObject &object); // Get the variant as the specified type. // // char as() const; // signed char as() const; // signed short as() const; // signed int as() const; // signed long as() const; // unsigned char as() const; // unsigned short as() const; // unsigned int as() const; // unsigned long as() const; template const typename Internals::EnableIf::value, T>::type as() const { return variantAsInteger(); } // bool as() const template const typename Internals::EnableIf::value, T>::type as() const { return variantAsInteger() != 0; } // // double as() const; // float as() const; template const typename Internals::EnableIf::value, T>::type as() const { return variantAsFloat(); } // // const char* as() const; // const char* as() const; template typename Internals::EnableIf::value || Internals::IsSame::value, const char *>::type as() const { return variantAsString(); } // // std::string as() const; // String as() const; template typename Internals::EnableIf::has_append, T>::type as() const { const char *cstr = variantAsString(); if (cstr) return T(cstr); T s; printTo(s); return s; } // // JsonArray& as const; // JsonArray& as const; template typename Internals::EnableIf< Internals::IsSame::type, JsonArray>::value, JsonArray &>::type as() const { return variantAsArray(); } // // const JsonArray& as const; template typename Internals::EnableIf< Internals::IsSame::type, const JsonArray>::value, const JsonArray &>::type as() const { return variantAsArray(); } // // JsonObject& as const; // JsonObject& as const; template typename Internals::EnableIf< Internals::IsSame::type, JsonObject>::value, JsonObject &>::type as() const { return variantAsObject(); } // // JsonObject& as const; // JsonObject& as const; template typename Internals::EnableIf< Internals::IsSame::type, const JsonObject>::value, const JsonObject &>::type as() const { return variantAsObject(); } // // JsonVariant as const; template typename Internals::EnableIf::value, T>::type as() const { return *this; } // Tells weither the variant has the specified type. // Returns true if the variant has type type T, false otherwise. // // bool is() const; // bool is() const; // bool is() const; // bool is() const; // bool is() const; // bool is() const; // bool is() const; // bool is() const; // bool is() const; template typename Internals::EnableIf::value, bool>::type is() const { return variantIsInteger(); } // // bool is() const; // bool is() const; template typename Internals::EnableIf::value, bool>::type is() const { return variantIsFloat(); } // // bool is() const template typename Internals::EnableIf::value, bool>::type is() const { return variantIsBoolean(); } // // bool is() const; // bool is() const; template typename Internals::EnableIf::value || Internals::IsSame::value, bool>::type is() const { return variantIsString(); } // // bool is const; // bool is const; // bool is const; template typename Internals::EnableIf< Internals::IsSame::type>::type, JsonArray>::value, bool>::type is() const { return variantIsArray(); } // // bool is const; // bool is const; // bool is const; template typename Internals::EnableIf< Internals::IsSame::type>::type, JsonObject>::value, bool>::type is() const { return variantIsObject(); } // Returns true if the variant has a value bool success() const { return _type != Internals::JSON_UNDEFINED; } private: JsonArray &variantAsArray() const; JsonObject &variantAsObject() const; const char *variantAsString() const; template T variantAsFloat() const; template T variantAsInteger() const; bool variantIsBoolean() const; bool variantIsFloat() const; bool variantIsInteger() const; bool variantIsArray() const { return _type == Internals::JSON_ARRAY; } bool variantIsObject() const { return _type == Internals::JSON_OBJECT; } bool variantIsString() const { return _type == Internals::JSON_STRING || (_type == Internals::JSON_UNPARSED && _content.asString && !strcmp("null", _content.asString)); } // The current type of the variant Internals::JsonVariantType _type; // The various alternatives for the value of the variant. Internals::JsonVariantContent _content; }; DEPRECATED("Decimal places are ignored, use the float value instead") inline JsonVariant float_with_n_digits(float value, uint8_t) { return JsonVariant(value); } DEPRECATED("Decimal places are ignored, use the double value instead") inline JsonVariant double_with_n_digits(double value, uint8_t) { return JsonVariant(value); } }