Просмотр исходного кода

Added `RawJson()` to insert pregenerated JSON portions (issue #259)

Benoit Blanchon 9 лет назад
Родитель
Сommit
a6724bd03f

+ 1 - 0
CHANGELOG.md

@@ -7,6 +7,7 @@ HEAD
 * Added `JsonVariant::as<char*>()` as a synonym for `JsonVariant::as<const char*>()` (issue #257)
 * Added example `JsonHttpClient` (issue #256)
 * Added `JsonArray::copyTo()` and `JsonArray::copyFrom()` (issue #254)
+* Added `RawJson()` to insert pregenerated JSON portions (issue #259)
 
 v5.1.1
 ------

+ 1 - 0
include/ArduinoJson/JsonObject.hpp

@@ -71,6 +71,7 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
   // bool set(TKey key, float value);
   // bool set(TKey key, double value);
   // bool set(TKey key, const char* value);
+  // bool set(TKey key, RawJson value);
   template <typename T>
   FORCE_INLINE bool set(
       JsonObjectKey key, T value,

+ 80 - 3
include/ArduinoJson/JsonVariant.hpp

@@ -13,8 +13,8 @@
 #include "Internals/JsonPrintable.hpp"
 #include "Internals/JsonVariantContent.hpp"
 #include "Internals/JsonVariantType.hpp"
-#include "Internals/Unparsed.hpp"
 #include "JsonVariantBase.hpp"
+#include "RawJson.hpp"
 #include "TypeTraits/EnableIf.hpp"
 #include "TypeTraits/IsFloatingPoint.hpp"
 #include "TypeTraits/IsIntegral.hpp"
@@ -80,7 +80,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
   FORCE_INLINE JsonVariant(const char *value);
 
   // Create a JsonVariant containing an unparsed string
-  FORCE_INLINE JsonVariant(Internals::Unparsed value);
+  FORCE_INLINE JsonVariant(RawJson value);
 
   // Create a JsonVariant containing a reference to an array.
   FORCE_INLINE JsonVariant(JsonArray &array);
@@ -89,6 +89,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
   FORCE_INLINE JsonVariant(JsonObject &object);
 
   // Get the variant as the specified type.
+  //
   // short as<short>() const;
   // int as<int>() const;
   // long as<long>() const;
@@ -97,6 +98,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
   as() const {
     return static_cast<T>(asInteger());
   }
+  //
   // double as<double>() const;
   // float as<float>() const;
   template <typename T>
@@ -105,6 +107,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
   as() const {
     return static_cast<T>(asFloat());
   }
+  //
   // const String as<String>() const;
   template <typename T>
   const typename TypeTraits::EnableIf<TypeTraits::IsSame<T, String>::value,
@@ -112,6 +115,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
   as() const {
     return toString();
   }
+  //
   // const char* as<const char*>() const;
   // const char* as<char*>() const;
   template <typename T>
@@ -121,6 +125,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
   as() const {
     return asString();
   }
+  //
   // const bool as<bool>() const
   template <typename T>
   const typename TypeTraits::EnableIf<TypeTraits::IsSame<T, bool>::value,
@@ -128,6 +133,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
   as() const {
     return asInteger() != 0;
   }
+  //
   // JsonArray& as<JsonArray> const;
   // JsonArray& as<JsonArray&> const;
   // JsonArray& as<const JsonArray&> const;
@@ -141,6 +147,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
   as() const {
     return asArray();
   }
+  //
   // JsonObject& as<JsonObject> const;
   // JsonObject& as<JsonObject&> const;
   // JsonObject& as<const JsonObject&> const;
@@ -157,8 +164,71 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
 
   // Tells weither the variant has the specified type.
   // Returns true if the variant has type type T, false otherwise.
+  //
+  // short as<short>() const;
+  // int as<int>() const;
+  // long as<long>() const;
+  template <typename T>
+  const typename TypeTraits::EnableIf<TypeTraits::IsIntegral<T>::value,
+                                      bool>::type
+  is() const {
+    return isInteger();
+  }
+  //
+  // double is<double>() const;
+  // float is<float>() const;
+  template <typename T>
+  const typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value,
+                                      bool>::type
+  is() const {
+    return isFloat();
+  }
+  //
+  // const bool is<bool>() const
   template <typename T>
-  bool is() const;
+  const typename TypeTraits::EnableIf<TypeTraits::IsSame<T, bool>::value,
+                                      bool>::type
+  is() const {
+    return isBoolean();
+  }
+  //
+  // bool is<const char*>() const;
+  // bool is<char*>() const;
+  template <typename T>
+  typename TypeTraits::EnableIf<TypeTraits::IsSame<T, const char *>::value ||
+                                    TypeTraits::IsSame<T, char *>::value,
+                                bool>::type
+  is() const {
+    return isString();
+  }
+  //
+  // bool is<JsonArray> const;
+  // bool is<JsonArray&> const;
+  // bool is<const JsonArray&> const;
+  template <typename T>
+  typename TypeTraits::EnableIf<
+      TypeTraits::IsSame<
+          typename TypeTraits::RemoveConst<
+              typename TypeTraits::RemoveReference<T>::type>::type,
+          JsonArray>::value,
+      bool>::type
+  is() const {
+    return isArray();
+  }
+  //
+  // JsonObject& as<JsonObject> const;
+  // JsonObject& as<JsonObject&> const;
+  // JsonObject& as<const JsonObject&> const;
+  template <typename T>
+  typename TypeTraits::EnableIf<
+      TypeTraits::IsSame<
+          typename TypeTraits::RemoveConst<
+              typename TypeTraits::RemoveReference<T>::type>::type,
+          JsonObject>::value,
+      bool>::type
+  is() const {
+    return isObject();
+  }
 
   // Serialize the variant to a JsonWriter
   void writeTo(Internals::JsonWriter &writer) const;
@@ -175,6 +245,12 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
   String toString() const;
   Internals::JsonFloat asFloat() const;
   Internals::JsonInteger asInteger() const;
+  bool isBoolean() const;
+  bool isFloat() const;
+  bool isInteger() const;
+  bool isArray() const { return _type == Internals::JSON_ARRAY; }
+  bool isObject() const { return _type == Internals::JSON_OBJECT; }
+  bool isString() const { return _type == Internals::JSON_STRING; }
 
   // The current type of the variant
   Internals::JsonVariantType _type;
@@ -199,6 +275,7 @@ struct JsonVariant::IsConstructibleFrom {
       TypeTraits::IsSame<T, bool>::value ||
       TypeTraits::IsSame<T, char *>::value ||
       TypeTraits::IsSame<T, const char *>::value ||
+      TypeTraits::IsSame<T, RawJson>::value ||
       TypeTraits::IsSame<T, JsonArray &>::value ||
       TypeTraits::IsSame<T, const JsonArray &>::value ||
       TypeTraits::IsSame<T, JsonArraySubscript &>::value ||

+ 1 - 80
include/ArduinoJson/JsonVariant.ipp

@@ -26,7 +26,7 @@ inline JsonVariant::JsonVariant(const char *value) {
   _content.asString = value;
 }
 
-inline JsonVariant::JsonVariant(Internals::Unparsed value) {
+inline JsonVariant::JsonVariant(RawJson value) {
   _type = Internals::JSON_UNPARSED;
   _content.asString = value;
 }
@@ -46,85 +46,6 @@ inline T JsonVariant::invalid() {
   return T();
 }
 
-template <typename T>
-inline bool JsonVariant::is() const {
-  return false;
-}
-
-template <>  // in .cpp
-bool JsonVariant::is<signed long>() const;
-
-template <>  // in .cpp
-bool JsonVariant::is<double>() const;
-
-template <>  // int .cpp
-bool JsonVariant::is<bool>() const;
-
-template <>
-inline bool JsonVariant::is<char const *>() const {
-  return _type == Internals::JSON_STRING;
-}
-
-template <>
-inline bool JsonVariant::is<float>() const {
-  return is<double>();
-}
-
-template <>
-inline bool JsonVariant::is<JsonArray &>() const {
-  return _type == Internals::JSON_ARRAY;
-}
-
-template <>
-inline bool JsonVariant::is<JsonArray const &>() const {
-  return _type == Internals::JSON_ARRAY;
-}
-
-template <>
-inline bool JsonVariant::is<JsonObject &>() const {
-  return _type == Internals::JSON_OBJECT;
-}
-
-template <>
-inline bool JsonVariant::is<JsonObject const &>() const {
-  return _type == Internals::JSON_OBJECT;
-}
-
-template <>
-inline bool JsonVariant::is<signed char>() const {
-  return is<signed long>();
-}
-
-template <>
-inline bool JsonVariant::is<signed int>() const {
-  return is<signed long>();
-}
-
-template <>
-inline bool JsonVariant::is<signed short>() const {
-  return is<signed long>();
-}
-
-template <>
-inline bool JsonVariant::is<unsigned char>() const {
-  return is<signed long>();
-}
-
-template <>
-inline bool JsonVariant::is<unsigned int>() const {
-  return is<signed long>();
-}
-
-template <>
-inline bool JsonVariant::is<unsigned long>() const {
-  return is<signed long>();
-}
-
-template <>
-inline bool JsonVariant::is<unsigned short>() const {
-  return is<signed long>();
-}
-
 inline Internals::JsonInteger JsonVariant::asInteger() const {
   if (_type == Internals::JSON_INTEGER || _type == Internals::JSON_BOOLEAN)
     return _content.asInteger;

+ 4 - 4
include/ArduinoJson/Internals/Unparsed.hpp → include/ArduinoJson/RawJson.hpp

@@ -8,14 +8,14 @@
 #pragma once
 
 namespace ArduinoJson {
-namespace Internals {
-class Unparsed {
+
+// A special type of data that can be used to insert pregenerated JSON portions.
+class RawJson {
  public:
-  explicit Unparsed(const char* str) : _str(str) {}
+  explicit RawJson(const char* str) : _str(str) {}
   operator const char*() const { return _str; }
 
  private:
   const char* _str;
 };
 }
-}

+ 1 - 1
src/Internals/JsonParser.cpp

@@ -195,7 +195,7 @@ bool JsonParser::parseStringTo(JsonVariant *destination) {
   if (hasQuotes) {
     *destination = value;
   } else {
-    *destination = Unparsed(value);
+    *destination = RawJson(value);
   }
   return true;
 }

+ 3 - 6
src/JsonVariant.cpp

@@ -47,8 +47,7 @@ String JsonVariant::toString() const {
   return s;
 }
 
-template <>
-bool JsonVariant::is<bool>() const {
+bool JsonVariant::isBoolean() const {
   if (_type == JSON_BOOLEAN) return true;
 
   if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
@@ -57,8 +56,7 @@ bool JsonVariant::is<bool>() const {
          !strcmp(_content.asString, "false");
 }
 
-template <>
-bool JsonVariant::is<signed long>() const {
+bool JsonVariant::isInteger() const {
   if (_type == JSON_INTEGER) return true;
 
   if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
@@ -70,8 +68,7 @@ bool JsonVariant::is<signed long>() const {
   return *end == '\0' && errno == 0;
 }
 
-template <>
-bool JsonVariant::is<double>() const {
+bool JsonVariant::isFloat() const {
   if (_type >= JSON_FLOAT_0_DECIMALS) return true;
 
   if (_type != JSON_UNPARSED || _content.asString == NULL) return false;

+ 1 - 3
test/Issue90.cpp

@@ -14,13 +14,11 @@
 
 #define SUITE Issue90
 
-using namespace ArduinoJson::Internals;
-
 static const char* superLong =
     "12345678901234567890123456789012345678901234567890123456789012345678901234"
     "5678901234567890123456789012345678901234567890123456789012345678901234567";
 
-static const JsonVariant variant = Unparsed(superLong);
+static const JsonVariant variant = RawJson(superLong);
 
 TEST(SUITE, IsNotALong) { ASSERT_FALSE(variant.is<long>()); }
 

+ 6 - 0
test/JsonArray_PrintTo_Tests.cpp

@@ -96,6 +96,12 @@ TEST_F(JsonArray_PrintTo_Tests, TwoIntegers) {
   outputMustBe("[1,2]");
 }
 
+TEST_F(JsonArray_PrintTo_Tests, RawJson) {
+  array.add(RawJson("{\"key\":\"value\"}"));
+
+  outputMustBe("[{\"key\":\"value\"}]");
+}
+
 TEST_F(JsonArray_PrintTo_Tests, OneIntegerOverCapacity) {
   array.add(1);
   array.add(2);

+ 6 - 2
test/JsonObject_PrintTo_Tests.cpp

@@ -8,8 +8,6 @@
 #include <ArduinoJson.h>
 #include <gtest/gtest.h>
 
-using namespace ArduinoJson::Internals;
-
 class JsonObject_PrintTo_Tests : public testing::Test {
  public:
   JsonObject_PrintTo_Tests() : _object(_jsonBuffer.createObject()) {}
@@ -75,6 +73,12 @@ TEST_F(JsonObject_PrintTo_Tests, TwoIntegers) {
   outputMustBe("{\"a\":1,\"b\":2}");
 }
 
+TEST_F(JsonObject_PrintTo_Tests, RawJson) {
+  _object["a"] = RawJson("[1,2]");
+  _object.set("b", RawJson("[4,5]"));
+  outputMustBe("{\"a\":[1,2],\"b\":[4,5]}");
+}
+
 TEST_F(JsonObject_PrintTo_Tests, TwoDoublesFourDigits) {
   _object["a"] = double_with_n_digits(3.14159265358979323846, 4);
   _object.set("b", 2.71828182845904523536, 4);

+ 29 - 33
test/JsonVariant_Is_Tests.cpp

@@ -10,8 +10,6 @@
 
 #define SUITE JsonVariant_Is_Tests
 
-using namespace ArduinoJson::Internals;
-
 template <typename TTo, typename TFrom>
 void assertIsNot(TFrom value) {
   JsonVariant variant = value;
@@ -76,37 +74,35 @@ TEST(SUITE, StringIsInt) { assertIsNot<int>("42"); }
 TEST(SUITE, StringIsLong) { assertIsNot<long>("42"); }
 TEST(SUITE, StringIsString) { assertIs<const char*>("42"); }
 
-TEST(SUITE, UnparsedTrueIsArra) { assertIsNot<JsonArray&>(Unparsed("true")); }
-TEST(SUITE, UnparsedTrueIsBool) { assertIs<bool>(Unparsed("true")); }
-TEST(SUITE, UnparsedTrueIsDouble) { assertIsNot<double>(Unparsed("true")); }
-TEST(SUITE, UnparsedTrueIsFloat) { assertIsNot<float>(Unparsed("true")); }
-TEST(SUITE, UnparsedTrueIsInt) { assertIsNot<int>(Unparsed("true")); }
-TEST(SUITE, UnparsedTrueIsLong) { assertIsNot<long>(Unparsed("true")); }
-TEST(SUITE, UnparsedTrueIsString) {
-  assertIsNot<const char*>(Unparsed("true"));
-}
-
-TEST(SUITE, UnparsedFalseIsArra) { assertIsNot<JsonArray&>(Unparsed("false")); }
-TEST(SUITE, UnparsedFalseIsBool) { assertIs<bool>(Unparsed("false")); }
-TEST(SUITE, UnparsedFalseIsDouble) { assertIsNot<double>(Unparsed("false")); }
-TEST(SUITE, UnparsedFalseIsFloat) { assertIsNot<float>(Unparsed("false")); }
-TEST(SUITE, UnparsedFalseIsInt) { assertIsNot<int>(Unparsed("false")); }
-TEST(SUITE, UnparsedFalseIsLong) { assertIsNot<long>(Unparsed("false")); }
+TEST(SUITE, UnparsedTrueIsArra) { assertIsNot<JsonArray&>(RawJson("true")); }
+TEST(SUITE, UnparsedTrueIsBool) { assertIs<bool>(RawJson("true")); }
+TEST(SUITE, UnparsedTrueIsDouble) { assertIsNot<double>(RawJson("true")); }
+TEST(SUITE, UnparsedTrueIsFloat) { assertIsNot<float>(RawJson("true")); }
+TEST(SUITE, UnparsedTrueIsInt) { assertIsNot<int>(RawJson("true")); }
+TEST(SUITE, UnparsedTrueIsLong) { assertIsNot<long>(RawJson("true")); }
+TEST(SUITE, UnparsedTrueIsString) { assertIsNot<const char*>(RawJson("true")); }
+
+TEST(SUITE, UnparsedFalseIsArra) { assertIsNot<JsonArray&>(RawJson("false")); }
+TEST(SUITE, UnparsedFalseIsBool) { assertIs<bool>(RawJson("false")); }
+TEST(SUITE, UnparsedFalseIsDouble) { assertIsNot<double>(RawJson("false")); }
+TEST(SUITE, UnparsedFalseIsFloat) { assertIsNot<float>(RawJson("false")); }
+TEST(SUITE, UnparsedFalseIsInt) { assertIsNot<int>(RawJson("false")); }
+TEST(SUITE, UnparsedFalseIsLong) { assertIsNot<long>(RawJson("false")); }
 TEST(SUITE, UnparsedFalseIsString) {
-  assertIsNot<const char*>(Unparsed("false"));
+  assertIsNot<const char*>(RawJson("false"));
 }
 
-TEST(SUITE, UnparsedIntIsArra) { assertIsNot<JsonArray&>(Unparsed("42")); }
-TEST(SUITE, UnparsedIntIsBool) { assertIsNot<bool>(Unparsed("42")); }
-TEST(SUITE, UnparsedIntIsDouble) { assertIsNot<double>(Unparsed("42")); }
-TEST(SUITE, UnparsedIntIsFloat) { assertIsNot<float>(Unparsed("42")); }
-TEST(SUITE, UnparsedIntIsInt) { assertIs<int>(Unparsed("42")); }
-TEST(SUITE, UnparsedIntIsLong) { assertIs<long>(Unparsed("42")); }
-TEST(SUITE, UnparsedIntIsString) { assertIsNot<const char*>(Unparsed("42")); }
-
-TEST(SUITE, UnparsedFloatIsBool) { assertIsNot<bool>(Unparsed("4.2e-10")); }
-TEST(SUITE, UnparsedFloatIsDouble) { assertIs<double>(Unparsed("4.2e-10")); }
-TEST(SUITE, UnparsedFloatIsFloat) { assertIs<float>(Unparsed("4.2e-10")); }
-TEST(SUITE, UnparsedFloatIsInt) { assertIsNot<int>(Unparsed("4.2e-10")); }
-TEST(SUITE, UnparsedFloatIsLong) { assertIsNot<long>(Unparsed("4.2e-10")); }
-TEST(SUITE, UnparsedFloatIsStr) { assertIsNot<const char*>(Unparsed("4.2")); }
+TEST(SUITE, UnparsedIntIsArra) { assertIsNot<JsonArray&>(RawJson("42")); }
+TEST(SUITE, UnparsedIntIsBool) { assertIsNot<bool>(RawJson("42")); }
+TEST(SUITE, UnparsedIntIsDouble) { assertIsNot<double>(RawJson("42")); }
+TEST(SUITE, UnparsedIntIsFloat) { assertIsNot<float>(RawJson("42")); }
+TEST(SUITE, UnparsedIntIsInt) { assertIs<int>(RawJson("42")); }
+TEST(SUITE, UnparsedIntIsLong) { assertIs<long>(RawJson("42")); }
+TEST(SUITE, UnparsedIntIsString) { assertIsNot<const char*>(RawJson("42")); }
+
+TEST(SUITE, UnparsedFloatIsBool) { assertIsNot<bool>(RawJson("4.2e-10")); }
+TEST(SUITE, UnparsedFloatIsDouble) { assertIs<double>(RawJson("4.2e-10")); }
+TEST(SUITE, UnparsedFloatIsFloat) { assertIs<float>(RawJson("4.2e-10")); }
+TEST(SUITE, UnparsedFloatIsInt) { assertIsNot<int>(RawJson("4.2e-10")); }
+TEST(SUITE, UnparsedFloatIsLong) { assertIsNot<long>(RawJson("4.2e-10")); }
+TEST(SUITE, UnparsedFloatIsStr) { assertIsNot<const char*>(RawJson("4.2")); }