mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 08:42:39 +01:00 
			
		
		
		
	Added support for Printable (closes #1444)
				
					
				
			This commit is contained in:
		| @@ -5,6 +5,7 @@ HEAD | ||||
| ---- | ||||
|  | ||||
| * Added support for custom converters (issue #687) | ||||
| * Added support for `Printable` (issue #1444) | ||||
| * Removed support for `char` values, see below (issue #1498) | ||||
| * `deserializeJson()` leaves `\uXXXX` unchanged instead of returning `NotSupported` | ||||
| * `deserializeMsgPack()` inserts `null` instead of returning `NotSupported` | ||||
|   | ||||
| @@ -4,5 +4,6 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "api/Print.h" | ||||
| #include "api/Stream.h" | ||||
| #include "api/String.h" | ||||
|   | ||||
							
								
								
									
										33
									
								
								extras/tests/Helpers/api/Print.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								extras/tests/Helpers/api/Print.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2021 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <stdint.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| class Print { | ||||
|  public: | ||||
|   virtual ~Print() {} | ||||
|  | ||||
|   virtual size_t write(uint8_t) = 0; | ||||
|   virtual size_t write(const uint8_t *buffer, size_t size) = 0; | ||||
|  | ||||
|   size_t write(const char *str) { | ||||
|     if (!str) | ||||
|       return 0; | ||||
|     return write(reinterpret_cast<const uint8_t *>(str), strlen(str)); | ||||
|   } | ||||
|  | ||||
|   size_t write(const char *buffer, size_t size) { | ||||
|     return write(reinterpret_cast<const uint8_t *>(buffer), size); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class Printable { | ||||
|  public: | ||||
|   virtual ~Printable() {} | ||||
|   virtual size_t printTo(Print &p) const = 0; | ||||
| }; | ||||
| @@ -7,6 +7,7 @@ add_executable(MiscTests | ||||
| 	conflicts.cpp | ||||
| 	FloatParts.cpp | ||||
| 	JsonString.cpp | ||||
| 	printable.cpp | ||||
| 	Readers.cpp | ||||
| 	StringAdapters.cpp | ||||
| 	StringWriter.cpp | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| // Copyright Benoit Blanchon 2014-2021 | ||||
| // MIT License | ||||
|  | ||||
| #define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1 | ||||
| #include <Arduino.h> | ||||
| #include <ArduinoJson.hpp> | ||||
| #include <catch.hpp> | ||||
|  | ||||
|   | ||||
							
								
								
									
										112
									
								
								extras/tests/Misc/printable.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								extras/tests/Misc/printable.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2021 | ||||
| // MIT License | ||||
|  | ||||
| #include <Arduino.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| #define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1 | ||||
| #include <ArduinoJson.h> | ||||
|  | ||||
| struct PrintOneCharacterAtATime { | ||||
|   static size_t printStringTo(const std::string& s, Print& p) { | ||||
|     size_t result = 0; | ||||
|     for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) { | ||||
|       size_t n = p.write(uint8_t(*it)); | ||||
|       if (n == 0) | ||||
|         break; | ||||
|       result += n; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| struct PrintAllAtOnce { | ||||
|   static size_t printStringTo(const std::string& s, Print& p) { | ||||
|     return p.write(s.data(), s.size()); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename PrintPolicy> | ||||
| struct PrintableString : public Printable { | ||||
|   PrintableString(const char* s) : _str(s), _total(0) {} | ||||
|  | ||||
|   virtual size_t printTo(Print& p) const { | ||||
|     size_t result = PrintPolicy::printStringTo(_str, p); | ||||
|     _total += result; | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   size_t totalBytesWritten() const { | ||||
|     return _total; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   std::string _str; | ||||
|   mutable size_t _total; | ||||
| }; | ||||
|  | ||||
| TEST_CASE("Printable") { | ||||
|   SECTION("Enough space for the whole string") { | ||||
|     StaticJsonDocument<64> doc; | ||||
|     doc.set(666); | ||||
|  | ||||
|     SECTION("Via Print::write(char)") { | ||||
|       PrintableString<PrintOneCharacterAtATime> printable = "Hello World!"; | ||||
|       CHECK(doc.set(printable) == true); | ||||
|       CHECK(doc.as<std::string>() == "Hello World!"); | ||||
|       CHECK(printable.totalBytesWritten() == 12); | ||||
|       CHECK(doc.overflowed() == false); | ||||
|       CHECK(doc.memoryUsage() == 13); | ||||
|     } | ||||
|  | ||||
|     SECTION("Via Print::write(const char* size_t)") { | ||||
|       PrintableString<PrintAllAtOnce> printable = "Hello World!"; | ||||
|       CHECK(doc.set(printable) == true); | ||||
|       CHECK(doc.as<std::string>() == "Hello World!"); | ||||
|       CHECK(printable.totalBytesWritten() == 12); | ||||
|       CHECK(doc.overflowed() == false); | ||||
|       CHECK(doc.memoryUsage() == 13); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Too small memory pool") { | ||||
|     StaticJsonDocument<8> doc; | ||||
|  | ||||
|     SECTION("Via Print::write(char)") { | ||||
|       PrintableString<PrintOneCharacterAtATime> printable = "Hello World!"; | ||||
|       CHECK(doc.set(printable) == false); | ||||
|       CHECK(doc.isNull()); | ||||
|       CHECK(printable.totalBytesWritten() == 8); | ||||
|       CHECK(doc.overflowed() == true); | ||||
|       CHECK(doc.memoryUsage() == 0); | ||||
|     } | ||||
|  | ||||
|     SECTION("Via Print::write(const char* size_t)") { | ||||
|       PrintableString<PrintAllAtOnce> printable = "Hello World!"; | ||||
|       CHECK(doc.set(printable) == false); | ||||
|       CHECK(doc.isNull()); | ||||
|       CHECK(printable.totalBytesWritten() == 0); | ||||
|       CHECK(doc.overflowed() == true); | ||||
|       CHECK(doc.memoryUsage() == 0); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Null variant") { | ||||
|     JsonVariant var; | ||||
|     PrintableString<PrintOneCharacterAtATime> printable = "Hello World!"; | ||||
|     CHECK(var.set(printable) == false); | ||||
|     CHECK(var.isNull()); | ||||
|     CHECK(printable.totalBytesWritten() == 0); | ||||
|   } | ||||
|  | ||||
|   SECTION("String deduplication") { | ||||
|     StaticJsonDocument<128> doc; | ||||
|     doc.add(PrintableString<PrintOneCharacterAtATime>("Hello World!")); | ||||
|     doc.add(PrintableString<PrintAllAtOnce>("Hello World!")); | ||||
|     REQUIRE(doc.size() == 2); | ||||
|     CHECK(doc[0] == "Hello World!"); | ||||
|     CHECK(doc[1] == "Hello World!"); | ||||
|     CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(2) + 13); | ||||
|   } | ||||
| } | ||||
| @@ -206,4 +206,67 @@ struct Converter<decltype(nullptr)> { | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_ARDUINO_STREAM | ||||
|  | ||||
| class MemoryPoolPrint : public Print { | ||||
|  public: | ||||
|   MemoryPoolPrint(MemoryPool* pool) : _pool(pool), _size(0) { | ||||
|     pool->getFreeZone(&_string, &_capacity); | ||||
|   } | ||||
|  | ||||
|   const char* c_str() { | ||||
|     if (_size >= _capacity) | ||||
|       return 0; | ||||
|  | ||||
|     _string[_size++] = 0;  // TODO: test overflow | ||||
|     return _pool->saveStringFromFreeZone(_size); | ||||
|   } | ||||
|  | ||||
|   size_t write(uint8_t c) { | ||||
|     if (_size >= _capacity) | ||||
|       return 0; | ||||
|  | ||||
|     _string[_size++] = char(c); | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   size_t write(const uint8_t* buffer, size_t size) { | ||||
|     if (_size + size >= _capacity) { | ||||
|       _size = _capacity;  // mark as overflowed | ||||
|       return 0; | ||||
|     } | ||||
|     memcpy(&_string[_size], buffer, size); | ||||
|     _size += size; | ||||
|     return size; | ||||
|   } | ||||
|  | ||||
|   bool overflowed() const { | ||||
|     return _size >= _capacity; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   MemoryPool* _pool; | ||||
|   size_t _size; | ||||
|   char* _string; | ||||
|   size_t _capacity; | ||||
| }; | ||||
|  | ||||
| inline bool convertToJson(VariantRef variant, const ::Printable& value) { | ||||
|   MemoryPool* pool = getPool(variant); | ||||
|   VariantData* data = getData(variant); | ||||
|   if (!pool || !data) | ||||
|     return false; | ||||
|   MemoryPoolPrint print(pool); | ||||
|   value.printTo(print); | ||||
|   if (print.overflowed()) { | ||||
|     pool->markAsOverflowed(); | ||||
|     data->setNull(); | ||||
|     return false; | ||||
|   } | ||||
|   data->setOwnedString(print.c_str()); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -244,16 +244,26 @@ class VariantData { | ||||
|     setType(VALUE_IS_NULL); | ||||
|   } | ||||
|  | ||||
|   void setStringPointer(const char *s, storage_policies::store_by_copy) { | ||||
|   void setOwnedString(const char *s) { | ||||
|     ARDUINOJSON_ASSERT(s != 0); | ||||
|     setType(VALUE_IS_OWNED_STRING); | ||||
|     _content.asString = s; | ||||
|   } | ||||
|  | ||||
|   void setStringPointer(const char *s, storage_policies::store_by_address) { | ||||
|   void setLinkedString(const char *s) { | ||||
|     ARDUINOJSON_ASSERT(s != 0); | ||||
|     setType(VALUE_IS_LINKED_STRING); | ||||
|     _content.asString = s; | ||||
|   } | ||||
|  | ||||
|   void setStringPointer(const char *s, storage_policies::store_by_copy) { | ||||
|     setOwnedString(s); | ||||
|   } | ||||
|  | ||||
|   void setStringPointer(const char *s, storage_policies::store_by_address) { | ||||
|     setLinkedString(s); | ||||
|   } | ||||
|  | ||||
|   template <typename TAdaptedString> | ||||
|   bool setString(TAdaptedString value, MemoryPool *pool) { | ||||
|     return setString(value, pool, typename TAdaptedString::storage_policy()); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user