mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 08:42:39 +01:00 
			
		
		
		
	Attach copy policy to string adapters
This commit is contained in:
		| @@ -38,15 +38,14 @@ class CollectionData { | |||||||
|  |  | ||||||
|   // Object only |   // Object only | ||||||
|  |  | ||||||
|   template <typename TAdaptedString, typename TStoragePolicy> |   template <typename TAdaptedString> | ||||||
|   VariantData* addMember(TAdaptedString key, MemoryPool* pool, TStoragePolicy); |   VariantData* addMember(TAdaptedString key, MemoryPool* pool); | ||||||
|  |  | ||||||
|   template <typename TAdaptedString> |   template <typename TAdaptedString> | ||||||
|   VariantData* getMember(TAdaptedString key) const; |   VariantData* getMember(TAdaptedString key) const; | ||||||
|  |  | ||||||
|   template <typename TAdaptedString, typename TStoragePolicy> |   template <typename TAdaptedString> | ||||||
|   VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool, |   VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool); | ||||||
|                               TStoragePolicy); |  | ||||||
|  |  | ||||||
|   template <typename TAdaptedString> |   template <typename TAdaptedString> | ||||||
|   void removeMember(TAdaptedString key) { |   void removeMember(TAdaptedString key) { | ||||||
|   | |||||||
| @@ -33,12 +33,11 @@ inline VariantData* CollectionData::addElement(MemoryPool* pool) { | |||||||
|   return slotData(addSlot(pool)); |   return slotData(addSlot(pool)); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename TAdaptedString, typename TStoragePolicy> | template <typename TAdaptedString> | ||||||
| inline VariantData* CollectionData::addMember(TAdaptedString key, | inline VariantData* CollectionData::addMember(TAdaptedString key, | ||||||
|                                               MemoryPool* pool, |                                               MemoryPool* pool) { | ||||||
|                                               TStoragePolicy storage) { |  | ||||||
|   VariantSlot* slot = addSlot(pool); |   VariantSlot* slot = addSlot(pool); | ||||||
|   if (!slotSetKey(slot, key, pool, storage)) { |   if (!slotSetKey(slot, key, pool)) { | ||||||
|     removeSlot(slot); |     removeSlot(slot); | ||||||
|     return 0; |     return 0; | ||||||
|   } |   } | ||||||
| @@ -62,7 +61,7 @@ inline bool CollectionData::copyFrom(const CollectionData& src, | |||||||
|     VariantData* var; |     VariantData* var; | ||||||
|     if (s->key() != 0) { |     if (s->key() != 0) { | ||||||
|       String key(s->key(), s->ownsKey() ? String::Copied : String::Linked); |       String key(s->key(), s->ownsKey() ? String::Copied : String::Linked); | ||||||
|       var = addMember(adaptString(key), pool, getStringStoragePolicy(key)); |       var = addMember(adaptString(key), pool); | ||||||
|     } else { |     } else { | ||||||
|       var = addElement(pool); |       var = addElement(pool); | ||||||
|     } |     } | ||||||
| @@ -110,9 +109,9 @@ inline VariantData* CollectionData::getMember(TAdaptedString key) const { | |||||||
|   return slot ? slot->data() : 0; |   return slot ? slot->data() : 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename TAdaptedString, typename TStoragePolicy> | template <typename TAdaptedString> | ||||||
| inline VariantData* CollectionData::getOrAddMember( | inline VariantData* CollectionData::getOrAddMember(TAdaptedString key, | ||||||
|     TAdaptedString key, MemoryPool* pool, TStoragePolicy storage_policy) { |                                                    MemoryPool* pool) { | ||||||
|   // ignore null key |   // ignore null key | ||||||
|   if (key.isNull()) |   if (key.isNull()) | ||||||
|     return 0; |     return 0; | ||||||
| @@ -122,7 +121,7 @@ inline VariantData* CollectionData::getOrAddMember( | |||||||
|   if (slot) |   if (slot) | ||||||
|     return slot->data(); |     return slot->data(); | ||||||
|  |  | ||||||
|   return addMember(key, pool, storage_policy); |   return addMember(key, pool); | ||||||
| } | } | ||||||
|  |  | ||||||
| inline VariantData* CollectionData::getElement(size_t index) const { | inline VariantData* CollectionData::getElement(size_t index) const { | ||||||
|   | |||||||
| @@ -208,4 +208,35 @@ class MemoryPool { | |||||||
|   bool _overflowed; |   bool _overflowed; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | template <typename TAdaptedString, typename TCallback> | ||||||
|  | bool storeString(MemoryPool* pool, TAdaptedString str, CopyStringStoragePolicy, | ||||||
|  |                  TCallback callback) { | ||||||
|  |   const char* copy = pool->saveString(str); | ||||||
|  |   String storedString(copy, str.size(), String::Copied); | ||||||
|  |   callback(storedString); | ||||||
|  |   return copy != 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename TAdaptedString, typename TCallback> | ||||||
|  | bool storeString(MemoryPool*, TAdaptedString str, LinkStringStoragePolicy, | ||||||
|  |                  TCallback callback) { | ||||||
|  |   String storedString(str.data(), str.size(), String::Linked); | ||||||
|  |   callback(storedString); | ||||||
|  |   return !str.isNull(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename TAdaptedString, typename TCallback> | ||||||
|  | bool storeString(MemoryPool* pool, TAdaptedString str, | ||||||
|  |                  LinkOrCopyStringStoragePolicy policy, TCallback callback) { | ||||||
|  |   if (policy.link) | ||||||
|  |     return storeString(pool, str, LinkStringStoragePolicy(), callback); | ||||||
|  |   else | ||||||
|  |     return storeString(pool, str, CopyStringStoragePolicy(), callback); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename TAdaptedString, typename TCallback> | ||||||
|  | bool storeString(MemoryPool* pool, TAdaptedString str, TCallback callback) { | ||||||
|  |   return storeString(pool, str, str.storagePolicy(), callback); | ||||||
|  | } | ||||||
|  |  | ||||||
| }  // namespace ARDUINOJSON_NAMESPACE | }  // namespace ARDUINOJSON_NAMESPACE | ||||||
|   | |||||||
| @@ -61,6 +61,10 @@ class FlashString { | |||||||
|     ::memcpy_P(p, s._str, n); |     ::memcpy_P(p, s._str, n); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   CopyStringStoragePolicy storagePolicy() { | ||||||
|  |     return CopyStringStoragePolicy(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   const char* _str; |   const char* _str; | ||||||
|   size_t _size; |   size_t _size; | ||||||
|   | |||||||
| @@ -10,8 +10,21 @@ | |||||||
|  |  | ||||||
| namespace ARDUINOJSON_NAMESPACE { | namespace ARDUINOJSON_NAMESPACE { | ||||||
|  |  | ||||||
| inline SizedRamString adaptString(const String& s) { | class JsonStringAdapter : public SizedRamString { | ||||||
|   return SizedRamString(s.c_str(), s.size()); |  public: | ||||||
|  |   JsonStringAdapter(const String& s) | ||||||
|  |       : SizedRamString(s.c_str(), s.size()), _linked(s.isLinked()) {} | ||||||
|  |  | ||||||
|  |   LinkOrCopyStringStoragePolicy storagePolicy() { | ||||||
|  |     return LinkOrCopyStringStoragePolicy(_linked); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   bool _linked; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | inline JsonStringAdapter adaptString(const String& s) { | ||||||
|  |   return JsonStringAdapter(s); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <> | template <> | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ | |||||||
|  |  | ||||||
| #include <ArduinoJson/Polyfills/assert.hpp> | #include <ArduinoJson/Polyfills/assert.hpp> | ||||||
| #include <ArduinoJson/Strings/IsString.hpp> | #include <ArduinoJson/Strings/IsString.hpp> | ||||||
|  | #include <ArduinoJson/Strings/StoragePolicy.hpp> | ||||||
|  |  | ||||||
| namespace ARDUINOJSON_NAMESPACE { | namespace ARDUINOJSON_NAMESPACE { | ||||||
|  |  | ||||||
| @@ -48,6 +49,10 @@ class ZeroTerminatedRamString { | |||||||
|     return stringCompare(a, b) == 0; |     return stringCompare(a, b) == 0; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   CopyStringStoragePolicy storagePolicy() { | ||||||
|  |     return CopyStringStoragePolicy(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   const char* _str; |   const char* _str; | ||||||
| }; | }; | ||||||
| @@ -55,7 +60,7 @@ class ZeroTerminatedRamString { | |||||||
| template <> | template <> | ||||||
| struct IsString<char*> : true_type {}; | struct IsString<char*> : true_type {}; | ||||||
|  |  | ||||||
| inline ZeroTerminatedRamString adaptString(const char* s) { | inline ZeroTerminatedRamString adaptString(char* s) { | ||||||
|   return ZeroTerminatedRamString(s); |   return ZeroTerminatedRamString(s); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -63,14 +68,27 @@ template <> | |||||||
| struct IsString<unsigned char*> : true_type {}; | struct IsString<unsigned char*> : true_type {}; | ||||||
|  |  | ||||||
| inline ZeroTerminatedRamString adaptString(const unsigned char* s) { | inline ZeroTerminatedRamString adaptString(const unsigned char* s) { | ||||||
|   return adaptString(reinterpret_cast<const char*>(s)); |   return ZeroTerminatedRamString(reinterpret_cast<const char*>(s)); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <> | template <> | ||||||
| struct IsString<signed char*> : true_type {}; | struct IsString<signed char*> : true_type {}; | ||||||
|  |  | ||||||
| inline ZeroTerminatedRamString adaptString(const signed char* s) { | inline ZeroTerminatedRamString adaptString(const signed char* s) { | ||||||
|   return adaptString(reinterpret_cast<const char*>(s)); |   return ZeroTerminatedRamString(reinterpret_cast<const char*>(s)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class StaticStringAdapter : public ZeroTerminatedRamString { | ||||||
|  |  public: | ||||||
|  |   StaticStringAdapter(const char* str) : ZeroTerminatedRamString(str) {} | ||||||
|  |  | ||||||
|  |   LinkStringStoragePolicy storagePolicy() { | ||||||
|  |     return LinkStringStoragePolicy(); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | inline StaticStringAdapter adaptString(const char* s) { | ||||||
|  |   return StaticStringAdapter(s); | ||||||
| } | } | ||||||
|  |  | ||||||
| class SizedRamString { | class SizedRamString { | ||||||
| @@ -97,6 +115,10 @@ class SizedRamString { | |||||||
|     return _str; |     return _str; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   CopyStringStoragePolicy storagePolicy() { | ||||||
|  |     return CopyStringStoragePolicy(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   const char* _str; |   const char* _str; | ||||||
|   size_t _size; |   size_t _size; | ||||||
|   | |||||||
| @@ -4,53 +4,16 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <ArduinoJson/Memory/MemoryPool.hpp> |  | ||||||
| #include <ArduinoJson/Strings/String.hpp> |  | ||||||
|  |  | ||||||
| namespace ARDUINOJSON_NAMESPACE { | namespace ARDUINOJSON_NAMESPACE { | ||||||
|  |  | ||||||
| struct LinkStringStoragePolicy { | struct LinkStringStoragePolicy {}; | ||||||
|   template <typename TAdaptedString, typename TCallback> |  | ||||||
|   bool store(TAdaptedString str, MemoryPool*, TCallback callback) { | struct CopyStringStoragePolicy {}; | ||||||
|     String storedString(str.data(), str.size(), String::Linked); |  | ||||||
|     callback(storedString); | struct LinkOrCopyStringStoragePolicy { | ||||||
|     return !str.isNull(); |   LinkOrCopyStringStoragePolicy(bool l) : link(l) {} | ||||||
|   } |  | ||||||
|  |   bool link; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| struct CopyStringStoragePolicy { |  | ||||||
|   template <typename TAdaptedString, typename TCallback> |  | ||||||
|   bool store(TAdaptedString str, MemoryPool* pool, TCallback callback); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| class LinkOrCopyStringStoragePolicy : LinkStringStoragePolicy, |  | ||||||
|                                       CopyStringStoragePolicy { |  | ||||||
|  public: |  | ||||||
|   LinkOrCopyStringStoragePolicy(bool link) : _link(link) {} |  | ||||||
|  |  | ||||||
|   template <typename TAdaptedString, typename TCallback> |  | ||||||
|   bool store(TAdaptedString str, MemoryPool* pool, TCallback callback) { |  | ||||||
|     if (_link) |  | ||||||
|       return LinkStringStoragePolicy::store(str, pool, callback); |  | ||||||
|     else |  | ||||||
|       return CopyStringStoragePolicy::store(str, pool, callback); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|  private: |  | ||||||
|   bool _link; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| template <typename T> |  | ||||||
| inline CopyStringStoragePolicy getStringStoragePolicy(const T&) { |  | ||||||
|   return CopyStringStoragePolicy(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline LinkStringStoragePolicy getStringStoragePolicy(const char*) { |  | ||||||
|   return LinkStringStoragePolicy(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline LinkOrCopyStringStoragePolicy getStringStoragePolicy(const String& s) { |  | ||||||
|   return LinkOrCopyStringStoragePolicy(s.isLinked()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| }  // namespace ARDUINOJSON_NAMESPACE | }  // namespace ARDUINOJSON_NAMESPACE | ||||||
|   | |||||||
| @@ -118,8 +118,7 @@ struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> | |||||||
| template <> | template <> | ||||||
| struct Converter<const char*> : private VariantAttorney { | struct Converter<const char*> : private VariantAttorney { | ||||||
|   static void toJson(const char* src, VariantRef dst) { |   static void toJson(const char* src, VariantRef dst) { | ||||||
|     variantSetString(getData(dst), adaptString(src), getPool(dst), |     variantSetString(getData(dst), adaptString(src), getPool(dst)); | ||||||
|                      getStringStoragePolicy(src)); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static const char* fromJson(VariantConstRef src) { |   static const char* fromJson(VariantConstRef src) { | ||||||
| @@ -136,8 +135,7 @@ struct Converter<const char*> : private VariantAttorney { | |||||||
| template <> | template <> | ||||||
| struct Converter<String> : private VariantAttorney { | struct Converter<String> : private VariantAttorney { | ||||||
|   static void toJson(String src, VariantRef dst) { |   static void toJson(String src, VariantRef dst) { | ||||||
|     variantSetString(getData(dst), adaptString(src), getPool(dst), |     variantSetString(getData(dst), adaptString(src), getPool(dst)); | ||||||
|                      getStringStoragePolicy(src)); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static String fromJson(VariantConstRef src) { |   static String fromJson(VariantConstRef src) { | ||||||
| @@ -156,8 +154,7 @@ inline typename enable_if<IsString<T>::value, bool>::type convertToJson( | |||||||
|     const T& src, VariantRef dst) { |     const T& src, VariantRef dst) { | ||||||
|   VariantData* data = VariantAttorney::getData(dst); |   VariantData* data = VariantAttorney::getData(dst); | ||||||
|   MemoryPool* pool = VariantAttorney::getPool(dst); |   MemoryPool* pool = VariantAttorney::getPool(dst); | ||||||
|   return variantSetString(data, adaptString(src), pool, |   return variantSetString(data, adaptString(src), pool); | ||||||
|                           getStringStoragePolicy(src)); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| template <> | template <> | ||||||
|   | |||||||
| @@ -23,12 +23,11 @@ struct SlotKeySetter { | |||||||
|   VariantSlot* _instance; |   VariantSlot* _instance; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename TAdaptedString, typename TStoragePolicy> | template <typename TAdaptedString> | ||||||
| inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, | inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) { | ||||||
|                        TStoragePolicy storage) { |  | ||||||
|   if (!var) |   if (!var) | ||||||
|     return false; |     return false; | ||||||
|   return storage.store(key, pool, SlotKeySetter(var)); |   return storeString(pool, key, SlotKeySetter(var)); | ||||||
| } | } | ||||||
|  |  | ||||||
| inline size_t slotSize(const VariantSlot* var) { | inline size_t slotSize(const VariantSlot* var) { | ||||||
|   | |||||||
| @@ -285,14 +285,13 @@ class VariantData { | |||||||
|     return col ? col->getMember(key) : 0; |     return col ? col->getMember(key) : 0; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename TAdaptedString, typename TStoragePolicy> |   template <typename TAdaptedString> | ||||||
|   VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool, |   VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool) { | ||||||
|                               TStoragePolicy storage_policy) { |  | ||||||
|     if (isNull()) |     if (isNull()) | ||||||
|       toObject(); |       toObject(); | ||||||
|     if (!isObject()) |     if (!isObject()) | ||||||
|       return 0; |       return 0; | ||||||
|     return _content.asCollection.getOrAddMember(key, pool, storage_policy); |     return _content.asCollection.getOrAddMember(key, pool); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { |   void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { | ||||||
| @@ -306,15 +305,14 @@ class VariantData { | |||||||
|     return _flags & VALUE_MASK; |     return _flags & VALUE_MASK; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename TAdaptedString, typename TStoragePolicy> |   template <typename TAdaptedString> | ||||||
|   inline bool storeString(TAdaptedString value, MemoryPool* pool, |   inline bool setString(TAdaptedString value, MemoryPool* pool) { | ||||||
|                           TStoragePolicy storage) { |  | ||||||
|     if (value.isNull()) { |     if (value.isNull()) { | ||||||
|       setNull(); |       setNull(); | ||||||
|       return true; |       return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return storage.store(value, pool, VariantStringSetter(this)); |     return storeString(pool, value, VariantStringSetter(this)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   | |||||||
| @@ -37,10 +37,10 @@ inline void variantSetNull(VariantData* var) { | |||||||
|   var->setNull(); |   var->setNull(); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename TAdaptedString, typename TStoragePolicy> | template <typename TAdaptedString> | ||||||
| inline bool variantSetString(VariantData* var, TAdaptedString value, | inline bool variantSetString(VariantData* var, TAdaptedString value, | ||||||
|                              MemoryPool* pool, TStoragePolicy storage_policy) { |                              MemoryPool* pool) { | ||||||
|   return var != 0 ? var->storeString(value, pool, storage_policy) : 0; |   return var != 0 ? var->setString(value, pool) : 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline size_t variantSize(const VariantData* var) { | inline size_t variantSize(const VariantData* var) { | ||||||
| @@ -88,8 +88,7 @@ VariantData* variantGetOrAddMember(VariantData* var, TChar* key, | |||||||
|                                    MemoryPool* pool) { |                                    MemoryPool* pool) { | ||||||
|   if (!var) |   if (!var) | ||||||
|     return 0; |     return 0; | ||||||
|   return var->getOrAddMember(adaptString(key), pool, |   return var->getOrAddMember(adaptString(key), pool); | ||||||
|                              getStringStoragePolicy(key)); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename TString> | template <typename TString> | ||||||
| @@ -97,8 +96,7 @@ VariantData* variantGetOrAddMember(VariantData* var, const TString& key, | |||||||
|                                    MemoryPool* pool) { |                                    MemoryPool* pool) { | ||||||
|   if (!var) |   if (!var) | ||||||
|     return 0; |     return 0; | ||||||
|   return var->getOrAddMember(adaptString(key), pool, |   return var->getOrAddMember(adaptString(key), pool); | ||||||
|                              getStringStoragePolicy(key)); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline bool variantIsNull(const VariantData* var) { | inline bool variantIsNull(const VariantData* var) { | ||||||
|   | |||||||
| @@ -91,8 +91,7 @@ inline bool VariantData::copyFrom(const VariantData& src, MemoryPool* pool) { | |||||||
|       return toObject().copyFrom(src._content.asCollection, pool); |       return toObject().copyFrom(src._content.asCollection, pool); | ||||||
|     case VALUE_IS_OWNED_STRING: { |     case VALUE_IS_OWNED_STRING: { | ||||||
|       String value = src.asString(); |       String value = src.asString(); | ||||||
|       return storeString(adaptString(value), pool, |       return setString(adaptString(value), pool); | ||||||
|                          getStringStoragePolicy(value)); |  | ||||||
|     } |     } | ||||||
|     case VALUE_IS_OWNED_RAW: |     case VALUE_IS_OWNED_RAW: | ||||||
|       return storeOwnedRaw( |       return storeOwnedRaw( | ||||||
| @@ -154,14 +153,4 @@ inline void convertToJson(const VariantRefBase<TDataSource>& src, | |||||||
|   dst.set(src.template as<VariantConstRef>()); |   dst.set(src.template as<VariantConstRef>()); | ||||||
| } | } | ||||||
|  |  | ||||||
| // TODO: move somewhere else |  | ||||||
| template <typename TAdaptedString, typename TCallback> |  | ||||||
| bool CopyStringStoragePolicy::store(TAdaptedString str, MemoryPool* pool, |  | ||||||
|                                     TCallback callback) { |  | ||||||
|   const char* copy = pool->saveString(str); |  | ||||||
|   String storedString(copy, str.size(), String::Copied); |  | ||||||
|   callback(storedString); |  | ||||||
|   return copy != 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| }  // namespace ARDUINOJSON_NAMESPACE | }  // namespace ARDUINOJSON_NAMESPACE | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user