From aec4ee88b8e8944a034b055c477e65b2b978cb86 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 30 Jul 2025 11:58:36 +0200 Subject: [PATCH 1/7] Vendor MsgPack library --- src/MsgPack.h | 21 + src/MsgPack/Packer.h | 1032 +++++++++ src/MsgPack/Types.h | 289 +++ src/MsgPack/Unpacker.h | 2006 +++++++++++++++++ src/MsgPack/Utility.h | 216 ++ .../util/TeensyDirtySTLErrorSolution/LICENSE | 21 + .../TeensyDirtySTLErrorSolution/README.md | 57 + .../TeensyDirtySTLErrorSolution.h | 65 + 8 files changed, 3707 insertions(+) create mode 100644 src/MsgPack.h create mode 100644 src/MsgPack/Packer.h create mode 100644 src/MsgPack/Types.h create mode 100644 src/MsgPack/Unpacker.h create mode 100644 src/MsgPack/Utility.h create mode 100644 src/MsgPack/util/TeensyDirtySTLErrorSolution/LICENSE create mode 100644 src/MsgPack/util/TeensyDirtySTLErrorSolution/README.md create mode 100644 src/MsgPack/util/TeensyDirtySTLErrorSolution/TeensyDirtySTLErrorSolution.h diff --git a/src/MsgPack.h b/src/MsgPack.h new file mode 100644 index 0000000..8499f3a --- /dev/null +++ b/src/MsgPack.h @@ -0,0 +1,21 @@ +#pragma once +#ifndef HT_SERIAL_MSGPACK_H +#define HT_SERIAL_MSGPACK_H + +#include +#ifdef MSGPACK_DEBUGLOG_ENABLE +#include +#else +#include +#endif + +#include "MsgPack/Types.h" +#include "MsgPack/Packer.h" +#include "MsgPack/Unpacker.h" +#include "MsgPack/Utility.h" + +namespace MsgPack = arduino::msgpack; + +#include + +#endif // ARDUINOMSGPACK_H diff --git a/src/MsgPack/Packer.h b/src/MsgPack/Packer.h new file mode 100644 index 0000000..c585e09 --- /dev/null +++ b/src/MsgPack/Packer.h @@ -0,0 +1,1032 @@ +#pragma once +#ifndef HT_SERIAL_MSGPACK_PACKER_H +#define HT_SERIAL_MSGPACK_PACKER_H + +#include +#include +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else // Do not have libstdc++11 +// containers are disabled +#endif + +#ifdef TEENSYDUINO +#include "util/TeensyDirtySTLErrorSolution/TeensyDirtySTLErrorSolution.h" +#endif // TEENSYDUINO + +#include "Types.h" +#include "Unpacker.h" +#include + +namespace arduino { +namespace msgpack { + + class Packer { + bin_t buffer; + size_t n_indices {0}; + + public: + void reserve_buffer(const size_t size) { + buffer.reserve(size); + } + + template + auto serialize(const First& first, Rest&&... rest) -> typename std::enable_if< + !std::is_pointer::value || std::is_same::value +#ifdef ARDUINO + || std::is_same::value +#endif + >::type { + pack(first); + serialize(std::forward(rest)...); + } + + void serialize() {} + + template + void serialize(const arr_size_t& arr_size, Args&&... args) { + packArraySize(arr_size.size()); + serialize(std::forward(args)...); + } + + template + void serialize(const map_size_t& map_size, Args&&... args) { + packMapSize(map_size.size()); + serialize(std::forward(args)...); + } + +#ifdef ARDUINOJSON_VERSION + + //! Note: ArduinoJson cannot handle Arduino's String class correctly. + //! So the external buffer size is required. + void serialize_arduinojson(const JsonDocument& doc, const size_t num_max_string_type = 32) { + const size_t size = measureMsgPack(doc); + uint8_t* data = new uint8_t[size + num_max_string_type]; + serializeMsgPack(doc, data, size + num_max_string_type); + packRawBytes(data, size); + // TODO: smarter way to calcurate size of indices? + Unpacker unpacker; + unpacker.feed(data, size); + n_indices += unpacker.size(); + delete[] data; + } + + template + void serialize(const StaticJsonDocument& doc, const size_t num_max_string_type = 32) { + serialize_arduinojson(doc, num_max_string_type); + } + void serialize(const DynamicJsonDocument& doc, const size_t num_max_string_type = 32) { + serialize_arduinojson(doc, num_max_string_type); + } + +#endif // ARDUINOJSON_VERSION + + template + void to_array(Args&&... args) { + serialize(arr_size_t(sizeof...(args)), std::forward(args)...); + } + + template + void to_map(Args&&... args) { + size_t size = sizeof...(args); + if ((size % 2) == 0) + serialize(map_size_t(size / 2), std::forward(args)...); + else + LOG_ERROR(F("serialize arg size must be even for map:"), size); + } + + const bin_t& packet() const { + return buffer; + } + const uint8_t* data() const { + return buffer.data(); + } + size_t size() const { + return buffer.size(); + } + size_t indices() const { + return n_indices; + } + void clear() { + buffer.clear(); + n_indices = 0; + } + + ///////////////////////////////////////////////// + // ---------- msgpack type adaptors ---------- // + ///////////////////////////////////////////////// + + // adaptation of types to msgpack + // https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_adaptor + + // ---------- NIL format family ---------- + // - N/A + + template + auto pack(const T& n) -> typename std::enable_if< + std::is_same::value || std::is_same::value>::type { + (void)n; + packNil(); + } + + // ---------- BOOL format family ---------- + // - bool + + template + auto pack(const T& b) -> typename std::enable_if::value>::type { + packBool(b); + } + + // ---------- INT format family ---------- + // - char (signed/unsigned) + // - ints (signed/unsigned) + + template + auto pack(const T& value) -> typename std::enable_if< + std::is_arithmetic::value && std::is_integral::value && !std::is_same::value + && !std::is_same::type, char*>::value>::type { + packInteger(value); + } + + // ---------- FLOAT format family ---------- + // - float + // - double + + template + auto pack(const T& value) -> + typename std::enable_if::value && std::is_floating_point::value>::type { + packFloat(value); + } + + // ---------- STRING format family ---------- + // - char* + // - char[] + // - std::string + + void pack(const str_t& str) { + packString(str, getStringSize(str)); + } + void pack(const char* str) { + packString(str, getStringSize(str)); + } + void pack(const char* str, const size_t size) { + packString(str, size); + } +#ifdef ARDUINO + void pack(const __FlashStringHelper* str) { + packString(str, getStringSize(str)); + } +#endif + + // ---------- BIN format family ---------- + // - unsigned char* + // - unsigned char[] + // - std::vector + // - std::vector + // - std::array + // - std::array + + void pack(const uint8_t* bin, const size_t size) { + packBinary(bin, size); + } + + void pack(const bin_t& bin) { + packBinary((const uint8_t*)bin.data(), bin.size()); + } + + void pack(const bin_t& bin) { + packBinary(bin.data(), bin.size()); + } + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + void pack(const std::array& bin) { + packBinary((const uint8_t*)bin.data(), bin.size()); + } + + template + void pack(const std::array& bin) { + packBinary(bin.data(), bin.size()); + } + +#endif // have libstdc++11 + + // ---------- ARRAY format family ---------- + // - T[] + // - std::vector + // - std::array + // - std::deque + // - std::pair + // - std::tuple + // - std::list + // - std::forward_list + // - std::set + // - std::multiset + // - std::unordered_set * + // - std::unordered_multiset * + // * : not supported in arduino + + template + auto pack(const T* arr, const size_t size) -> + typename std::enable_if::value && !std::is_same::value>::type { + packArraySize(size); + for (size_t i = 0; i < size; ++i) pack(arr[i]); + } + + template + auto pack(const arr_t& arr) -> + typename std::enable_if::value && !std::is_same::value>::type { + packArrayContainer(arr); + } + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + auto pack(const std::array& arr) -> + typename std::enable_if::value && !std::is_same::value>::type { + packArrayContainer(arr); + } + + template + void pack(const std::deque& arr) { + packArrayContainer(arr); + } + + template + void pack(const std::pair& arr) { + packArraySize(2); + pack(arr.first); + pack(arr.second); + } + +#endif // have libstdc++11 + + template + auto pack(const std::tuple& t) -> typename std::enable_if < I::type { + if (I == 0) packArraySize(sizeof...(Ts)); + pack(std::get(t)); + pack(t); + } + + template + auto pack(const std::tuple&) -> typename std::enable_if::type {} + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + void pack(const std::list& arr) { + packArrayContainer(arr); + } + + template + void pack(const std::forward_list& arr) { + auto size = std::distance(arr.begin(), arr.end()); + packArraySize(size); + for (const auto& a : arr) pack(a); + } + + template + void pack(const std::set& arr) { + packArrayContainer(arr); + } + + template + void pack(const std::multiset& arr) { + packArrayContainer(arr); + } + + template + void pack(const std::unordered_set& arr) { + packArrayContainer(arr); + } + + template + void pack(const std::unordered_multiset& arr) { + packArrayContainer(arr); + } + +#endif // have libstdc++11 + + // ---------- MAP format family ---------- + // - std::map + // - std::multimap + // - std::unordered_map * + // - std::unordered_multimap * + // * : not supported in arduino + + template + void pack(const map_t& mp) { + packMapContainer(mp); + } + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + void pack(const std::multimap& mp) { + packMapContainer(mp); + } + + template + void pack(const std::unordered_map& mp) { + packMapContainer(mp); + } + + template + void pack(const std::unordered_multimap& mp) { + packMapContainer(mp); + } + +#endif // have libstdc++11 + + // ---------- EXT format family ---------- + + void pack(const object::ext& e) { + packExt(e); + } + + // ---------- TIMESTAMP format family ---------- + + void pack(const object::timespec& t) { + packTimestamp(t); + } + + // ---------- CUSTOM format ---------- + + template + auto pack(const C& c) -> typename std::enable_if::value>::type { + c.to_msgpack(*this); + } + + // ---------- Array/Map Size format ---------- + + void pack(const arr_size_t& t) { + packArraySize(t.size()); + } + + void pack(const map_size_t& t) { + packMapSize(t.size()); + } + + ///////////////////////////////////////////////////// + // ---------- msgpack types abstraction ---------- // + /////////////////////////////////////////............ + + // ---------- INT format family ---------- + + template + auto packInteger(const T& value) -> typename std::enable_if< + std::is_arithmetic::value && std::is_integral::value && !std::is_same::value + && !std::is_same::type, char*>::value>::type { + if (value >= 0) { + if ((uint64_t)value < (uint64_t)BitMask::UINT7) + packUInt7(value); + else if ((uint64_t)value <= (uint64_t)std::numeric_limits::max()) + packUInt8(value); + else if ((uint64_t)value <= (uint64_t)std::numeric_limits::max()) + packUInt16(value); + else if ((uint64_t)value <= (uint64_t)std::numeric_limits::max()) + packUInt32(value); + else + packUInt64(value); + } else { + if ((int64_t)value > -(int64_t)BitMask::INT5) + packInt5(value); + else if ((int64_t)value >= (int64_t)std::numeric_limits::min()) + packInt8(value); + else if ((int64_t)value >= (int64_t)std::numeric_limits::min()) + packInt16(value); + else if ((int64_t)value >= (int64_t)std::numeric_limits::min()) + packInt32(value); + else + packInt64(value); + } + } + + // ---------- FLOAT format family ---------- + + template + auto packFloat(const T& value) -> + typename std::enable_if::value && std::is_floating_point::value>::type { + if (sizeof(T) == sizeof(float)) + packFloat32(value); + else + packFloat64(value); + } + + // ---------- STR format family ---------- + + template + void packString(const T& str) { + packString(str, getStringSize(str)); + } + + template + void packString(const T& str, const size_t len) { + if (len <= (size_t)BitMask::STR5) + packString5(str, len); + else if (len <= std::numeric_limits::max()) + packString8(str, len); + else if (len <= std::numeric_limits::max()) + packString16(str, len); + else if (len <= std::numeric_limits::max()) + packString32(str, len); + } + + // ---------- BIN format family ---------- + + void packBinary(const uint8_t* bin, const size_t size) { + if (size <= std::numeric_limits::max()) + packBinary8(bin, (uint8_t)size); + else if (size <= std::numeric_limits::max()) + packBinary16(bin, (uint16_t)size); + else if (size <= std::numeric_limits::max()) + packBinary32(bin, (uint32_t)size); + } + + // ---------- ARRAY format family ---------- + + void packArraySize(const size_t size) { + if (size < (1 << 4)) + packArraySize4((uint8_t)size); + else if (size <= std::numeric_limits::max()) + packArraySize16((uint16_t)size); + else if (size <= std::numeric_limits::max()) + packArraySize32((uint32_t)size); + } + + // ---------- MAP format family ---------- + + void packMapSize(const size_t size) { + if (size < (1 << 4)) + packMapSize4((uint8_t)size); + else if (size <= std::numeric_limits::max()) + packMapSize16((uint16_t)size); + else if (size <= std::numeric_limits::max()) + packMapSize32((uint32_t)size); + } + + // ---------- EXT format family ---------- + + template + auto packFixExt(const int8_t type, const T value) -> + typename std::enable_if::value>::type { + size_t size = sizeof(T); + if (size == sizeof(uint8_t)) + packFixExt1(type, value); + else if (size == sizeof(uint16_t)) + packFixExt2(type, value); + else if (size == sizeof(uint32_t)) + packFixExt4(type, value); + else if (size == sizeof(uint64_t)) + packFixExt8(type, value); + } + + void packFixExt(const int8_t type, const uint64_t value_h, const uint64_t value_l) { + packFixExt16(type, value_h, value_l); + } + + void packFixExt(const int8_t type, const uint8_t* ptr, const uint8_t size) { + if (size == 0) return; + if (size == sizeof(uint8_t)) + packFixExt1(type, (uint8_t) * (ptr)); + else if (size == sizeof(uint16_t)) + packFixExt2(type, ptr); + else if (size <= sizeof(uint32_t)) + packFixExt4(type, ptr); + else if (size <= sizeof(uint64_t)) + packFixExt8(type, ptr); + else if (size <= sizeof(uint64_t) * 2) + packFixExt16(type, ptr); + } + + void packFixExt(const int8_t type, const uint16_t* ptr, const uint8_t size) { + packFixExt(type, (const uint8_t*)ptr, size); + } + + void packFixExt(const int8_t type, const uint32_t* ptr, const uint8_t size) { + packFixExt(type, (const uint8_t*)ptr, size); + } + + void packFixExt(const int8_t type, const uint64_t* ptr, const uint8_t size) { + packFixExt(type, (const uint8_t*)ptr, size); + } + + template + auto packExt(const int8_t type, const T* ptr, const U size) -> + typename std::enable_if::value && std::is_integral::value>::type { + if (size <= sizeof(uint64_t) * 2) + packFixExt(type, ptr, size); + else { + if (size <= std::numeric_limits::max()) + packExtSize8(type, size); + else if (size <= std::numeric_limits::max()) + packExtSize16(type, size); + else if (size <= std::numeric_limits::max()) + packExtSize32(type, size); + packRawBytes((const uint8_t*)ptr, size); + } + } + + void packExt(const object::ext& e) { + packExt(e.type(), e.data(), e.size()); + } + + // ---------- TIMESTAMP format family ---------- + + void packTimestamp(const object::timespec& time) { + if ((time.tv_sec >> 34) == 0) { + uint64_t data64 = ((uint64_t)time.tv_nsec << 34) | time.tv_sec; + if ((data64 & 0xffffffff00000000L) == 0) + packTimestamp32((uint32_t)data64); + else + packTimestamp64(data64); + } else + packTimestamp96(time.tv_sec, time.tv_nsec); + } + + ///////////////////////////////////////// + // ---------- msgpack types ---------- // + ///////////////////////////////////////// + + // MessagePack Specification + // https://github.com/msgpack/msgpack/blob/master/spec.md + + // ---------- NIL format family ---------- + + void packNil() { + packRawByte(Type::NIL); + ++n_indices; + } + + void packNil(const object::nil_t& n) { + (void)n; + packRawByte(Type::NIL); + ++n_indices; + } + + // ---------- BOOL format family ---------- + + void packBool(const bool b) { + packRawByte((uint8_t)Type::BOOL | ((uint8_t)b & (uint8_t)BitMask::BOOL)); + ++n_indices; + } + + // ---------- INT format family ---------- + + void packUInt7(const uint8_t value) { + packRawByte((uint8_t)Type::UINT7 | (value & (uint8_t)BitMask::UINT7)); + ++n_indices; + } + + void packUInt8(const uint8_t value) { + packRawByte(Type::UINT8); + packRawByte(value); + ++n_indices; + } + + void packUInt16(const uint16_t value) { + packRawByte(Type::UINT16); + packRawReversed(value); + ++n_indices; + } + + void packUInt32(const uint32_t value) { + packRawByte(Type::UINT32); + packRawReversed(value); + ++n_indices; + } + + void packUInt64(const uint64_t value) { + packRawByte(Type::UINT64); + packRawReversed(value); + ++n_indices; + } + + void packInt5(const int8_t value) { + packRawByte((uint8_t)Type::INT5 | ((uint8_t)value & (uint8_t)BitMask::INT5)); + ++n_indices; + } + + void packInt8(const int8_t value) { + packRawByte(Type::INT8); + packRawByte(value); + ++n_indices; + } + + void packInt16(const int16_t value) { + packRawByte(Type::INT16); + packRawReversed(value); + ++n_indices; + } + + void packInt32(const int32_t value) { + packRawByte(Type::INT32); + packRawReversed(value); + ++n_indices; + } + + void packInt64(const int64_t value) { + packRawByte(Type::INT64); + packRawReversed(value); + ++n_indices; + } + + // ---------- FLOAT format family ---------- + + void packFloat32(const float value) { + packRawByte(Type::FLOAT32); + packRawReversed(value); + ++n_indices; + } + + void packFloat64(const double value) { +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + packRawByte(Type::FLOAT64); + packRawReversed(value); + ++n_indices; +#else + packFloat32((const float)value); // Uno, etc. does not support double +#endif // have libstdc++11 + } + + // ---------- STR format family ---------- + + void packString5(const str_t& str) { + packString5(str, getStringSize(str)); + } + void packString5(const str_t& str, const size_t len) { + packString5(str.c_str(), len); + } + void packString5(const char* value) { + packString5(value, getStringSize(value)); + } + void packString5(const char* value, const size_t len) { + packRawByte((uint8_t)Type::STR5 | ((uint8_t)len & (uint8_t)BitMask::STR5)); + packRawBytes(value, len); + ++n_indices; + } + + void packString8(const str_t& str) { + packString8(str, getStringSize(str)); + } + void packString8(const str_t& str, const size_t len) { + packString8(str.c_str(), len); + } + void packString8(const char* value) { + packString8(value, getStringSize(value)); + } + void packString8(const char* value, const size_t len) { + packRawByte(Type::STR8); + packRawByte((uint8_t)len); + packRawBytes(value, len); + ++n_indices; + } + + void packString16(const str_t& str) { + packString16(str, getStringSize(str)); + } + void packString16(const str_t& str, const size_t len) { + packString16(str.c_str(), len); + } + void packString16(const char* value) { + packString16(value, getStringSize(value)); + } + void packString16(const char* value, const size_t len) { + packRawByte(Type::STR16); + packRawReversed((uint16_t)len); + packRawBytes(value, len); + ++n_indices; + } + + void packString32(const str_t& str) { + packString32(str, getStringSize(str)); + } + void packString32(const str_t& str, const size_t len) { + packString32(str.c_str(), len); + } + void packString32(const char* value) { + packString32(value, getStringSize(value)); + } + void packString32(const char* value, const size_t len) { + packRawByte(Type::STR32); + packRawReversed((uint32_t)len); + packRawBytes(value, len); + ++n_indices; + } + +#ifdef ARDUINO + + void packString5(const __FlashStringHelper* str) { + packString5(str, getStringSize(str)); + } + void packString5(const __FlashStringHelper* str, const size_t len) { + packRawByte((uint8_t)Type::STR5 | ((uint8_t)len & (uint8_t)BitMask::STR5)); + packFlashString(str); + ++n_indices; + } + + void packString8(const __FlashStringHelper* str) { + packString8(str, getStringSize(str)); + } + void packString8(const __FlashStringHelper* str, const size_t len) { + packRawByte(Type::STR8); + packRawByte((uint8_t)len); + packFlashString(str); + ++n_indices; + } + + void packString16(const __FlashStringHelper* str) { + packString16(str, getStringSize(str)); + } + void packString16(const __FlashStringHelper* str, const size_t len) { + packRawByte(Type::STR16); + packRawReversed((uint16_t)len); + packFlashString(str); + ++n_indices; + } + + void packString32(const __FlashStringHelper* str) { + packString32(str, getStringSize(str)); + } + void packString32(const __FlashStringHelper* str, const size_t len) { + packRawByte(Type::STR32); + packRawReversed((uint32_t)len); + packFlashString(str); + ++n_indices; + } + +#endif + + // ---------- BIN format family ---------- + + void packBinary8(const uint8_t* value, const uint8_t size) { + packRawByte(Type::BIN8); + packRawByte(size); + packRawBytes(value, size); + ++n_indices; + } + + void packBinary16(const uint8_t* value, const uint16_t size) { + packRawByte(Type::BIN16); + packRawReversed(size); + packRawBytes(value, size); + ++n_indices; + } + + void packBinary32(const uint8_t* value, const uint32_t size) { + packRawByte(Type::BIN32); + packRawReversed(size); + packRawBytes(value, size); + ++n_indices; + } + + // ---------- ARRAY format family ---------- + + void packArraySize4(const uint8_t value) { + packRawByte((uint8_t)Type::ARRAY4 | (value & (uint8_t)BitMask::ARRAY4)); + ++n_indices; + } + + void packArraySize16(const uint16_t value) { + packRawByte(Type::ARRAY16); + packRawReversed(value); + ++n_indices; + } + + void packArraySize32(const uint32_t value) { + packRawByte(Type::ARRAY32); + packRawReversed(value); + ++n_indices; + } + + // ---------- MAP format family ---------- + + void packMapSize4(const uint8_t value) { + packRawByte((uint8_t)Type::MAP4 | (value & (uint8_t)BitMask::MAP4)); + ++n_indices; + } + + void packMapSize16(const uint16_t value) { + packRawByte(Type::MAP16); + packRawReversed(value); + ++n_indices; + } + + void packMapSize32(const uint32_t value) { + packRawByte(Type::MAP32); + packRawReversed(value); + ++n_indices; + } + + // ---------- EXT format family ---------- + + void packFixExt1(const int8_t type, const uint8_t value) { + packRawByte(Type::FIXEXT1); + packRawByte((uint8_t)type); + packRawByte(value); + ++n_indices; + } + + void packFixExt2(const int8_t type, const uint16_t value) { + packRawByte(Type::FIXEXT2); + packRawByte((uint8_t)type); + packRawBytes((const uint8_t*)&value, sizeof(value)); + ++n_indices; + } + + void packFixExt2(const int8_t type, const uint8_t* ptr) { + packRawByte(Type::FIXEXT2); + packRawByte((uint8_t)type); + packRawBytes((const uint8_t*)ptr, 2); + ++n_indices; + } + + void packFixExt2(const int8_t type, const uint16_t* ptr) { + packFixExt2(type, (const uint8_t*)ptr); + } + + void packFixExt4(const int8_t type, const uint32_t value) { + packRawByte(Type::FIXEXT4); + packRawByte((uint8_t)type); + packRawBytes((const uint8_t*)&value, sizeof(value)); + ++n_indices; + } + + void packFixExt4(const int8_t type, const uint8_t* ptr) { + packRawByte(Type::FIXEXT4); + packRawByte((uint8_t)type); + packRawBytes((const uint8_t*)ptr, 4); + ++n_indices; + } + + void packFixExt4(const int8_t type, const uint32_t* ptr) { + packFixExt4(type, (const uint8_t*)ptr); + } + + void packFixExt8(const int8_t type, const uint64_t value) { + packRawByte(Type::FIXEXT8); + packRawByte((uint8_t)type); + packRawBytes((const uint8_t*)&value, sizeof(value)); + ++n_indices; + } + + void packFixExt8(const int8_t type, const uint8_t* ptr) { + packRawByte(Type::FIXEXT8); + packRawByte((uint8_t)type); + packRawBytes((const uint8_t*)ptr, 8); + ++n_indices; + } + + void packFixExt8(const int8_t type, const uint64_t* ptr) { + packFixExt8(type, (const uint8_t*)ptr); + } + + void packFixExt16(const int8_t type, const uint64_t value_h, const uint64_t value_l) { + packRawByte(Type::FIXEXT16); + packRawByte((uint8_t)type); + packRawBytes((const uint8_t*)&value_h, sizeof(value_h)); + packRawBytes((const uint8_t*)&value_l, sizeof(value_l)); + ++n_indices; + } + + void packFixExt16(const int8_t type, const uint8_t* ptr) { + packRawByte(Type::FIXEXT16); + packRawByte((uint8_t)type); + packRawBytes((const uint8_t*)ptr, 16); + ++n_indices; + } + + void packFixExt16(const int8_t type, const uint64_t* ptr) { + packFixExt16(type, (const uint8_t*)ptr); + } + + void packExtSize8(const int8_t type, const uint8_t size) { + packRawByte(Type::EXT8); + packRawByte(size); + packRawByte((uint8_t)type); + ++n_indices; + } + + void packExtSize16(const int8_t type, const uint16_t size) { + packRawByte(Type::EXT16); + packRawReversed(size); + packRawByte((uint8_t)type); + ++n_indices; + } + + void packExtSize32(const int8_t type, const uint32_t size) { + packRawByte(Type::EXT32); + packRawReversed(size); + packRawByte((uint8_t)type); + ++n_indices; + } + + // ---------- TIMESTAMP format family ---------- + + void packTimestamp32(const uint32_t unix_time_sec) { + packRawByte(Type::FIXEXT4); + packRawByte((uint8_t)-1); + packRawReversed(unix_time_sec); + ++n_indices; + } + + void packTimestamp64(const uint64_t unix_time) { + packRawByte(Type::FIXEXT8); + packRawByte((uint8_t)-1); + packRawReversed(unix_time); + ++n_indices; + } + + void packTimestamp64(const uint64_t unix_time_sec, const uint32_t unix_time_nsec) { + uint64_t utime = ((unix_time_nsec & 0x00000003FFFFFFFF) << 34) | (uint64_t)(unix_time_sec & 0x3FFFFFFFF); + packTimestamp64(utime); + } + + void packTimestamp96(const int64_t unix_time_sec, const uint32_t unix_time_nsec) { + packExtSize8(-1, 12); + packRawReversed(unix_time_nsec); + packRawReversed(unix_time_sec); + ++n_indices; + } + + private: + void packRawByte(const uint8_t value) { + buffer.emplace_back(value); + } + + void packRawByte(const Type& type) { + buffer.emplace_back((uint8_t)type); + } + + void packRawBytes(const uint8_t* value, const size_t size) { + for (size_t i = 0; i < size; ++i) buffer.emplace_back(value[i]); + } + + void packRawBytes(const char* value, const size_t size) { + for (size_t i = 0; i < size; ++i) buffer.emplace_back(value[i]); + } + + template + void packRawReversed(const DataType& value) { + const auto size = sizeof(DataType); + for (size_t i = 0; i < size; ++i) { + buffer.emplace_back(((uint8_t*)&value)[size - 1 - i]); + } + } + + template + void packArrayContainer(const A& arr) { + packArraySize(arr.size()); + for (const auto& a : arr) pack(a); + } + + template + void packMapContainer(const M& mp) { + packMapSize(mp.size()); + for (const auto& m : mp) { + pack(m.first); + pack(m.second); + } + } + + size_t getStringSize(const str_t& str) const { + return str.length(); + } + + size_t getStringSize(const char* str) const { + return strlen(str); + } + +#ifdef ARDUINO + + size_t getStringSize(const __FlashStringHelper* str) const { + return strlen_P((const char*)str); + } + + void packFlashString(const __FlashStringHelper* str) { + char* p = (char*)str; + while (1) { + uint8_t c = pgm_read_byte(p++); + if (c == 0) break; + packRawByte(c); + } + } + +#endif + }; + +} // namespace msgpack +} // namespace arduino + +#endif // HT_SERIAL_MSGPACK_PACKER_H diff --git a/src/MsgPack/Types.h b/src/MsgPack/Types.h new file mode 100644 index 0000000..837c54c --- /dev/null +++ b/src/MsgPack/Types.h @@ -0,0 +1,289 @@ +#pragma once +#ifndef HT_SERIAL_MSGPACK_TYPES_H +#define HT_SERIAL_MSGPACK_TYPES_H + +#include +#ifdef ARDUINO +#include +#else +#include +#endif + +#ifdef INT5 +// avoid conflict with interrrupt macro on e.g. Arduino Mega. This +// should not break code that rely on this constant, by keeping the +// value available as a C++-level constant. This first allocates a +// temporary constant, to capture the value before undeffing, and +// then defines the actual INT5 constant. Finally, INT5 is redefined +// as itself to make sure #ifdef INT5 still works. +static constexpr uint8_t INT5_TEMP_VALUE = INT5; +#undef INT5 +static constexpr uint8_t INT5 = INT5_TEMP_VALUE; +#define INT5 INT5 +#endif + +#include +#include + +namespace arduino { +namespace msgpack { + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + using idx_t = std::vector; + template + using arr_t = std::vector; + template + using fix_arr_t = std::array; + template + using map_t = std::map; + template + using bin_t = std::vector< + typename std::enable_if::value || std::is_same::value, T>::type, + std::allocator >; + +#else // Do not have libstdc++11 + +#ifndef MSGPACK_MAX_PACKET_BYTE_SIZE +#define MSGPACK_MAX_PACKET_BYTE_SIZE 128 +#endif // MSGPACK_MAX_PACKET_BYTE_SIZE +#ifndef MSGPACK_MAX_ARRAY_SIZE +#define MSGPACK_MAX_ARRAY_SIZE 8 +#endif // MSGPACK_MAX_ARRAY_SIZE +#ifndef MSGPACK_MAX_MAP_SIZE +#define MSGPACK_MAX_MAP_SIZE 8 +#endif // MSGPACK_MAX_MAP_SIZE +#ifndef MSGPACK_MAX_OBJECT_SIZE +#define MSGPACK_MAX_OBJECT_SIZE 32 +#endif // MSGPACK_MAX_OBJECT_SIZE + + using idx_t = arx::stdx::vector; + template + using arr_t = arx::stdx::vector; + template + using fix_arr_t = arx::stdx::array; + template + using map_t = arx::stdx::map; + template + using bin_t = arx::stdx::vector::value || std::is_same::value, T>::type, N>; + +#endif // Do not have libstdc++11 + +#ifdef ARDUINO + using str_t = String; +#else + using str_t = std::string; +#ifndef F + inline const char* F(const char* c) { + return c; + } +#endif +#endif + + namespace type { + class ArraySize { + size_t sz; + + public: + explicit ArraySize(const size_t size = 0) : sz(size) {} + size_t size() const { + return sz; + } + void size(const size_t s) { + sz = s; + } + }; + class MapSize { + size_t sz; + + public: + explicit MapSize(const size_t size = 0) : sz(size) {} + size_t size() const { + return sz; + } + void size(const size_t s) { + sz = s; + } + }; + } // namespace type + + using arr_size_t = type::ArraySize; + using map_size_t = type::MapSize; + + namespace object { + struct nil_t { + bool is_nil {false}; + nil_t& operator=(const nil_t& rhs) { + this->is_nil = rhs.is_nil; + return *this; + } + nil_t& operator=(const bool b) { + this->is_nil = b; + return *this; + } + bool operator()() const { + return this->is_nil; + } + bool operator==(const nil_t& x) { + return (*this)() == x(); + } + bool operator!=(const nil_t& x) { + return !(*this == x); + } + }; + + class ext { + bin_t m_data; + + public: + ext() : m_data() {} + ext(int8_t t, const uint8_t* p, uint32_t s) { + m_data.reserve(static_cast(s) + 1); + m_data.push_back(static_cast(t)); + m_data.insert(m_data.end(), p, p + s); + } + ext(int8_t t, uint32_t s) { + m_data.resize(static_cast(s) + 1); + m_data[0] = static_cast(t); + } + int8_t type() const { + return static_cast(m_data[0]); + } + const uint8_t* data() const { + return &(m_data[0]) + 1; + } + uint8_t* data() { + return &(m_data[0]) + 1; + } + uint32_t size() const { + return static_cast(m_data.size()) - 1; + } + bool operator==(const ext& x) const { + return m_data == x.m_data; + } + bool operator!=(const ext& x) const { + return !(*this == x); + } + }; + + struct timespec { + int64_t tv_sec; // seconds + uint32_t tv_nsec; // nanoseconds + + bool operator==(const timespec& x) const { + return (tv_sec == x.tv_sec) && (tv_nsec == x.tv_nsec); + } + bool operator!=(const timespec& x) const { + return !(*this == x); + } + bool operator<(const timespec& x) const { + if (tv_sec < x.tv_sec) + return true; + else if (tv_sec > x.tv_sec) + return false; + else + return tv_nsec < x.tv_nsec; + } + bool operator>(const timespec& x) const { + return (*this != x) && (*this < x); + } + }; + + } // namespace object + + enum class Type : uint8_t { + NA = 0xC1, // never used + NIL = 0xC0, + BOOL = 0xC2, + UINT7 = 0x00, // same as POSITIVE_FIXINT + UINT8 = 0xCC, + UINT16 = 0xCD, + UINT32 = 0xCE, + UINT64 = 0xCF, + INT5 = 0xE0, // same as NEGATIVE_FIXINT + INT8 = 0xD0, + INT16 = 0xD1, + INT32 = 0xD2, + INT64 = 0xD3, + FLOAT32 = 0xCA, + FLOAT64 = 0xCB, + STR5 = 0xA0, // same as FIXSTR + STR8 = 0xD9, + STR16 = 0xDA, + STR32 = 0xDB, + BIN8 = 0xC4, + BIN16 = 0xC5, + BIN32 = 0xC6, + ARRAY4 = 0x90, // same as FIXARRAY + ARRAY16 = 0xDC, + ARRAY32 = 0xDD, + MAP4 = 0x80, // same as FIXMAP + MAP16 = 0xDE, + MAP32 = 0xDF, + FIXEXT1 = 0xD4, + FIXEXT2 = 0xD5, + FIXEXT4 = 0xD6, + FIXEXT8 = 0xD7, + FIXEXT16 = 0xD8, + EXT8 = 0xC7, + EXT16 = 0xC8, + EXT32 = 0xC9, + TIMESTAMP32 = 0xD6, + TIMESTAMP64 = 0xD7, + TIMESTAMP96 = 0xC7, + + POSITIVE_FIXINT = 0x00, + NEGATIVE_FIXINT = 0xE0, + FIXSTR = 0xA0, + FIXARRAY = 0x90, + FIXMAP = 0x80, + }; + + enum class BitMask : uint8_t { + BOOL = 0x01, + POSITIVE_FIXINT = 0x7F, + UINT7 = 0x7F, // same as POSITIVE_FIXINT + NEGATIVE_FIXINT = 0x1F, + INT5 = 0x1F, // same as NEGATIVE_FIXINT + FIXSTR = 0x1F, + STR5 = 0x1F, // same as FIXSTR + FIXARRAY = 0x0F, + ARRAY4 = 0x0F, // same as FIXARRAY + FIXMAP = 0x0F, + MAP4 = 0x0F, // same as FIXMAP + }; + + template + using has_to_msgpack_impl = typename std::enable_if< + std::is_same::value>::type; + template + using has_to_msgpack = arx::is_detected; + + template + using has_from_msgpack_impl = typename std::enable_if< + std::is_same::value>::type; + template + using has_from_msgpack = arx::is_detected; + +} // namespace msgpack +} // namespace arduino + +#define MSGPACK_DEFINE(...) \ + void to_msgpack(MsgPack::Packer& packer) const { \ + packer.to_array(__VA_ARGS__); \ + } \ + void from_msgpack(MsgPack::Unpacker& unpacker) { \ + unpacker.from_array(__VA_ARGS__); \ + } + +#define MSGPACK_DEFINE_MAP(...) \ + void to_msgpack(MsgPack::Packer& packer) const { \ + packer.to_map(__VA_ARGS__); \ + } \ + void from_msgpack(MsgPack::Unpacker& unpacker) { \ + unpacker.from_map(__VA_ARGS__); \ + } + +#define MSGPACK_BASE(base) (*const_cast(static_cast(this))) + +#endif // HT_SERIAL_MSGPACK_TYPES_H diff --git a/src/MsgPack/Unpacker.h b/src/MsgPack/Unpacker.h new file mode 100644 index 0000000..512601e --- /dev/null +++ b/src/MsgPack/Unpacker.h @@ -0,0 +1,2006 @@ +#pragma once +#ifndef HT_SERIAL_MSGPACK_UNPACKER_H +#define HT_SERIAL_MSGPACK_UNPACKER_H + +#include +#include +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else // Do not have libstdc++11 +// containers are disabled +#endif +#ifdef TEENSYDUINO +#include "util/TeensyDirtySTLErrorSolution/TeensyDirtySTLErrorSolution.h" +#endif // TEENSYDUINO + +#include "Types.h" +#include + +namespace arduino { +namespace msgpack { + + class Unpacker { + uint8_t* raw_data {nullptr}; + idx_t indices; + size_t curr_index {0}; + bool b_size_matched {false}; + bool b_decode_success {false}; + +#define MSGPACK_DECODABLE_CHECK(T) \ + if (curr_index >= indices.size()) { \ + LOG_ERROR(F("no more decodable objects")); \ + b_decode_success = false; \ + return T(); \ + } else { \ + b_decode_success = true; \ + } + + public: + void reserve_indices(const size_t size) { + indices.reserve(size); + } + + bool feed(const uint8_t* data, const size_t size) { + raw_data = (uint8_t*)data; + for (size_t i = 0; i < size; i += getElementSize(indices.size() - 1)) indices.emplace_back(i); + const size_t decoded_size = indices.back() + getElementSize(indices.size() - 1); + b_size_matched = (size == decoded_size); + if (!b_size_matched) LOG_ERROR(F("decoded binary size"), decoded_size, F("not matched to"), size); + return b_size_matched; + } + + template + bool deserialize(First& first, Rest&&... rest) { + if (!b_size_matched || indices.empty()) { + LOG_WARN(F("correct binary data was not supplied yet")); + b_decode_success = false; + return b_decode_success; + } + if (curr_index >= indices.size()) { + LOG_ERROR(F("too many args: obj index overflow")); + b_decode_success = false; + return b_decode_success; + } + if (!unpack(first)) { + return b_decode_success; + } + + return deserialize(std::forward(rest)...); + } + + bool deserialize() { + if (curr_index > indices.size()) { + LOG_ERROR("index overflow:", curr_index, "must be <=", indices.size()); + b_decode_success = false; + } + + // do nothing if curr_index is <= indices.size() + // - curr_index == indices.size() + // - to be decoded after this deserialize() + + return b_decode_success; + } + +#ifdef ARDUINOJSON_VERSION + + private: + bool deserialize_arduinojson(JsonDocument& doc) { + auto err = deserializeMsgPack(doc, raw_data); + if (err) { + LOG_ERROR("deserializeJson() faled: ", err.c_str()); + b_decode_success = false; + } else { + b_decode_success = true; + } + return b_decode_success; + } + + public: + template + bool deserialize(StaticJsonDocument& doc) { + return deserialize_arduinojson(doc); + } + bool deserialize(DynamicJsonDocument& doc) { + return deserialize_arduinojson(doc); + } + +#endif // ARDUINOJSON_VERSION + + template + bool from_array(Args&&... args) { + static arr_size_t sz; + return deserialize(sz, std::forward(args)...); + } + + template + bool from_map(Args&&... args) { + if ((sizeof...(args) % 2) == 0) { + static map_size_t sz; + return deserialize(sz, std::forward(args)...); + } else { + LOG_ERROR(F("arg size must be even for map:"), sizeof...(args)); + b_decode_success = false; + return b_decode_success; + } + } + + template + void to_tuple(std::tuple& t) { + to_tuple(std::make_index_sequence(), t); + } + template + void to_tuple(std::index_sequence&&, std::tuple& t) { + size_t i {0}; + idx_t {(unpack(std::get(t)), i++)...}; + } + void to_tuple() { + // nothing to do + } + + bool decode_ready() const { + return b_size_matched; + } + bool decoded() const { + return b_decode_success; + } + size_t size() const { + return indices.size(); + } + void index(const size_t i) { + curr_index = i; + } + size_t index() const { + return curr_index; + } + void clear() { + indices.clear(); + index(0); + b_size_matched = false; + b_decode_success = false; + raw_data = nullptr; + } + + ///////////////////////////////////////////////// + // ---------- msgpack type adaptors ---------- // + ///////////////////////////////////////////////// + + // adaptation of types to msgpack + // https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_adaptor + + // ---------- NIL format family ---------- + // - N/A + + template + auto unpack(T& value) -> typename std::enable_if::value, bool>::type { + value = unpackNil(); + return b_decode_success; + } + + // ---------- BOOL format family ---------- + // - bool + + template + auto unpack(T& value) -> typename std::enable_if::value, bool>::type { + value = unpackBool(); + return b_decode_success; + } + + // ---------- INT format family ---------- + // - char (signed/unsigned) + // - ints (signed/unsigned) + + template + auto unpack(T& value) -> typename std::enable_if< + std::is_arithmetic::value && std::is_integral::value && !std::is_same::value + && !std::is_same::type, char*>::value && !std::is_signed::value, + bool>::type { + value = unpackUInt(); + return b_decode_success; + } + + template + auto unpack(T& value) -> typename std::enable_if< + std::is_arithmetic::value && std::is_integral::value && !std::is_same::value + && !std::is_same::type, char*>::value && std::is_signed::value, + bool>::type { + value = unpackInt(); + return b_decode_success; + } + + // ---------- FLOAT format family ---------- + // - float + // - double + + template + auto unpack(T& value) -> + typename std::enable_if::value && std::is_floating_point::value, bool>::type { + value = unpackFloat(); + return b_decode_success; + } + + // ---------- STRING format family ---------- + // - char* + // - char[] + // - std::string + + bool unpack(str_t& str) { + str = unpackString(); + return b_decode_success; + } + + // ---------- BIN format family ---------- + // - unsigned char* + // - unsigned char[] + // - std::vector + // - std::vector + // - std::array + // - std::array + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + auto unpack(bin_t& bin) -> + typename std::enable_if::value || std::is_same::value, bool>::type { + bin = unpackBinary(); + return b_decode_success; + } + +#else + + template + auto unpack(arx::stdx::vector& bin) // bin_t + -> typename std::enable_if::value || std::is_same::value, bool>::type { + bin = unpackBinary(); + return b_decode_success; + } + +#endif // Do not have libstdc++11 + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + auto unpack(std::array& bin) -> + typename std::enable_if::value || std::is_same::value, bool>::type { + bin = unpackBinary(); + return b_decode_success; + } + +#endif // Do not have libstdc++11 + + // ---------- ARRAY format family ---------- + // - T[] + // - std::vector + // - std::array + // - std::deque + // - std::pair + // - std::tuple + // - std::list + // - std::forward_list + // - std::set + // - std::multiset + // - std::unordered_set * + // - std::unordered_multiset * + // * : not supported in arduino + + template + auto unpack(arr_t& arr) -> + typename std::enable_if::value && !std::is_same::value, bool>::type { + unpackArrayContainerArray(arr); + arr.shrink_to_fit(); + return b_decode_success; + } + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + auto unpack(std::array& arr) -> + typename std::enable_if::value && !std::is_same::value, bool>::type { + const size_t size = unpackArraySize(); + if (N == size) + for (auto& a : arr) unpack(a); + else { + LOG_ERROR(F("array size mismatch:"), size, F("must be"), N); + b_decode_success = false; + } + return b_decode_success; + } + + template + bool unpack(std::deque& arr) { + unpackArrayContainerArray(arr); + arr.shrink_to_fit(); + return b_decode_success; + } + + template + bool unpack(std::pair& arr) { + const size_t size = unpackArraySize(); + if (size == 2) { + unpack(arr.first); + unpack(arr.second); + } else { + LOG_ERROR(F("array size mismatch:"), size, F("must be"), 2); + b_decode_success = false; + } + return b_decode_success; + } + + template + bool unpack(std::tuple& t) { + const size_t size = unpackArraySize(); + if (sizeof...(Args) == size) { + to_tuple(t); + } else { + LOG_ERROR(F("array size mismatch:"), size, F("must be"), sizeof...(Args)); + b_decode_success = false; + } + return b_decode_success; + } + + template + bool unpack(std::list& arr) { + unpackArrayContainerArray(arr); + return b_decode_success; + } + + template + bool unpack(std::forward_list& arr) { + const size_t arr_size = std::distance(arr.begin(), arr.end()); + const size_t size = unpackArraySize(); + if (size == 0) { + LOG_ERROR(F("array size mismatch:"), size, F("must be"), arr_size); + b_decode_success = false; + } else if (arr_size == size) + for (auto& a : arr) unpack(a); + else { + arr.clear(); + for (size_t a = 0; a < size; ++a) { + T t; + unpack(t); + arr.emplace_after(std::next(arr.before_begin(), a), t); + } + } + return b_decode_success; + } + + template + bool unpack(std::set& arr) { + unpackArrayContainerSet(arr); + return b_decode_success; + } + + template + bool unpack(std::multiset& arr) { + unpackArrayContainerSet(arr); + return b_decode_success; + } + + template + bool unpack(std::unordered_set& arr) { + unpackArrayContainerSet(arr); + return b_decode_success; + } + + template + bool unpack(std::unordered_multiset& arr) { + unpackArrayContainerSet(arr); + return b_decode_success; + } + +#endif // Do not have libstdc++11 + + // ---------- MAP format family ---------- + // - std::map + // - std::multimap + // - std::unordered_map * + // - std::unordered_multimap * + // * : not supported in arduino + + template + bool unpack(map_t& mp) { + unpackMapContainer(mp); + return b_decode_success; + } + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + bool unpack(std::multimap& mp) { + unpackMapContainer(mp); + return b_decode_success; + } + + template + bool unpack(std::unordered_map& mp) { + unpackMapContainer(mp); + return b_decode_success; + } + + template + bool unpack(std::unordered_multimap& mp) { + unpackMapContainer(mp); + return b_decode_success; + } + +#endif // Do not have libstdc++11 + + // ---------- EXT format family ---------- + + bool unpack(object::ext& e) { + e = unpackExt(); + return b_decode_success; + } + + // ---------- TIMESTAMP format family ---------- + + bool unpack(object::timespec& t) { + t = unpackTimestamp(); + return b_decode_success; + } + + // ---------- CUSTOM format ---------- + + template + auto unpack(C& c) -> typename std::enable_if::value, bool>::type { + c.from_msgpack(*this); + return b_decode_success; + } + + // ---------- Array/Map Size format ---------- + + bool unpack(arr_size_t& t) { + t = arr_size_t(unpackArraySize()); + return b_decode_success; + } + + bool unpack(map_size_t& t) { + t = map_size_t(unpackMapSize()); + return b_decode_success; + } + + ///////////////////////////////////////////////////// + // ---------- msgpack types abstraction ---------- // + /////////////////////////////////////////............ + + // ---------- INT format family ---------- + + template + auto unpackUInt() -> typename std::enable_if< + std::is_arithmetic::value && std::is_integral::value && !std::is_same::value + && !std::is_same::type, char*>::value && !std::is_signed::value, + T>::type { + MSGPACK_DECODABLE_CHECK(T); + switch (getType()) { + case Type::UINT7: + return (T)unpackUInt7(); + case Type::UINT8: + return (T)unpackUInt8(); + case Type::UINT16: + return (T)unpackUInt16(); + case Type::UINT32: + return (T)unpackUInt32(); + case Type::UINT64: + return (T)unpackUInt64(); + default: + LOG_ERROR("type error"); + return type_error(); + } + } + + template + auto unpackInt() -> typename std::enable_if< + std::is_arithmetic::value && std::is_integral::value && !std::is_same::value + && !std::is_same::type, char*>::value && std::is_signed::value, + T>::type { + MSGPACK_DECODABLE_CHECK(T); + switch (getType()) { + case Type::INT5: + return (T)unpackInt5(); + case Type::INT8: + return (T)unpackInt8(); + case Type::INT16: + return (T)unpackInt16(); + case Type::INT32: + return (T)unpackInt32(); + case Type::INT64: + return (T)unpackInt64(); + case Type::UINT7: + return (T)unpackUInt7(); + case Type::UINT8: + return uint_to_int(unpackUInt8()); + case Type::UINT16: + return uint_to_int(unpackUInt16()); + case Type::UINT32: + return uint_to_int(unpackUInt32()); + case Type::UINT64: + return uint_to_int(unpackUInt64()); + default: + LOG_ERROR("type error"); + return type_error(); + } + } + + // ---------- FLOAT format family ---------- + + template + auto unpackFloat() -> + typename std::enable_if::value && std::is_floating_point::value, T>::type { + MSGPACK_DECODABLE_CHECK(T); + switch (getType()) { + case Type::UINT7: + return (T)unpackUInt7(); + case Type::UINT8: + return (T)unpackUInt8(); + case Type::UINT16: + return (T)unpackUInt16(); + case Type::UINT32: + return (T)unpackUInt32(); + case Type::UINT64: + return (T)unpackUInt64(); + case Type::INT5: + return (T)unpackInt5(); + case Type::INT8: + return (T)unpackInt8(); + case Type::INT16: + return (T)unpackInt16(); + case Type::INT32: + return (T)unpackInt32(); + case Type::INT64: + return (T)unpackInt64(); + case Type::FLOAT32: + return (T)unpackFloat32(); + case Type::FLOAT64: + return (T)unpackFloat64(); + default: + LOG_ERROR("type error"); + return type_error(); + } + } + + // ---------- STR format family ---------- + + str_t unpackString() { + MSGPACK_DECODABLE_CHECK(str_t); + switch (getType()) { + case Type::STR5: + return unpackStringUnchecked5(); + case Type::STR8: + return unpackStringUnchecked8(); + case Type::STR16: + return unpackStringUnchecked16(); + case Type::STR32: + return unpackStringUnchecked32(); + default: + LOG_ERROR("type error"); + return type_error(); + } + } + + // ---------- BIN format family ---------- + + template + auto unpackBinary() -> + typename std::enable_if::value || std::is_same::value, bin_t>::type { + MSGPACK_DECODABLE_CHECK(bin_t); + switch (getType()) { + case Type::BIN8: + return unpackBinaryUnchecked8(); + case Type::BIN16: + return unpackBinaryUnchecked16(); + case Type::BIN32: + return unpackBinaryUnchecked32(); + default: + LOG_ERROR("type error"); + return type_error>(); + } + } + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + auto unpackBinary() -> typename std:: + enable_if::value || std::is_same::value, std::array>::type { + using t = std::array; + MSGPACK_DECODABLE_CHECK(t); + switch (getType()) { + case Type::BIN8: + return unpackBinaryUnchecked8(); + case Type::BIN16: + return unpackBinaryUnchecked16(); + case Type::BIN32: + return unpackBinaryUnchecked32(); + default: + LOG_ERROR("type error"); + return type_error>(); + } + } + +#endif // Do not have libstdc++11 + + // ---------- ARRAY format family ---------- + + size_t unpackArraySize() { + MSGPACK_DECODABLE_CHECK(size_t); + switch (getType()) { + case Type::ARRAY4: + return unpackArraySizeUnchecked4(); + case Type::ARRAY16: + return unpackArraySizeUnchecked16(); + case Type::ARRAY32: + return unpackArraySizeUnchecked32(); + default: + LOG_ERROR("type error"); + return type_error(); + } + } + + // ---------- MAP format family ---------- + + size_t unpackMapSize() { + MSGPACK_DECODABLE_CHECK(size_t); + switch (getType()) { + case Type::MAP4: + return unpackMapSizeUnchecked4(); + case Type::MAP16: + return unpackMapSizeUnchecked16(); + case Type::MAP32: + return unpackMapSizeUnchecked32(); + default: + LOG_ERROR("type error"); + return type_error(); + } + } + + // ---------- EXT format family ---------- + + object::ext unpackExt() { + MSGPACK_DECODABLE_CHECK(object::ext); + switch (getType()) { + case Type::FIXEXT1: + return unpackFixExtUnchecked1(); + case Type::FIXEXT2: + return unpackFixExtUnchecked2(); + case Type::FIXEXT4: + return unpackFixExtUnchecked4(); + case Type::FIXEXT8: + return unpackFixExtUnchecked8(); + case Type::FIXEXT16: + return unpackFixExtUnchecked16(); + case Type::EXT8: + return unpackExtUnchecked8(); + case Type::EXT16: + return unpackExtUnchecked16(); + case Type::EXT32: + return unpackExtUnchecked32(); + default: + LOG_ERROR("type error"); + return type_error(); + } + } + + // ---------- TIMESTAMP format family ---------- + + object::timespec unpackTimestamp() { + // because only timestamp has mutiple condition to satisfy, + // used isTimestampXX() instead of switch + type tag + MSGPACK_DECODABLE_CHECK(object::timespec); + if (isTimestamp32()) + return unpackTimestampUnchecked32(); + else if (isTimestamp64()) + return unpackTimestampUnchecked64(); + else if (isTimestamp96()) + return unpackTimestampUnchecked96(); + else { + LOG_ERROR("type error"); + return type_error(); + } + } + + ////////////////////////////////////////////////////// + // ---------- msgpack types with checker ---------- // + ////////////////////////////////////////////////////// + + // ---------- NIL format family ---------- + + bool unpackNil() { + MSGPACK_DECODABLE_CHECK(bool); + if (isNil()) + return unpackNilUnchecked(); + else + return type_error(Type::NIL); + } + + // ---------- BOOL format family ---------- + + bool unpackBool() { + MSGPACK_DECODABLE_CHECK(bool); + if (isBool()) + return unpackBoolUnchecked(); + else + return type_error(Type::BOOL); + } + + // ---------- INT format family ---------- + + uint8_t unpackUInt7() { + MSGPACK_DECODABLE_CHECK(uint8_t); + if (isUInt7()) + return unpackUIntUnchecked7(); + else + return type_error(Type::UINT7); + } + + uint8_t unpackUInt8() { + MSGPACK_DECODABLE_CHECK(uint8_t); + if (isUInt8()) + return unpackUIntUnchecked8(); + else + return type_error(Type::UINT8); + } + + uint16_t unpackUInt16() { + MSGPACK_DECODABLE_CHECK(uint16_t); + if (isUInt16()) + return unpackUIntUnchecked16(); + else + return type_error(Type::UINT16); + } + + uint32_t unpackUInt32() { + MSGPACK_DECODABLE_CHECK(uint32_t); + if (isUInt32()) + return unpackUIntUnchecked32(); + else + return type_error(Type::UINT32); + } + + uint64_t unpackUInt64() { + MSGPACK_DECODABLE_CHECK(uint64_t); + if (isUInt64()) + return unpackUIntUnchecked64(); + else + return type_error(Type::UINT64); + } + + int8_t unpackInt5() { + MSGPACK_DECODABLE_CHECK(int8_t); + if (isInt5()) + return unpackIntUnchecked5(); + else + return type_error(Type::INT5); + } + + int8_t unpackInt8() { + MSGPACK_DECODABLE_CHECK(int8_t); + if (isInt8()) + return unpackIntUnchecked8(); + else + return type_error(Type::INT8); + } + + int16_t unpackInt16() { + MSGPACK_DECODABLE_CHECK(int16_t); + if (isInt16()) + return unpackIntUnchecked16(); + else + return type_error(Type::INT16); + } + + int32_t unpackInt32() { + MSGPACK_DECODABLE_CHECK(int32_t); + if (isInt32()) + return unpackIntUnchecked32(); + else + return type_error(Type::INT32); + } + + int64_t unpackInt64() { + MSGPACK_DECODABLE_CHECK(int64_t); + if (isInt64()) + return unpackIntUnchecked64(); + else + return type_error(Type::INT64); + } + + // ---------- FLOAT format family ---------- + + float unpackFloat32() { + MSGPACK_DECODABLE_CHECK(float); + if (isFloat32()) + return unpackFloatUnchecked32(); + else + return type_error(Type::FLOAT32); + } + + double unpackFloat64() { + MSGPACK_DECODABLE_CHECK(double); +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + if (isFloat64()) + return unpackFloatUnchecked64(); + else + return type_error(Type::FLOAT64); +#else + if (isFloat32() || isFloat64()) + return unpackFloat32(); // AVR does not support double + else + return type_error(Type::FLOAT64); +#endif + } + + // ---------- STR format family ---------- + + str_t unpackString5() { + MSGPACK_DECODABLE_CHECK(str_t); + if (isStr5()) + return unpackStringUnchecked5(); + else + return type_error(Type::STR5); + } + + str_t unpackString8() { + MSGPACK_DECODABLE_CHECK(str_t); + if (isStr8()) + return unpackStringUnchecked8(); + else + return type_error(Type::STR8); + } + + str_t unpackString16() { + str_t str(""); + MSGPACK_DECODABLE_CHECK(str_t); + if (isStr16()) + return unpackStringUnchecked16(); + else + return type_error(Type::STR16); + } + + str_t unpackString32() { + MSGPACK_DECODABLE_CHECK(str_t); + if (isStr32()) + return unpackStringUnchecked32(); + else + return type_error(Type::STR32); + } + + // ---------- BIN format family ---------- + + template + auto unpackBinary8() -> + typename std::enable_if::value || std::is_same::value, bin_t>::type { + MSGPACK_DECODABLE_CHECK(bin_t); + if (isBin8()) + return unpackBinaryUnchecked8(); + else + return type_error>(Type::BIN8); + } + + template + auto unpackBinary16() -> + typename std::enable_if::value || std::is_same::value, bin_t>::type { + MSGPACK_DECODABLE_CHECK(bin_t); + if (isBin16()) + return unpackBinaryUnchecked16(); + else + return type_error>(Type::BIN16); + } + + template + auto unpackBinary32() -> + typename std::enable_if::value || std::is_same::value, bin_t>::type { + MSGPACK_DECODABLE_CHECK(bin_t); + if (isBin32()) + return unpackBinaryUnchecked32(); + else + return type_error>(Type::BIN32); + } + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + auto unpackBinary8() -> typename std:: + enable_if::value || std::is_same::value, std::array>::type { + using t = std::array; + MSGPACK_DECODABLE_CHECK(t); + if (isBin8()) + return unpackBinaryUnchecked8(); + else + return type_error>(Type::BIN8); + } + + template + auto unpackBinary16() -> typename std:: + enable_if::value || std::is_same::value, std::array>::type { + using t = std::array; + MSGPACK_DECODABLE_CHECK(t); + if (isBin16()) + return unpackBinaryUnchecked16(); + else + return type_error>(Type::BIN16); + } + + template + auto unpackBinary32() -> typename std:: + enable_if::value || std::is_same::value, std::array>::type { + using t = std::array; + MSGPACK_DECODABLE_CHECK(t); + if (isBin32()) + return unpackBinaryUnchecked32(); + else + return type_error>(Type::BIN32); + } + +#endif // Do not have libstdc++11 + + // ---------- ARRAY format family ---------- + + size_t unpackArraySize4() { + MSGPACK_DECODABLE_CHECK(size_t); + if (isArray4()) + return unpackArraySizeUnchecked4(); + else + return type_error(Type::ARRAY4); + } + + size_t unpackArraySize16() { + MSGPACK_DECODABLE_CHECK(size_t); + if (isArray16()) + return unpackArraySizeUnchecked16(); + else + return type_error(Type::ARRAY16); + } + + size_t unpackArraySize32() { + MSGPACK_DECODABLE_CHECK(size_t); + if (isArray32()) + return unpackArraySizeUnchecked32(); + else + return type_error(Type::ARRAY32); + } + + // ---------- MAP format family ---------- + + size_t unpackMapSize4() { + MSGPACK_DECODABLE_CHECK(size_t); + if (isMap4()) + return unpackMapSizeUnchecked4(); + else + return type_error(Type::MAP4); + } + + size_t unpackMapSize16() { + MSGPACK_DECODABLE_CHECK(size_t); + if (isMap16()) + return unpackMapSizeUnchecked16(); + else + return type_error(Type::MAP16); + } + + size_t unpackMapSize32() { + MSGPACK_DECODABLE_CHECK(size_t); + if (isMap32()) + return unpackMapSizeUnchecked32(); + else + return type_error(Type::MAP32); + } + + // ---------- EXT format family ---------- + + object::ext unpackFixExt1() { + MSGPACK_DECODABLE_CHECK(object::ext); + if (isFixExt1()) + return unpackFixExtUnchecked1(); + else + return type_error(Type::FIXEXT1); + } + + object::ext unpackFixExt2() { + MSGPACK_DECODABLE_CHECK(object::ext); + if (isFixExt2()) + return unpackFixExtUnchecked2(); + else + return type_error(Type::FIXEXT2); + } + + object::ext unpackFixExt4() { + MSGPACK_DECODABLE_CHECK(object::ext); + if (isFixExt4()) + return unpackFixExtUnchecked4(); + else + return type_error(Type::FIXEXT4); + } + + object::ext unpackFixExt8() { + MSGPACK_DECODABLE_CHECK(object::ext); + if (isFixExt8()) + return unpackFixExtUnchecked8(); + else + return type_error(Type::FIXEXT8); + } + + object::ext unpackFixExt16() { + MSGPACK_DECODABLE_CHECK(object::ext); + if (isFixExt16()) + return unpackFixExtUnchecked16(); + else + return type_error(Type::FIXEXT16); + } + + object::ext unpackExt8() { + MSGPACK_DECODABLE_CHECK(object::ext); + if (isExt8()) + return unpackExtUnchecked8(); + else + return type_error(Type::EXT8); + } + + object::ext unpackExt16() { + MSGPACK_DECODABLE_CHECK(object::ext); + if (isExt16()) + return unpackExtUnchecked16(); + else + return type_error(Type::EXT16); + } + + object::ext unpackExt32() { + MSGPACK_DECODABLE_CHECK(object::ext); + if (isExt32()) + return unpackExtUnchecked32(); + else + return type_error(Type::EXT32); + } + + // ---------- TIMESTAMP format family ---------- + + object::timespec unpackTimestamp32() { + MSGPACK_DECODABLE_CHECK(object::timespec); + if (isTimestamp32()) + return unpackTimestampUnchecked32(); + else + return type_error(Type::TIMESTAMP32); + } + + object::timespec unpackTimestamp64() { + MSGPACK_DECODABLE_CHECK(object::timespec); + if (isTimestamp64()) + return unpackTimestampUnchecked64(); + else + return type_error(Type::TIMESTAMP64); + } + + object::timespec unpackTimestamp96() { + MSGPACK_DECODABLE_CHECK(object::timespec); + if (isTimestamp96()) + return unpackTimestampUnchecked96(); + else + return type_error(Type::TIMESTAMP96); + } + + ///////////////////////////////////////////////////////// + // ---------- msgpack types without checker ---------- // + ///////////////////////////////////////////////////////// + + // ---------- NIL format family ---------- + + bool unpackNilUnchecked() { + ++curr_index; + return true; + } + + // ---------- BOOL format family ---------- + + bool unpackBoolUnchecked() { + return (bool)(getRawBytes(curr_index++, 0) & (uint8_t)BitMask::BOOL); + } + + // ---------- INT format family ---------- + + uint8_t unpackUIntUnchecked7() { + return (uint8_t)(getRawBytes(curr_index++, 0) & (uint8_t)BitMask::UINT7); + } + + uint8_t unpackUIntUnchecked8() { + return getRawBytes(curr_index++, 1); + } + + uint16_t unpackUIntUnchecked16() { + return getRawBytes(curr_index++, 1); + } + + uint32_t unpackUIntUnchecked32() { + return getRawBytes(curr_index++, 1); + } + + uint64_t unpackUIntUnchecked64() { + return getRawBytes(curr_index++, 1); + } + + int8_t unpackIntUnchecked5() { + return (int8_t)getRawBytes(curr_index++, 0); + } + + int8_t unpackIntUnchecked8() { + return getRawBytes(curr_index++, 1); + } + + int16_t unpackIntUnchecked16() { + return getRawBytes(curr_index++, 1); + } + + int32_t unpackIntUnchecked32() { + return getRawBytes(curr_index++, 1); + } + + int64_t unpackIntUnchecked64() { + return getRawBytes(curr_index++, 1); + } + + // ---------- FLOAT format family ---------- + + float unpackFloatUnchecked32() { + return getRawBytes(curr_index++, 1); + } + + double unpackFloatUnchecked64() { +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + return getRawBytes(curr_index++, 1); +#else + return unpackFloatUnchecked32(); // AVR does not support double +#endif + } + + // ---------- STR format family ---------- + + str_t unpackStringUnchecked5() { + str_t str; + uint8_t size = getRawBytes(curr_index, 0) & (uint8_t)BitMask::STR5; + for (uint8_t c = 0; c < size; ++c) str += getRawBytes(curr_index, c + 1); + ++curr_index; + return str; + } + + str_t unpackStringUnchecked8() { + str_t str; + uint8_t size = getRawBytes(curr_index, 1); + for (uint8_t c = 0; c < size; ++c) str += getRawBytes(curr_index, c + 1 + sizeof(uint8_t)); + ++curr_index; + return str; + } + + str_t unpackStringUnchecked16() { + str_t str; + uint16_t size = getRawBytes(curr_index, 1); + for (uint16_t c = 0; c < size; ++c) str += getRawBytes(curr_index, c + 1 + sizeof(uint16_t)); + ++curr_index; + return str; + } + + str_t unpackStringUnchecked32() { + str_t str; + uint32_t size = getRawBytes(curr_index, 1); + for (uint32_t c = 0; c < size; ++c) str += getRawBytes(curr_index, c + 1 + sizeof(uint32_t)); + ++curr_index; + return str; + } + + // ---------- BIN format family ---------- + + template + auto unpackBinaryUnchecked8() -> + typename std::enable_if::value || std::is_same::value, bin_t>::type { + bin_t data; + uint8_t size = getRawBytes(curr_index, 1); + for (uint8_t v = 0; v < size; ++v) data.emplace_back(getRawBytes(curr_index, v + 1 + sizeof(uint8_t))); + ++curr_index; + return data; + } + + template + auto unpackBinaryUnchecked16() -> + typename std::enable_if::value || std::is_same::value, bin_t>::type { + bin_t data; + uint16_t size = getRawBytes(curr_index, 1); + for (uint16_t v = 0; v < size; ++v) + data.emplace_back(getRawBytes(curr_index, v + 1 + sizeof(uint16_t))); + ++curr_index; + return data; + } + + template + auto unpackBinaryUnchecked32() -> + typename std::enable_if::value || std::is_same::value, bin_t>::type { + bin_t data; + uint32_t size = getRawBytes(curr_index, 1); + for (uint32_t v = 0; v < size; ++v) + data.emplace_back(getRawBytes(curr_index, v + 1 + sizeof(uint32_t))); + ++curr_index; + return data; + } + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + auto unpackBinaryUnchecked8() -> typename std:: + enable_if::value || std::is_same::value, std::array>::type { + std::array data; + uint8_t size = getRawBytes(curr_index, 1); + for (uint8_t v = 0; v < size; ++v) data[v] = getRawBytes(curr_index, v + 1 + sizeof(uint8_t)); + ++curr_index; + return data; + } + + template + auto unpackBinaryUnchecked16() -> typename std:: + enable_if::value || std::is_same::value, std::array>::type { + std::array data; + uint16_t size = getRawBytes(curr_index, 1); + for (uint16_t v = 0; v < size; ++v) data[v] = getRawBytes(curr_index, v + 1 + sizeof(uint16_t)); + ++curr_index; + return data; + } + + template + auto unpackBinaryUnchecked32() -> typename std:: + enable_if::value || std::is_same::value, std::array>::type { + std::array data; + uint32_t size = getRawBytes(curr_index, 1); + for (uint32_t v = 0; v < size; ++v) data[v] = getRawBytes(curr_index, v + 1 + sizeof(uint32_t)); + ++curr_index; + return data; + } + +#endif // Do not have libstdc++11 + + // ---------- ARRAY format family ---------- + + size_t unpackArraySizeUnchecked4() { + return (size_t)((getRawBytes(curr_index++, 0) & (uint8_t)BitMask::ARRAY4)); + } + + size_t unpackArraySizeUnchecked16() { + return (size_t)getRawBytes(curr_index++, 1); + } + + size_t unpackArraySizeUnchecked32() { + return (size_t)getRawBytes(curr_index++, 1); + } + + // ---------- MAP format family ---------- + + size_t unpackMapSizeUnchecked4() { + return (size_t)((getRawBytes(curr_index++, 0) & (uint8_t)BitMask::MAP4)); + } + + size_t unpackMapSizeUnchecked16() { + return (size_t)getRawBytes(curr_index++, 1); + } + + size_t unpackMapSizeUnchecked32() { + return (size_t)getRawBytes(curr_index++, 1); + } + + // ---------- EXT format family ---------- + + object::ext unpackFixExtUnchecked1() { + int8_t ext_type = getRawBytes(curr_index, 1); + uint8_t* ptr = getRawBytePtr(curr_index++, 2); + return object::ext(ext_type, ptr, 1); + } + + object::ext unpackFixExtUnchecked2() { + int8_t ext_type = getRawBytes(curr_index, 1); + uint8_t* ptr = getRawBytePtr(curr_index++, 2); + return object::ext(ext_type, ptr, 2); + } + + object::ext unpackFixExtUnchecked4() { + int8_t ext_type = getRawBytes(curr_index, 1); + uint8_t* ptr = getRawBytePtr(curr_index++, 2); + return object::ext(ext_type, ptr, 4); + } + + object::ext unpackFixExtUnchecked8() { + int8_t ext_type = getRawBytes(curr_index, 1); + uint8_t* ptr = getRawBytePtr(curr_index++, 2); + return object::ext(ext_type, ptr, 8); + } + + object::ext unpackFixExtUnchecked16() { + int8_t ext_type = getRawBytes(curr_index, 1); + uint8_t* ptr = getRawBytePtr(curr_index++, 2); + return object::ext(ext_type, ptr, 16); + } + + object::ext unpackExtUnchecked8() { + uint8_t size = getRawBytes(curr_index, 1); + int8_t ext_type = getRawBytes(curr_index, 2); + uint8_t* ptr = getRawBytePtr(curr_index++, 3); + return object::ext(ext_type, ptr, size); + } + + object::ext unpackExtUnchecked16() { + uint16_t size = getRawBytes(curr_index, 1); + int8_t ext_type = getRawBytes(curr_index, 3); + uint8_t* ptr = getRawBytePtr(curr_index++, 4); + return object::ext(ext_type, ptr, size); + } + + object::ext unpackExtUnchecked32() { + uint32_t size = getRawBytes(curr_index, 1); + int8_t ext_type = getRawBytes(curr_index, 5); + uint8_t* ptr = getRawBytePtr(curr_index++, 6); + return object::ext(ext_type, ptr, size); + } + + // ---------- TIMESTAMP format family ---------- + + object::timespec unpackTimestampUnchecked32() { + object::timespec ts; + ts.tv_nsec = 0; + ts.tv_sec = getRawBytes(curr_index++, 2); + return ts; + } + + object::timespec unpackTimestampUnchecked64() { + object::timespec ts; + uint64_t data64 = getRawBytes(curr_index++, 2); + ts.tv_nsec = data64 >> 34; + ts.tv_sec = data64 & 0x00000003ffffffffL; + return ts; + } + + object::timespec unpackTimestampUnchecked96() { + object::timespec ts; + ts.tv_nsec = getRawBytes(curr_index, 3); + ts.tv_sec = getRawBytes(curr_index++, 7); + return ts; + } + + ///////////////////////////////////////// + // ---------- type checkers ---------- // + ///////////////////////////////////////// + + // ---------- NIL format family ---------- + // - N/A + + template + auto unpackable(const T& value) const -> + typename std::enable_if::value, bool>::type { + (void)value; + return isNil(); + } + + // ---------- BOOL format family ---------- + // - bool + + template + auto unpackable(const T& value) const -> typename std::enable_if::value, bool>::type { + (void)value; + return isBool(); + } + + // ---------- INT format family ---------- + // - char (signed/unsigned) + // - ints (signed/unsigned) + + template + auto unpackable(const T&) const -> typename std::enable_if< + std::is_arithmetic::value && !std::is_floating_point::value && !std::is_same::value + && !std::is_same::type, char*>::value && !std::is_signed::value, + bool>::type { + if (isUInt7()) + return sizeof(T) >= sizeof(uint8_t); + else if (isUInt8()) + return sizeof(T) >= sizeof(uint8_t); + else if (isUInt16()) + return sizeof(T) >= sizeof(uint16_t); + else if (isUInt32()) + return sizeof(T) >= sizeof(uint32_t); + else if (isUInt64()) + return sizeof(T) >= sizeof(uint64_t); + else + return false; + } + + template + auto unpackable(const T&) const -> typename std::enable_if< + std::is_arithmetic::value && !std::is_floating_point::value && !std::is_same::value + && !std::is_same::type, char*>::value && std::is_signed::value, + bool>::type { + if (isInt5()) + return sizeof(T) >= sizeof(int8_t); + else if (isInt8()) + return sizeof(T) >= sizeof(int8_t); + else if (isInt16()) + return sizeof(T) >= sizeof(int16_t); + else if (isInt32()) + return sizeof(T) >= sizeof(int32_t); + else if (isInt64()) + return sizeof(T) >= sizeof(int64_t); + else if (isUInt7()) + return sizeof(T) >= sizeof(int8_t); + else if (isUInt8()) + return sizeof(T) >= sizeof(int8_t); + else if (isUInt16()) + return sizeof(T) >= sizeof(int16_t); + else if (isUInt32()) + return sizeof(T) >= sizeof(int32_t); + else if (isUInt64()) + return sizeof(T) >= sizeof(int64_t); + else + return false; + } + + // ---------- FLOAT format family ---------- + // - float + // - double + + template + auto unpackable(const T&) const -> + typename std::enable_if::value && std::is_floating_point::value, bool>::type { + switch (getType()) { + case Type::UINT7: + case Type::UINT8: + case Type::UINT16: + case Type::UINT32: + case Type::UINT64: + case Type::INT5: + case Type::INT8: + case Type::INT16: + case Type::INT32: + case Type::INT64: + case Type::FLOAT32: + case Type::FLOAT64: + return true; + default: + return false; + } + } + + // ---------- STRING format family ---------- + // - char* + // - char[] + // - std::string + + bool unpackable(const str_t& str) const { + (void)str; + return isStr(); + } + + // ---------- BIN format family ---------- + // - unsigned char* + // - unsigned char[] + // - std::vector + // - std::vector + // - std::array + // - std::array + + template + auto unpackable(const bin_t& bin) const -> + typename std::enable_if::value || std::is_same::value, bool>::type { + (void)bin; + return isBin(); + } + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + auto unpackable(const std::array& bin) const -> + typename std::enable_if::value || std::is_same::value, bool>::type { + (void)bin; + return isBin(); + } + +#endif // Do not have libstdc++11 + + // ---------- ARRAY format family ---------- + // - T[] + // - std::vector + // - std::array + // - std::deque + // - std::pair + // - std::tuple + // - std::list + // - std::forward_list + // - std::set + // - std::unordered_set + // - std::multiset + // - std::unordered_multiset + + template + auto unpackable(const arr_t& arr) const -> + typename std::enable_if::value && !std::is_same::value, bool>::type { + (void)arr; + return isArray(); + } + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + auto unpackable(const std::array& arr) const -> + typename std::enable_if::value && !std::is_same::value, bool>::type { + (void)arr; + return isArray(); + } + + template + bool unpackable(const std::deque& arr) const { + (void)arr; + return isArray(); + } + + template + bool unpackable(const std::pair& arr) const { + (void)arr; + return isArray(); + } + + template + bool unpackable(const std::tuple& arr) const { + (void)arr; + return isArray(); + } + + template + bool unpackable(const std::list& arr) const { + (void)arr; + return isArray(); + } + + template + bool unpackable(const std::forward_list& arr) const { + (void)arr; + return isArray(); + } + + template + bool unpackable(const std::set& arr) const { + (void)arr; + return isArray(); + } + + template + bool unpackable(const std::unordered_set& arr) const { + (void)arr; + return isArray(); + } + + template + bool unpackable(const std::multiset& arr) const { + (void)arr; + return isArray(); + } + + template + bool unpackable(std::unordered_multiset& arr) const { + (void)arr; + return isArray(); + } + +#endif // Do not have libstdc++11 + + // ---------- MAP format family ---------- + // - std::map + // - std::multimap + // - std::unordered_map * + // - std::unordered_multimap * + // * : not supported in arduino + + template + bool unpackable(const map_t& mp) const { + (void)mp; + return isMap(); + } + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + + template + bool unpackable(const std::multimap& mp) const { + (void)mp; + return isMap(); + } + + template + bool unpackable(const std::unordered_map& mp) const { + (void)mp; + return isMap(); + } + + template + bool unpackable(const std::unordered_multimap& mp) const { + (void)mp; + return isMap(); + } + +#endif // Do not have libstdc++11 + + // ---------- EXT format family ---------- + + bool unpackable(const object::ext& e) const { + (void)e; + return isFixExt() || isExt(); + } + + // ---------- TIMESTAMP format family ---------- + + bool unpackable(const object::timespec& t) const { + (void)t; + return isTimestamp(); + } + + ///////////////////////////////////////////////// + // ---------- msgpack type checkers ---------- // + ///////////////////////////////////////////////// + + bool isNil() const { + return getType() == Type::NIL; + } + bool isBool() const { + return getType() == Type::BOOL; + } + bool isUInt7() const { + return getType() == Type::UINT7; + } + bool isUInt8() const { + return getType() == Type::UINT8; + } + bool isUInt16() const { + return getType() == Type::UINT16; + } + bool isUInt32() const { + return getType() == Type::UINT32; + } + bool isUInt64() const { + return getType() == Type::UINT64; + } + bool isUInt() const { + return isUInt7() || isUInt8() || isUInt16() || isUInt32() || isUInt64(); + } + bool isInt5() const { + return getType() == Type::INT5; + } + bool isInt8() const { + return getType() == Type::INT8; + } + bool isInt16() const { + return getType() == Type::INT16; + } + bool isInt32() const { + return getType() == Type::INT32; + } + bool isInt64() const { + return getType() == Type::INT64; + } + bool isInt() const { + return isInt5() || isInt8() || isInt16() || isInt32() || isInt64(); + } + bool isFloat32() const { + return getType() == Type::FLOAT32; + } + bool isFloat64() const { + return getType() == Type::FLOAT64; + } + bool isStr5() const { + return getType() == Type::STR5; + } + bool isStr8() const { + return getType() == Type::STR8; + } + bool isStr16() const { + return getType() == Type::STR16; + } + bool isStr32() const { + return getType() == Type::STR32; + } + bool isStr() const { + return isStr5() || isStr8() || isStr16() || isStr32(); + } + bool isBin8() const { + return getType() == Type::BIN8; + } + bool isBin16() const { + return getType() == Type::BIN16; + } + bool isBin32() const { + return getType() == Type::BIN32; + } + bool isBin() const { + return isBin8() || isBin16() || isBin32(); + } + bool isArray4() const { + return getType() == Type::ARRAY4; + } + bool isArray16() const { + return getType() == Type::ARRAY16; + } + bool isArray32() const { + return getType() == Type::ARRAY32; + } + bool isArray() const { + return isArray4() || isArray16() || isArray32(); + } + bool isMap4() const { + return getType() == Type::MAP4; + } + bool isMap16() const { + return getType() == Type::MAP16; + } + bool isMap32() const { + return getType() == Type::MAP32; + } + bool isMap() const { + return isMap4() || isMap16() || isMap32(); + } + bool isFixExt1() const { + return getType() == Type::FIXEXT1; + } + bool isFixExt2() const { + return getType() == Type::FIXEXT2; + } + bool isFixExt4() const { + return getType() == Type::FIXEXT4; + } + bool isFixExt8() const { + return getType() == Type::FIXEXT8; + } + bool isFixExt16() const { + return getType() == Type::FIXEXT16; + } + bool isFixExt() const { + return isFixExt1() || isFixExt2() || isFixExt4() || isFixExt8() || isFixExt16(); + } + bool isExt8() const { + return getType() == Type::EXT8; + } + bool isExt16() const { + return getType() == Type::EXT16; + } + bool isExt32() const { + return getType() == Type::EXT32; + } + bool isExt() const { + return isExt8() || isExt16() || isExt32(); + } + bool isTimestamp32() const { + return (getType() == Type::TIMESTAMP32) && (getRawBytes(curr_index, 1) == -1); + } + bool isTimestamp64() const { + return (getType() == Type::TIMESTAMP64) && (getRawBytes(curr_index, 1) == -1); + } + bool isTimestamp96() const { + return (getType() == Type::TIMESTAMP96) && (getRawBytes(curr_index, 2) == -1) + && (getRawBytes(curr_index, 1) == 12); + } + bool isTimestamp() const { + return isTimestamp32() || isTimestamp64() || isTimestamp96(); + } + + Type getType() const { + return getType(curr_index); + } + + private: + template + DataType getRawBytes(const size_t idx, const size_t offset) const { + if (idx >= indices.size()) { + LOG_ERROR(F("index overrun: idx"), idx, F("must be <"), indices.size()); + return DataType(); + } + DataType data; + const auto size = sizeof(DataType); + for (uint8_t b = 0; b < size; ++b) { + uint8_t distance = size - 1 - b; + auto index = indices[idx] + offset + distance; + ((uint8_t*)&data)[b] = raw_data[index]; + } + return data; + } + + uint8_t* getRawBytePtr(const size_t idx, const size_t offset) const { + if (idx >= indices.size()) { + LOG_ERROR(F("index overrun: idx"), idx, F("must be <"), indices.size()); + return nullptr; + } + auto index = indices[idx] + offset; + return raw_data + index; + } + + Type getType(const size_t idx) const { + if (idx >= indices.size()) { + LOG_ERROR(F("index overrun: idx"), idx, F("must be <"), indices.size()); + return Type::NA; + } + + uint8_t raw = getRawBytes(idx, 0); + if (raw < (uint8_t)Type::MAP4) + return Type::UINT7; + else if (raw < (uint8_t)Type::ARRAY4) + return Type::MAP4; + else if (raw < (uint8_t)Type::STR5) + return Type::ARRAY4; + else if (raw < (uint8_t)Type::NIL) + return Type::STR5; + else if (raw == (uint8_t)Type::NIL) + return Type::NIL; + else if (raw == (uint8_t)Type::NA) + return Type::NA; + else if (raw < (uint8_t)Type::BIN8) + return Type::BOOL; + else if (raw < (uint8_t)Type::INT5) + return (Type)raw; + else + return Type::INT5; + } + + size_t getElementSize(size_t i) const { + Type type = getType(i); + switch (type) { + // size of ARRAY & MAP is size of OBJECTs + // so the size from header to first object is returned + case Type::NIL: + case Type::BOOL: + case Type::UINT7: + case Type::INT5: + case Type::ARRAY4: + case Type::MAP4: + return 1; + case Type::UINT8: + case Type::INT8: + return 2; + case Type::UINT16: + case Type::INT16: + case Type::ARRAY16: + case Type::MAP16: + case Type::FIXEXT1: + return 3; + case Type::FIXEXT2: + return 4; + case Type::UINT32: + case Type::INT32: + case Type::FLOAT32: + case Type::ARRAY32: + case Type::MAP32: + return 5; + case Type::FIXEXT4: // includes case Type::TIMESTAMP32: + return 6; + case Type::UINT64: + case Type::INT64: + case Type::FLOAT64: + return 9; + case Type::FIXEXT8: // includes case Type::TIMESTAMP64: + return 10; + case Type::FIXEXT16: + return 18; + case Type::STR5: + return (getRawBytes(i, 0) & (uint8_t)BitMask::STR5) + 1; + case Type::STR8: + case Type::BIN8: + return getRawBytes(i, 1) + sizeof(uint8_t) + 1; + case Type::STR16: + case Type::BIN16: + return (size_t)getRawBytes(i, 1) + sizeof(uint16_t) + 1; + case Type::STR32: + case Type::BIN32: + return (size_t)getRawBytes(i, 1) + sizeof(uint32_t) + 1; + case Type::EXT8: // includes case Type::TIMESTAMP96: + return (size_t)getRawBytes(i, 1) + sizeof(uint8_t) + 1 + 1; + case Type::EXT16: + return (size_t)getRawBytes(i, 1) + sizeof(uint16_t) + 1 + 1; + case Type::EXT32: + return (size_t)getRawBytes(i, 1) + sizeof(uint32_t) + 1 + 1; + default: + LOG_ERROR(F("undefined type:"), (int)type); + return 0; + } + } + + template + T type_error(const Type type = Type::NA) { + if (type == Type::NA) + LOG_ERROR(F("unknown type in index"), curr_index, F(": type byte"), (int)getType()); + else + LOG_ERROR( + F("unpack type mimatch in index"), + curr_index, + F(": type byte"), + (int)getType(), + F("must be"), + (int)type); + b_decode_success = false; + ++curr_index; + return T(); + } + + template + auto uint_to_int(const U value) -> typename std::enable_if< + std::is_arithmetic::value && std::is_integral::value && !std::is_same::value + && !std::is_same::type, char*>::value && std::is_signed::value, + T>::type { + if ((sizeof(T) > sizeof(V)) || (value <= (U)std::numeric_limits::max())) + return (T)value; + else + return T(); + } + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + template