diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f1a2ce..2ee01c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,9 @@ cmake_minimum_required(VERSION 3.13) +add_subdirectory(util) add_subdirectory(w6300) add_subdirectory(debug_log) +add_subdirectory(msgpack) add_library(limen STATIC src/arp.cpp @@ -23,8 +25,10 @@ target_include_directories(limen PUBLIC target_compile_options(limen PRIVATE -Wall -Wextra -Wno-unused-parameter) target_link_libraries(limen PUBLIC + util w6300 debug_log + msgpack pico_stdlib pico_sha256 pico_unique_id diff --git a/msgpack/CMakeLists.txt b/msgpack/CMakeLists.txt new file mode 100644 index 0000000..280924e --- /dev/null +++ b/msgpack/CMakeLists.txt @@ -0,0 +1,7 @@ +add_library(msgpack STATIC msgpack.cpp) + +target_include_directories(msgpack PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +target_compile_options(msgpack PRIVATE -Wall -Wextra -Wno-unused-parameter) + +target_link_libraries(msgpack PUBLIC util) diff --git a/msgpack/msgpack.cpp b/msgpack/msgpack.cpp new file mode 100644 index 0000000..424a443 --- /dev/null +++ b/msgpack/msgpack.cpp @@ -0,0 +1,419 @@ +#include "msgpack.h" + +namespace msgpack { + +result get_body_info(const uint8_t *p, int size) { + if (size < 1) return std::unexpected(error_code::empty); + uint8_t b = p[0]; + + using namespace format; + + if (is_positive_fixint(b)) return body_info{1, 0}; + if (is_negative_fixint(b)) return body_info{1, 0}; + if (is_fixmap(b)) return body_info{1, 0}; + if (is_fixarray(b)) return body_info{1, 0}; + if (is_fixstr(b)) return body_info{1, static_cast(b & 0x1F)}; + + switch (b) { + case NIL: case FALSE: case TRUE: + return body_info{1, 0}; + case NEVER_USED: + return std::unexpected(error_code::invalid); + + case BIN8: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+1, *n}; } + case BIN16: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+2, *n}; } + case BIN32: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+4, *n}; } + + case EXT8: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+1+1, *n}; } + case EXT16: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+2+1, *n}; } + case EXT32: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+4+1, *n}; } + + case FLOAT32: return body_info{1, 4}; + case FLOAT64: return body_info{1, 8}; + case UINT8: return body_info{1, 1}; + case UINT16: return body_info{1, 2}; + case UINT32: return body_info{1, 4}; + case UINT64: return body_info{1, 8}; + case INT8: return body_info{1, 1}; + case INT16: return body_info{1, 2}; + case INT32: return body_info{1, 4}; + case INT64: return body_info{1, 8}; + + case FIXEXT1: return body_info{1+1, 1}; + case FIXEXT2: return body_info{1+1, 2}; + case FIXEXT4: return body_info{1+1, 4}; + case FIXEXT8: return body_info{1+1, 8}; + case FIXEXT16: return body_info{1+1, 16}; + + case STR8: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+1, *n}; } + case STR16: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+2, *n}; } + case STR32: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+4, *n}; } + + case ARRAY16: case ARRAY32: + case MAP16: case MAP32: + return body_info{1 + (b == ARRAY16 || b == MAP16 ? 2 : 4), 0}; + + default: + return std::unexpected(error_code::invalid); + } +} + +packer::pack_result packer::pack_nil() { + m_buf.push_back(format::NIL); + return *this; +} + +packer::pack_result packer::pack_bool(bool v) { + m_buf.push_back(v ? format::TRUE : format::FALSE); + return *this; +} + +packer::pack_result packer::pack_uint32_fixed(uint32_t n) { + m_buf.push_back(format::UINT32); + push_big_endian(n); + return *this; +} + +packer::pack_result packer::pack_float(float n) { + m_buf.push_back(format::FLOAT32); + push_big_endian(n); + return *this; +} + +packer::pack_result packer::pack_double(double n) { + m_buf.push_back(format::FLOAT64); + push_big_endian(n); + return *this; +} + +packer::pack_result packer::pack_str(const char *s) { + return pack_str(std::string_view(s)); +} + +packer::pack_result packer::pack_array(size_t n) { + if (n <= 15) { + m_buf.push_back(format::FIXARRAY_MIN | static_cast(n)); + } else if (n <= std::numeric_limits::max()) { + m_buf.push_back(format::ARRAY16); + push_big_endian(static_cast(n)); + } else if (n <= std::numeric_limits::max()) { + m_buf.push_back(format::ARRAY32); + push_big_endian(static_cast(n)); + } else { + return std::unexpected(error_code::overflow); + } + return *this; +} + +packer::pack_result packer::pack_map(size_t n) { + if (n <= 15) { + m_buf.push_back(format::FIXMAP_MIN | static_cast(n)); + } else if (n <= std::numeric_limits::max()) { + m_buf.push_back(format::MAP16); + push_big_endian(static_cast(n)); + } else if (n <= std::numeric_limits::max()) { + m_buf.push_back(format::MAP32); + push_big_endian(static_cast(n)); + } else { + return std::unexpected(error_code::overflow); + } + return *this; +} + +packer::pack_result packer::pack_ext16_header(char type, uint16_t len) { + m_buf.push_back(format::EXT16); + push_big_endian(len); + m_buf.push_back(static_cast(type)); + return *this; +} + +packer::pack_result packer::pack_bin16_header(uint16_t len) { + m_buf.push_back(format::BIN16); + push_big_endian(len); + return *this; +} + +packer::pack_result packer::pack(bool v) { return pack_bool(v); } +packer::pack_result packer::pack(float v) { return pack_float(v); } +packer::pack_result packer::pack(double v) { return pack_double(v); } +packer::pack_result packer::pack(const char *v) { return pack_str(v); } +packer::pack_result packer::pack(std::string_view v) { return pack_str(v); } +packer::pack_result packer::pack(const std::string &v) { return pack_str(v); } +packer::pack_result packer::pack(const std::vector &v) { return pack_bin(v); } + +result parser::next() const { + auto hdr = header_byte(); + if (!hdr) return std::unexpected(hdr.error()); + + if (is_array()) { + auto info = get_body_info(m_p, m_size); + if (!info) return std::unexpected(info.error()); + auto cnt = count(); + if (!cnt) return std::unexpected(cnt.error()); + auto cur = advance(info->header); + if (!cur) return std::unexpected(cur.error()); + for (uint32_t i = 0; i < *cnt; ++i) { + auto n = cur->next(); + if (!n) return std::unexpected(n.error()); + cur = *n; + } + return *cur; + } else if (is_map()) { + auto info = get_body_info(m_p, m_size); + if (!info) return std::unexpected(info.error()); + auto cnt = count(); + if (!cnt) return std::unexpected(cnt.error()); + auto cur = advance(info->header); + if (!cur) return std::unexpected(cur.error()); + for (uint32_t i = 0; i < *cnt; ++i) { + auto k = cur->next(); + if (!k) return std::unexpected(k.error()); + cur = *k; + auto v = cur->next(); + if (!v) return std::unexpected(v.error()); + cur = *v; + } + return *cur; + } else { + auto info = get_body_info(m_p, m_size); + if (!info) return std::unexpected(info.error()); + auto total = info->header + static_cast(info->body); + return advance(total); + } +} + +bool parser::is_nil() const { + auto h = header_byte(); + return h && *h == format::NIL; +} + +bool parser::is_bool() const { + auto h = header_byte(); + return h && (*h == format::TRUE || *h == format::FALSE); +} + +bool parser::is_number() const { + auto h = header_byte(); + if (!h) return false; + uint8_t b = *h; + if (format::is_positive_fixint(b)) return true; + if (format::is_negative_fixint(b)) return true; + return b >= format::FLOAT32 && b <= format::INT64; +} + +bool parser::is_string() const { + auto h = header_byte(); + if (!h) return false; + uint8_t b = *h; + if (format::is_fixstr(b)) return true; + return b == format::STR8 || b == format::STR16 || b == format::STR32; +} + +bool parser::is_binary() const { + auto h = header_byte(); + if (!h) return false; + uint8_t b = *h; + return b == format::BIN8 || b == format::BIN16 || b == format::BIN32; +} + +bool parser::is_ext() const { + auto h = header_byte(); + if (!h) return false; + uint8_t b = *h; + return (b >= format::FIXEXT1 && b <= format::FIXEXT16) || + b == format::EXT8 || b == format::EXT16 || b == format::EXT32; +} + +bool parser::is_array() const { + auto h = header_byte(); + if (!h) return false; + uint8_t b = *h; + if (format::is_fixarray(b)) return true; + return b == format::ARRAY16 || b == format::ARRAY32; +} + +bool parser::is_map() const { + auto h = header_byte(); + if (!h) return false; + uint8_t b = *h; + if (format::is_fixmap(b)) return true; + return b == format::MAP16 || b == format::MAP32; +} + +result parser::get_bool() const { + auto h = header_byte(); + if (!h) return std::unexpected(h.error()); + if (*h == format::TRUE) return true; + if (*h == format::FALSE) return false; + return std::unexpected(error_code::type_error); +} + +result parser::get_string() const { + auto h = header_byte(); + if (!h) return std::unexpected(h.error()); + uint8_t b = *h; + size_t offset, len; + if (format::is_fixstr(b)) { + len = b & 0x1F; + offset = 1; + } else if (b == format::STR8) { + auto n = body_number(m_p, m_size); + if (!n) return std::unexpected(n.error()); + len = *n; offset = 1 + 1; + } else if (b == format::STR16) { + auto n = body_number(m_p, m_size); + if (!n) return std::unexpected(n.error()); + len = *n; offset = 1 + 2; + } else if (b == format::STR32) { + auto n = body_number(m_p, m_size); + if (!n) return std::unexpected(n.error()); + len = *n; offset = 1 + 4; + } else { + return std::unexpected(error_code::type_error); + } + if (static_cast(offset + len) > m_size) { + return std::unexpected(error_code::lack); + } + return std::string_view(reinterpret_cast(m_p + offset), len); +} + +result parser::get_binary_view() const { + auto h = header_byte(); + if (!h) return std::unexpected(h.error()); + uint8_t b = *h; + size_t offset, len; + + if (b == format::BIN8) { + auto n = body_number(m_p, m_size); + if (!n) return std::unexpected(n.error()); + len = *n; offset = 1 + 1; + } else if (b == format::BIN16) { + auto n = body_number(m_p, m_size); + if (!n) return std::unexpected(n.error()); + len = *n; offset = 1 + 2; + } else if (b == format::BIN32) { + auto n = body_number(m_p, m_size); + if (!n) return std::unexpected(n.error()); + len = *n; offset = 1 + 4; + } else { + return std::unexpected(error_code::type_error); + } + if (static_cast(offset + len) > m_size) { + return std::unexpected(error_code::lack); + } + return std::string_view(reinterpret_cast(m_p + offset), len); +} + +result> parser::get_ext() const { + auto h = header_byte(); + if (!h) return std::unexpected(h.error()); + uint8_t b = *h; + int8_t ext_type; + size_t data_offset, data_len; + + switch (b) { + case format::FIXEXT1: ext_type = m_p[1]; data_offset = 2; data_len = 1; break; + case format::FIXEXT2: ext_type = m_p[1]; data_offset = 2; data_len = 2; break; + case format::FIXEXT4: ext_type = m_p[1]; data_offset = 2; data_len = 4; break; + case format::FIXEXT8: ext_type = m_p[1]; data_offset = 2; data_len = 8; break; + case format::FIXEXT16: ext_type = m_p[1]; data_offset = 2; data_len = 16; break; + case format::EXT8: { + auto n = body_number(m_p, m_size); + if (!n) return std::unexpected(n.error()); + ext_type = m_p[2]; data_offset = 3; data_len = *n; + break; + } + case format::EXT16: { + auto n = body_number(m_p, m_size); + if (!n) return std::unexpected(n.error()); + ext_type = m_p[3]; data_offset = 4; data_len = *n; + break; + } + case format::EXT32: { + auto n = body_number(m_p, m_size); + if (!n) return std::unexpected(n.error()); + ext_type = m_p[5]; data_offset = 6; data_len = *n; + break; + } + default: + return std::unexpected(error_code::type_error); + } + if (static_cast(data_offset + data_len) > m_size) { + return std::unexpected(error_code::lack); + } + return std::tuple{ext_type, + std::string_view(reinterpret_cast(m_p + data_offset), data_len)}; +} + +result parser::count() const { + auto h = header_byte(); + if (!h) return std::unexpected(h.error()); + uint8_t b = *h; + + if (format::is_fixarray(b)) return static_cast(b & 0x0F); + if (format::is_fixmap(b)) return static_cast(b & 0x0F); + + switch (b) { + case format::ARRAY16: { auto n = body_number(m_p, m_size); if (!n) return std::unexpected(n.error()); return static_cast(*n); } + case format::ARRAY32: { auto n = body_number(m_p, m_size); if (!n) return std::unexpected(n.error()); return *n; } + case format::MAP16: { auto n = body_number(m_p, m_size); if (!n) return std::unexpected(n.error()); return static_cast(*n); } + case format::MAP32: { auto n = body_number(m_p, m_size); if (!n) return std::unexpected(n.error()); return *n; } + default: + return std::unexpected(error_code::type_error); + } +} + +result parser::first_item() const { + if (!is_array() && !is_map()) return std::unexpected(error_code::type_error); + auto info = get_body_info(m_p, m_size); + if (!info) return std::unexpected(info.error()); + return advance(info->header); +} + +parser parser::operator[](int index) const { + auto cur = first_item(); + if (!cur) return {}; + for (int i = 0; i < index; ++i) { + auto n = cur->next(); + if (!n) return {}; + cur = *n; + } + return *cur; +} + +result unpack(const parser &p, bool &out) { + auto v = p.get_bool(); + if (!v) return std::unexpected(v.error()); + out = *v; + return p.next(); +} + +result unpack(const parser &p, std::string_view &out) { + auto v = p.get_string(); + if (!v) return std::unexpected(v.error()); + out = *v; + return p.next(); +} + +result unpack(const parser &p, std::string &out) { + auto v = p.get_string(); + if (!v) return std::unexpected(v.error()); + out = std::string(v->data(), v->size()); + return p.next(); +} + +result unpack(const parser &p, std::vector &out) { + auto v = p.get_binary_view(); + if (!v) return std::unexpected(v.error()); + out.assign(v->begin(), v->end()); + return p.next(); +} + +result unpack(const parser &p, std::span &out) { + auto v = p.get_binary_view(); + if (!v) return std::unexpected(v.error()); + out = std::span(reinterpret_cast(v->data()), v->size()); + return p.next(); +} + +} // namespace msgpack diff --git a/include/msgpack.h b/msgpack/msgpack.h similarity index 51% rename from include/msgpack.h rename to msgpack/msgpack.h index ae3e331..1a05491 100644 --- a/include/msgpack.h +++ b/msgpack/msgpack.h @@ -1,14 +1,16 @@ #pragma once #include #include -#include #include #include #include #include +#include +#include #include #include #include +#include #include #include "span_writer.h" @@ -102,65 +104,11 @@ result body_number(const uint8_t *p, int size) { } struct body_info { - int header; // bytes before the body (includes format byte + length fields + ext type byte) - uint32_t body; // body size in bytes (0 for containers, computed for variable-length) + int header; + uint32_t body; }; -inline result get_body_info(const uint8_t *p, int size) { - if (size < 1) return std::unexpected(error_code::empty); - uint8_t b = p[0]; - - using namespace format; - - if (is_positive_fixint(b)) return body_info{1, 0}; - if (is_negative_fixint(b)) return body_info{1, 0}; - if (is_fixmap(b)) return body_info{1, 0}; // container - if (is_fixarray(b)) return body_info{1, 0}; // container - if (is_fixstr(b)) return body_info{1, static_cast(b & 0x1F)}; - - switch (b) { - case NIL: case FALSE: case TRUE: - return body_info{1, 0}; - case NEVER_USED: - return std::unexpected(error_code::invalid); - - case BIN8: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+1, *n}; } - case BIN16: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+2, *n}; } - case BIN32: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+4, *n}; } - - case EXT8: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+1+1, *n}; } - case EXT16: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+2+1, *n}; } - case EXT32: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+4+1, *n}; } - - case FLOAT32: return body_info{1, 4}; - case FLOAT64: return body_info{1, 8}; - case UINT8: return body_info{1, 1}; - case UINT16: return body_info{1, 2}; - case UINT32: return body_info{1, 4}; - case UINT64: return body_info{1, 8}; - case INT8: return body_info{1, 1}; - case INT16: return body_info{1, 2}; - case INT32: return body_info{1, 4}; - case INT64: return body_info{1, 8}; - - case FIXEXT1: return body_info{1+1, 1}; - case FIXEXT2: return body_info{1+1, 2}; - case FIXEXT4: return body_info{1+1, 4}; - case FIXEXT8: return body_info{1+1, 8}; - case FIXEXT16: return body_info{1+1, 16}; - - case STR8: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+1, *n}; } - case STR16: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+2, *n}; } - case STR32: { auto n = body_number(p, size); if (!n) return std::unexpected(n.error()); return body_info{1+4, *n}; } - - case ARRAY16: case ARRAY32: - case MAP16: case MAP32: - return body_info{1 + (b == ARRAY16 || b == MAP16 ? 2 : 4), 0}; // container - - default: - return std::unexpected(error_code::invalid); - } -} +result get_body_info(const uint8_t *p, int size); class packer { private: @@ -185,15 +133,8 @@ public: using pack_result = result>; - pack_result pack_nil() { - m_buf.push_back(format::NIL); - return *this; - } - - pack_result pack_bool(bool v) { - m_buf.push_back(v ? format::TRUE : format::FALSE); - return *this; - } + pack_result pack_nil(); + pack_result pack_bool(bool v); template pack_result pack_integer(T n) { @@ -201,7 +142,7 @@ public: if (n >= 0 && n <= 0x7F) { m_buf.push_back(static_cast(n)); } else if (n >= -32 && n < 0) { - m_buf.push_back(static_cast(n)); // negative fixint + m_buf.push_back(static_cast(n)); } else if (n >= std::numeric_limits::min() && n <= std::numeric_limits::max()) { m_buf.push_back(format::INT8); m_buf.push_back(static_cast(n)); @@ -235,23 +176,9 @@ public: return *this; } - pack_result pack_uint32_fixed(uint32_t n) { - m_buf.push_back(format::UINT32); - push_big_endian(n); - return *this; - } - - pack_result pack_float(float n) { - m_buf.push_back(format::FLOAT32); - push_big_endian(n); - return *this; - } - - pack_result pack_double(double n) { - m_buf.push_back(format::FLOAT64); - push_big_endian(n); - return *this; - } + pack_result pack_uint32_fixed(uint32_t n); + pack_result pack_float(float n); + pack_result pack_double(double n); template pack_result pack_str(const Range &r) { @@ -274,9 +201,7 @@ public: return *this; } - pack_result pack_str(const char *s) { - return pack_str(std::string_view(s)); - } + pack_result pack_str(const char *s); template pack_result pack_bin(const Range &r) { @@ -297,48 +222,10 @@ public: return *this; } - pack_result pack_array(size_t n) { - if (n <= 15) { - m_buf.push_back(format::FIXARRAY_MIN | static_cast(n)); - } else if (n <= std::numeric_limits::max()) { - m_buf.push_back(format::ARRAY16); - push_big_endian(static_cast(n)); - } else if (n <= std::numeric_limits::max()) { - m_buf.push_back(format::ARRAY32); - push_big_endian(static_cast(n)); - } else { - return std::unexpected(error_code::overflow); - } - return *this; - } - - pack_result pack_map(size_t n) { - if (n <= 15) { - m_buf.push_back(format::FIXMAP_MIN | static_cast(n)); - } else if (n <= std::numeric_limits::max()) { - m_buf.push_back(format::MAP16); - push_big_endian(static_cast(n)); - } else if (n <= std::numeric_limits::max()) { - m_buf.push_back(format::MAP32); - push_big_endian(static_cast(n)); - } else { - return std::unexpected(error_code::overflow); - } - return *this; - } - - pack_result pack_ext16_header(char type, uint16_t len) { - m_buf.push_back(format::EXT16); - push_big_endian(len); - m_buf.push_back(static_cast(type)); - return *this; - } - - pack_result pack_bin16_header(uint16_t len) { - m_buf.push_back(format::BIN16); - push_big_endian(len); - return *this; - } + pack_result pack_array(size_t n); + pack_result pack_map(size_t n); + pack_result pack_ext16_header(char type, uint16_t len); + pack_result pack_bin16_header(uint16_t len); template pack_result pack_ext(char type, const Range &r) { @@ -377,14 +264,13 @@ public: requires std::is_enum_v pack_result pack(T v) { return pack_integer(static_cast>(v)); } - pack_result pack(bool v) { return pack_bool(v); } - pack_result pack(float v) { return pack_float(v); } - pack_result pack(double v) { return pack_double(v); } - pack_result pack(const char *v) { return pack_str(v); } - pack_result pack(std::string_view v) { return pack_str(v); } - pack_result pack(const std::string &v) { return pack_str(v); } - - pack_result pack(const std::vector &v) { return pack_bin(v); } + pack_result pack(bool v); + pack_result pack(float v); + pack_result pack(double v); + pack_result pack(const char *v); + pack_result pack(std::string_view v); + pack_result pack(const std::string &v); + pack_result pack(const std::vector &v); template requires (!std::is_same_v) @@ -464,210 +350,21 @@ public: return parser(m_p + n, m_size - n); } - result next() const { - auto hdr = header_byte(); - if (!hdr) return std::unexpected(hdr.error()); + result next() const; - if (is_array()) { - auto info = get_body_info(m_p, m_size); - if (!info) return std::unexpected(info.error()); - auto cnt = count(); - if (!cnt) return std::unexpected(cnt.error()); - auto cur = advance(info->header); - if (!cur) return std::unexpected(cur.error()); - for (uint32_t i = 0; i < *cnt; ++i) { - auto n = cur->next(); - if (!n) return std::unexpected(n.error()); - cur = *n; - } - return *cur; - } else if (is_map()) { - auto info = get_body_info(m_p, m_size); - if (!info) return std::unexpected(info.error()); - auto cnt = count(); - if (!cnt) return std::unexpected(cnt.error()); - auto cur = advance(info->header); - if (!cur) return std::unexpected(cur.error()); - for (uint32_t i = 0; i < *cnt; ++i) { - auto k = cur->next(); - if (!k) return std::unexpected(k.error()); - cur = *k; - auto v = cur->next(); - if (!v) return std::unexpected(v.error()); - cur = *v; - } - return *cur; - } else { - auto info = get_body_info(m_p, m_size); - if (!info) return std::unexpected(info.error()); - auto total = info->header + static_cast(info->body); - return advance(total); - } - } + bool is_nil() const; + bool is_bool() const; + bool is_number() const; + bool is_string() const; + bool is_binary() const; + bool is_ext() const; + bool is_array() const; + bool is_map() const; - bool is_nil() const { - auto h = header_byte(); - return h && *h == format::NIL; - } - - bool is_bool() const { - auto h = header_byte(); - return h && (*h == format::TRUE || *h == format::FALSE); - } - - bool is_number() const { - auto h = header_byte(); - if (!h) return false; - uint8_t b = *h; - if (format::is_positive_fixint(b)) return true; - if (format::is_negative_fixint(b)) return true; - return b >= format::FLOAT32 && b <= format::INT64; - } - - bool is_string() const { - auto h = header_byte(); - if (!h) return false; - uint8_t b = *h; - if (format::is_fixstr(b)) return true; - return b == format::STR8 || b == format::STR16 || b == format::STR32; - } - - bool is_binary() const { - auto h = header_byte(); - if (!h) return false; - uint8_t b = *h; - return b == format::BIN8 || b == format::BIN16 || b == format::BIN32; - } - - bool is_ext() const { - auto h = header_byte(); - if (!h) return false; - uint8_t b = *h; - return (b >= format::FIXEXT1 && b <= format::FIXEXT16) || - b == format::EXT8 || b == format::EXT16 || b == format::EXT32; - } - - bool is_array() const { - auto h = header_byte(); - if (!h) return false; - uint8_t b = *h; - if (format::is_fixarray(b)) return true; - return b == format::ARRAY16 || b == format::ARRAY32; - } - - bool is_map() const { - auto h = header_byte(); - if (!h) return false; - uint8_t b = *h; - if (format::is_fixmap(b)) return true; - return b == format::MAP16 || b == format::MAP32; - } - - - result get_bool() const { - auto h = header_byte(); - if (!h) return std::unexpected(h.error()); - if (*h == format::TRUE) return true; - if (*h == format::FALSE) return false; - return std::unexpected(error_code::type_error); - } - - result get_string() const { - auto h = header_byte(); - if (!h) return std::unexpected(h.error()); - uint8_t b = *h; - size_t offset, len; - if (format::is_fixstr(b)) { - len = b & 0x1F; - offset = 1; - } else if (b == format::STR8) { - auto n = body_number(m_p, m_size); - if (!n) return std::unexpected(n.error()); - len = *n; offset = 1 + 1; - } else if (b == format::STR16) { - auto n = body_number(m_p, m_size); - if (!n) return std::unexpected(n.error()); - len = *n; offset = 1 + 2; - } else if (b == format::STR32) { - auto n = body_number(m_p, m_size); - if (!n) return std::unexpected(n.error()); - len = *n; offset = 1 + 4; - } else { - return std::unexpected(error_code::type_error); - } - if (static_cast(offset + len) > m_size) { - return std::unexpected(error_code::lack); - } - return std::string_view(reinterpret_cast(m_p + offset), len); - } - - result get_binary_view() const { - auto h = header_byte(); - if (!h) return std::unexpected(h.error()); - uint8_t b = *h; - size_t offset, len; - - if (b == format::BIN8) { - auto n = body_number(m_p, m_size); - if (!n) return std::unexpected(n.error()); - len = *n; offset = 1 + 1; - } else if (b == format::BIN16) { - auto n = body_number(m_p, m_size); - if (!n) return std::unexpected(n.error()); - len = *n; offset = 1 + 2; - } else if (b == format::BIN32) { - auto n = body_number(m_p, m_size); - if (!n) return std::unexpected(n.error()); - len = *n; offset = 1 + 4; - } else { - return std::unexpected(error_code::type_error); - } - if (static_cast(offset + len) > m_size) { - return std::unexpected(error_code::lack); - } - return std::string_view(reinterpret_cast(m_p + offset), len); - } - - result> get_ext() const { - auto h = header_byte(); - if (!h) return std::unexpected(h.error()); - uint8_t b = *h; - int8_t ext_type; - size_t data_offset, data_len; - - switch (b) { - case format::FIXEXT1: ext_type = m_p[1]; data_offset = 2; data_len = 1; break; - case format::FIXEXT2: ext_type = m_p[1]; data_offset = 2; data_len = 2; break; - case format::FIXEXT4: ext_type = m_p[1]; data_offset = 2; data_len = 4; break; - case format::FIXEXT8: ext_type = m_p[1]; data_offset = 2; data_len = 8; break; - case format::FIXEXT16: ext_type = m_p[1]; data_offset = 2; data_len = 16; break; - case format::EXT8: { - auto n = body_number(m_p, m_size); - if (!n) return std::unexpected(n.error()); - ext_type = m_p[2]; data_offset = 3; data_len = *n; - break; - } - case format::EXT16: { - auto n = body_number(m_p, m_size); - if (!n) return std::unexpected(n.error()); - ext_type = m_p[3]; data_offset = 4; data_len = *n; - break; - } - case format::EXT32: { - auto n = body_number(m_p, m_size); - if (!n) return std::unexpected(n.error()); - ext_type = m_p[5]; data_offset = 6; data_len = *n; - break; - } - default: - return std::unexpected(error_code::type_error); - } - if (static_cast(data_offset + data_len) > m_size) { - return std::unexpected(error_code::lack); - } - return std::tuple{ext_type, - std::string_view(reinterpret_cast(m_p + data_offset), data_len)}; - } + result get_bool() const; + result get_string() const; + result get_binary_view() const; + result> get_ext() const; template result get_number() const { @@ -694,41 +391,9 @@ public: } } - result count() const { - auto h = header_byte(); - if (!h) return std::unexpected(h.error()); - uint8_t b = *h; - - if (format::is_fixarray(b)) return static_cast(b & 0x0F); - if (format::is_fixmap(b)) return static_cast(b & 0x0F); - - switch (b) { - case format::ARRAY16: { auto n = body_number(m_p, m_size); if (!n) return std::unexpected(n.error()); return static_cast(*n); } - case format::ARRAY32: { auto n = body_number(m_p, m_size); if (!n) return std::unexpected(n.error()); return *n; } - case format::MAP16: { auto n = body_number(m_p, m_size); if (!n) return std::unexpected(n.error()); return static_cast(*n); } - case format::MAP32: { auto n = body_number(m_p, m_size); if (!n) return std::unexpected(n.error()); return *n; } - default: - return std::unexpected(error_code::type_error); - } - } - - result first_item() const { - if (!is_array() && !is_map()) return std::unexpected(error_code::type_error); - auto info = get_body_info(m_p, m_size); - if (!info) return std::unexpected(info.error()); - return advance(info->header); - } - - parser operator[](int index) const { - auto cur = first_item(); - if (!cur) return {}; - for (int i = 0; i < index; ++i) { - auto n = cur->next(); - if (!n) return {}; - cur = *n; - } - return *cur; - } + result count() const; + result first_item() const; + parser operator[](int index) const; }; template @@ -750,26 +415,11 @@ result unpack(const parser &p, T &out) { return p.next(); } -inline result unpack(const parser &p, bool &out) { - auto v = p.get_bool(); - if (!v) return std::unexpected(v.error()); - out = *v; - return p.next(); -} - -inline result unpack(const parser &p, std::string_view &out) { - auto v = p.get_string(); - if (!v) return std::unexpected(v.error()); - out = *v; - return p.next(); -} - -inline result unpack(const parser &p, std::string &out) { - auto v = p.get_string(); - if (!v) return std::unexpected(v.error()); - out = std::string(v->data(), v->size()); - return p.next(); -} +result unpack(const parser &p, bool &out); +result unpack(const parser &p, std::string_view &out); +result unpack(const parser &p, std::string &out); +result unpack(const parser &p, std::vector &out); +result unpack(const parser &p, std::span &out); template result unpack(const parser &p, std::array &out) { @@ -780,20 +430,6 @@ result unpack(const parser &p, std::array &out) { return p.next(); } -inline result unpack(const parser &p, std::vector &out) { - auto v = p.get_binary_view(); - if (!v) return std::unexpected(v.error()); - out.assign(v->begin(), v->end()); - return p.next(); -} - -inline result unpack(const parser &p, std::span &out) { - auto v = p.get_binary_view(); - if (!v) return std::unexpected(v.error()); - out = std::span(reinterpret_cast(v->data()), v->size()); - return p.next(); -} - template requires (!std::is_same_v) result unpack(const parser &p, std::vector &out) { diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt new file mode 100644 index 0000000..df3bb83 --- /dev/null +++ b/util/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(util INTERFACE) +target_include_directories(util INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/include/span_writer.h b/util/span_writer.h similarity index 100% rename from include/span_writer.h rename to util/span_writer.h