// 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 "Polyfills/type_traits.hpp" #include "RawJson.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 { 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::enable_if< Internals::is_floating_point::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::enable_if::value && Internals::is_signed::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) + 1; } } // JsonVariant(unsigned short) // JsonVariant(unsigned int) // JsonVariant(unsigned long) template JsonVariant( T value, typename Internals::enable_if::value && Internals::is_unsigned::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::enable_if::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; } JsonVariant(JsonArray array); JsonVariant(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::enable_if::value, T>::type as() const { return variantAsInteger(); } // bool as() const template const typename Internals::enable_if::value, T>::type as() const { return variantAsInteger() != 0; } // // double as() const; // float as() const; template const typename Internals::enable_if::value, T>::type as() const { return variantAsFloat(); } // // const char* as() const; // const char* as() const; template typename Internals::enable_if::value || Internals::is_same::value, const char *>::type as() const { return variantAsString(); } // // std::string as() const; // String as() const; template typename Internals::enable_if::has_append, T>::type as() const { const char *cstr = variantAsString(); if (cstr) return T(cstr); T s; serializeJson(*this, s); return s; } // // JsonArray as() const; // const JsonArray as() const; template typename Internals::enable_if< Internals::is_same::type, JsonArray>::value, JsonArray>::type as() const; // // JsonObject as() const; // const JsonObject as() const; template typename Internals::enable_if< Internals::is_same::type, JsonObject>::value, T>::type as() const; // // JsonVariant as const; template typename Internals::enable_if::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::enable_if::value, bool>::type is() const { return variantIsInteger(); } // // bool is() const; // bool is() const; template typename Internals::enable_if::value, bool>::type is() const { return variantIsFloat(); } // // bool is() const template typename Internals::enable_if::value, bool>::type is() const { return variantIsBoolean(); } // // bool is() const; // bool is() const; template typename Internals::enable_if::value || Internals::is_same::value, bool>::type is() const { return variantIsString(); } // // bool is const; // bool is const; template typename Internals::enable_if< Internals::is_same::type, JsonArray>::value, bool>::type is() const { return variantIsArray(); } // // bool is const; // bool is const; template typename Internals::enable_if< Internals::is_same::type, JsonObject>::value, bool>::type is() const { return variantIsObject(); } // Returns true if the variant has a value bool isNull() const { return _type == Internals::JSON_UNDEFINED; } template void visit(Visitor &visitor) const { using namespace Internals; switch (_type) { case JSON_FLOAT: return visitor.acceptFloat(_content.asFloat); case JSON_ARRAY: return visitor.acceptArray(_content.asArray); case JSON_OBJECT: return visitor.acceptObject(_content.asObject); case JSON_STRING: return visitor.acceptString(_content.asString); case JSON_UNPARSED: return visitor.acceptRawJson(_content.asString); case JSON_NEGATIVE_INTEGER: return visitor.acceptNegativeInteger(_content.asInteger); case JSON_POSITIVE_INTEGER: return visitor.acceptPositiveInteger(_content.asInteger); case JSON_BOOLEAN: return visitor.acceptBoolean(_content.asInteger != 0); default: // JSON_UNDEFINED return visitor.acceptNull(); } } 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; }; } // namespace ArduinoJson