mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +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 custom converters (issue #687) | ||||||
|  | * Added support for `Printable` (issue #1444) | ||||||
| * Removed support for `char` values, see below (issue #1498) | * Removed support for `char` values, see below (issue #1498) | ||||||
| * `deserializeJson()` leaves `\uXXXX` unchanged instead of returning `NotSupported` | * `deserializeJson()` leaves `\uXXXX` unchanged instead of returning `NotSupported` | ||||||
| * `deserializeMsgPack()` inserts `null` instead of returning `NotSupported` | * `deserializeMsgPack()` inserts `null` instead of returning `NotSupported` | ||||||
|   | |||||||
| @@ -4,5 +4,6 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include "api/Print.h" | ||||||
| #include "api/Stream.h" | #include "api/Stream.h" | ||||||
| #include "api/String.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 | 	conflicts.cpp | ||||||
| 	FloatParts.cpp | 	FloatParts.cpp | ||||||
| 	JsonString.cpp | 	JsonString.cpp | ||||||
|  | 	printable.cpp | ||||||
| 	Readers.cpp | 	Readers.cpp | ||||||
| 	StringAdapters.cpp | 	StringAdapters.cpp | ||||||
| 	StringWriter.cpp | 	StringWriter.cpp | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| // Copyright Benoit Blanchon 2014-2021 | // Copyright Benoit Blanchon 2014-2021 | ||||||
| // MIT License | // MIT License | ||||||
|  |  | ||||||
| #define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1 | #include <Arduino.h> | ||||||
| #include <ArduinoJson.hpp> | #include <ArduinoJson.hpp> | ||||||
| #include <catch.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 | #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 | }  // namespace ARDUINOJSON_NAMESPACE | ||||||
|   | |||||||
| @@ -244,16 +244,26 @@ class VariantData { | |||||||
|     setType(VALUE_IS_NULL); |     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); |     setType(VALUE_IS_OWNED_STRING); | ||||||
|     _content.asString = s; |     _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); |     setType(VALUE_IS_LINKED_STRING); | ||||||
|     _content.asString = s; |     _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> |   template <typename TAdaptedString> | ||||||
|   bool setString(TAdaptedString value, MemoryPool *pool) { |   bool setString(TAdaptedString value, MemoryPool *pool) { | ||||||
|     return setString(value, pool, typename TAdaptedString::storage_policy()); |     return setString(value, pool, typename TAdaptedString::storage_policy()); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user