{"id":21274167,"url":"https://github.com/endurodave/messageserialize","last_synced_at":"2025-07-11T12:34:20.697Z","repository":{"id":230447090,"uuid":"779401886","full_name":"endurodave/MessageSerialize","owner":"endurodave","description":"C++ Object Binary Serialize and Deserialize","archived":false,"fork":false,"pushed_at":"2025-04-07T16:32:30.000Z","size":76,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-07T17:38:34.458Z","etag":null,"topics":["binary","communication-protocol","cpp","cross-platform","encoder-decoder","messagepack","messagepack-serializer","serializer","transport"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/endurodave.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-03-29T18:52:45.000Z","updated_at":"2025-04-07T16:32:34.000Z","dependencies_parsed_at":null,"dependency_job_id":"bff8e9e5-8d33-4fd1-aaf7-f7d47abfd29c","html_url":"https://github.com/endurodave/MessageSerialize","commit_stats":null,"previous_names":["endurodave/messageserialize"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/endurodave/MessageSerialize","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FMessageSerialize","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FMessageSerialize/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FMessageSerialize/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FMessageSerialize/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/endurodave","download_url":"https://codeload.github.com/endurodave/MessageSerialize/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FMessageSerialize/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264806823,"owners_count":23666690,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["binary","communication-protocol","cpp","cross-platform","encoder-decoder","messagepack","messagepack-serializer","serializer","transport"],"created_at":"2024-11-21T09:19:12.322Z","updated_at":"2025-07-11T12:34:20.665Z","avatar_url":"https://github.com/endurodave.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"![License MIT](https://img.shields.io/github/license/BehaviorTree/BehaviorTree.CPP?color=blue)\n[![conan Ubuntu](https://github.com/endurodave/MessageSerialize/actions/workflows/cmake_ubuntu.yml/badge.svg)](https://github.com/endurodave/MessageSerialize/actions/workflows/cmake_ubuntu.yml)\n[![conan Ubuntu](https://github.com/endurodave/MessageSerialize/actions/workflows/cmake_clang.yml/badge.svg)](https://github.com/endurodave/MessageSerialize/actions/workflows/cmake_clang.yml)\n[![conan Windows](https://github.com/endurodave/MessageSerialize/actions/workflows/cmake_windows.yml/badge.svg)](https://github.com/endurodave/MessageSerialize/actions/workflows/cmake_windows.yml)\n\n# Message Serialize\nA simple serialize class to binary serialize and deserialize C++ objects.\n\n## Introduction\n\nThe `serialize` class can be used to serialize and deserialize structured data into a binary format suitable for communication protocols, data storage, and inter-process communication (IPC). The STL Input/Output Stream Library is used to hold the encoded octet streams in readiness for transmission or parsing. A single header file `serialize.h` implements the serialize functionality. Any C++14 or higher compiler is supported.\n\n1. **Purpose:** The serialize class is designed to provide a framework for serializing and deserializing C++ objects into binary format, enabling data interchange between different systems or storage mediums.\n\n1. **Interface:** The class provides an abstract interface `serialize::I` that all serialized user-defined classes must implement. This interface consists of `write` and `read` functions, responsible for writing class members to an output stream and reading them from an input stream, respectively.\n\n1. **Supported Data Types:** The serialize class supports various C++ data types for serialization, including literals, strings (`std::string` and `std::wstring`), vectors, maps, lists, sets, and character arrays (`char[]`).\n\n1. **Endianness Handling:** It provides functions to determine the endianness of the system and read/write endianness information from/to streams.\n\n1. **Error Handling:** The class handles various parsing errors, such as type mismatch, stream errors, string length exceeding limits, and invalid input, ensuring robustness during serialization and deserialization.\n\n1. **Protocol Evolution:** It supports parsing objects with additional or missing data fields, allowing flexibility in the data interchange protocol. Extra data received after parsing an object is discarded, and missing data fields are ignored, facilitating protocol evolution without breaking compatibility.\n\n1. **Serialization and Deserialization Functions:** The class provides specialized read and write functions for different data types, including user-defined types, strings, vectors (including `std::vector\u003cbool\u003e`), and character arrays.\n\n## Purpose \n\nNumerous libraries are available for encoding transport payloads. The `serialize` class has a few advantages: \n\n1. **Simplicity:** A single header file with less than 1000 source lines of code.\n\n1. **Ease of Use:** Inherit from `serialize::I` and override `write()` and `read()`; that's it. \n\n1. **Flexibility:** Serialize built-in or user defined data types, and STL data containers (e.g. `std::list`, `std::string`).\n\n1. **Efficiency:** Binary encoding efficiently serializes/deserializes messages using STL streams.\n\n1. **Robustness:** Automatic endianness handling and parser resilience to message changes over time. \n\n## Example Usage\n\nC++ objects inherit from `serialize::I` to support serialize and deserialize. Methods for serialization (`write`) and deserialization (`read`) are implemented to write/read each object member. `Date` shows a simple example.\n\n```cpp\nclass Date : public serialize::I\n{\npublic:\n    Date() = default;\n    Date(int16_t d, int16_t m, int16_t y) : day(d), month(m), year(y) {}\n    virtual ~Date() = default;\n\n    virtual ostream\u0026 write(serialize\u0026 ms, ostream\u0026 os) override\n    {\n        ms.write(os, day);\n        ms.write(os, month);\n        ms.write(os, year);\n        return os;\n    }\n\n    virtual istream\u0026 read(serialize\u0026 ms, istream\u0026 is) override\n    {\n        ms.read(is, day);\n        ms.read(is, month);\n        ms.read(is, year);\n        return is;\n    }\n\n    int16_t day = 0;\n    int16_t month = 0;\n    int16_t year = 0;\n};\n```\n\n`Log` uses `Date` as a data member. \n\n```cpp\nclass Log : public serialize::I\n{\npublic:\n    enum class LogType : uint16_t { ALARM, DIAGNOSTIC };\n\n    virtual ostream\u0026 write(serialize\u0026 ms, ostream\u0026 os) override\n    {\n        ms.write(os, logType);\n        ms.write(os, date);\n        return os;\n    }\n\n    virtual istream\u0026 read(serialize\u0026 ms, istream\u0026 is) override\n    {\n        ms.read(is, logType);\n        ms.read(is, date);\n        return is;\n    }\n\n    LogType logType = LogType::ALARM;\n    Date date;\n};\n```\n\n`AlarmLog` inherits from the `Log` base class showing how complex data hierarchies can be constructed.\n\n```cpp\nclass AlarmLog : public Log\n{\npublic:\n    virtual ostream\u0026 write(serialize\u0026 ms, ostream\u0026 os) override\n    {\n        Log::write(ms, os);\n        ms.write(os, alarmValue);\n        return os;\n    }\n\n    virtual istream\u0026 read(serialize\u0026 ms, istream\u0026 is) override\n    {\n        Log::read(ms, is);\n        ms.read(is, alarmValue);\n        return is;\n    }\n\n    uint32_t alarmValue = 0;\n};\n```\n\nThe code snippet below demonstrates creating, transmitting, and receiving a binary-encoded `AlarmLog` message. At runtime, serialize and deserialize an `AlarmLog` object to a `std::stringstream`. Check stream `good()` to ensure parsing success before using object data. The data bytes within the stream can be sent as a communication protocol payload, for instance.\n\n```cpp\n// Create an AlarmLog message\nAlarmLog writeLog;\nwriteLog.date.day = 31;\nwriteLog.date.month = 12;\nwriteLog.date.year = 2024;\nwriteLog.logType = Log::LogType::ALARM;\nwriteLog.alarmValue = 0x11223344;\n\n// Write log to stringstream\nstringstream ss(ios::in | ios::out | ios::binary);\nms.write(ss, writeLog);\n\n// Copy outgoing stringstream data bytes to a raw character buffer for transmission\nauto size = ss.tellp();\nchar* binary_buf = static_cast\u003cchar*\u003e(malloc(size));\nss.rdbuf()-\u003esgetn(binary_buf, size);\n\n// Alternatively, don't copy and just send data directly from stringstream \n//extern void SendMsg(const void* data, uint32_t dataSize);\n//SendMsg(ss.str().c_str(), ss.tellp());\n\n// TODO: Send binary_buf to somewhere\n// TODO: Receive binary_buf from somewhere\n\n// Convert incoming bytes to a stream for parsing\nistringstream is(std::string(binary_buf, size), std::ios::in | std::ios::binary);\n\n// Read log from stringstream\nAlarmLog readLog;\nms.read(is, readLog);\nif (is.good())\n{\n    // Parse succeeded; use readLog values\n    cout \u003c\u003c \"AlarmLog Parse Success! \" \u003c\u003c readLog.alarmValue \u003c\u003c endl;\n}\nelse\n{\n    cout \u003c\u003c \"ERROR: AlarmLog\" \u003c\u003c endl;\n}\n\nfree(binary_buf);\n```\n\n`AllData` shows more examples using C++ container classes such as `std::list`, character arrays, and more.\n\n```cpp\nclass AllData : public serialize::I\n{\npublic:\n    AllData() = default;\n    virtual ~AllData()\n    {\n        for (auto\u0026 ptr : dataVectorPtr) \n            delete ptr;\n        dataVectorPtr.clear();\n\n        for (auto\u0026 ptr : dataListPtr)\n            delete ptr;\n        dataListPtr.clear();\n\n        for (auto\u0026 ptr : dataMapPtr)\n            delete ptr.second;\n        dataMapPtr.clear();\n\n        for (auto\u0026 ptr : dataSetPtr)\n            delete ptr;\n        dataSetPtr.clear();\n    }\n\n    AllData(const AllData\u0026 other) = delete;\n    AllData\u0026 operator=(const AllData\u0026 other) = delete;\n\n    virtual ostream\u0026 write(serialize\u0026 ms, ostream\u0026 os)\n    {\n        ms.write(os, valueInt);\n        ms.write(os, valueInt8);\n        ms.write(os, valueInt16);\n        ms.write(os, valueInt32);\n        ms.write(os, valueInt64);\n        ms.write(os, valueUInt8);\n        ms.write(os, valueUInt16);\n        ms.write(os, valueUInt32);\n        ms.write(os, valueUInt64);\n        ms.write(os, valueFloat);\n        ms.write(os, valueDouble);\n        ms.write(os, color);\n        ms.write(os, cstr);\n        ms.write(os, str);\n        ms.write(os, wstr);\n        ms.write(os, dataVectorBool);\n        ms.write(os, dataVectorFloat);\n        ms.write(os, dataVectorPtr);\n        ms.write(os, dataVectorValue);\n        ms.write(os, dataVectorInt);\n        ms.write(os, dataListPtr);\n        ms.write(os, dataListValue);\n        ms.write(os, dataListInt);\n        ms.write(os, dataMapPtr);\n        ms.write(os, dataMapValue);\n        ms.write(os, dataMapInt);\n        ms.write(os, dataSetPtr);\n        ms.write(os, dataSetValue);\n        ms.write(os, dataSetInt);\n        return os;\n    }\n\n    virtual istream\u0026 read(serialize\u0026 ms, istream\u0026 is)\n    {\n        ms.read(is, valueInt);\n        ms.read(is, valueInt8);\n        ms.read(is, valueInt16);\n        ms.read(is, valueInt32);\n        ms.read(is, valueInt64);\n        ms.read(is, valueUInt8);\n        ms.read(is, valueUInt16);\n        ms.read(is, valueUInt32);\n        ms.read(is, valueUInt64);\n        ms.read(is, valueFloat);\n        ms.read(is, valueDouble);\n        ms.read(is, color);\n        ms.read(is, cstr);\n        ms.read(is, str);\n        ms.read(is, wstr);\n        ms.read(is, dataVectorBool);\n        ms.read(is, dataVectorFloat);\n        ms.read(is, dataVectorPtr);\n        ms.read(is, dataVectorValue);\n        ms.read(is, dataVectorInt);\n        ms.read(is, dataListPtr);\n        ms.read(is, dataListValue);\n        ms.read(is, dataListInt);\n        ms.read(is, dataMapPtr);\n        ms.read(is, dataMapValue);\n        ms.read(is, dataMapInt);\n        ms.read(is, dataSetPtr);\n        ms.read(is, dataSetValue);\n        ms.read(is, dataSetInt);\n        return is;\n    }\n\n    int valueInt = 4;\n    int8_t valueInt8 = 8;\n    int16_t valueInt16 = 16;\n    int32_t valueInt32 = 32;\n    int64_t valueInt64 = 64;\n    uint8_t valueUInt8 = 8;\n    uint16_t valueUInt16 = 16;\n    uint32_t valueUInt32 = 32;\n    uint64_t valueUInt64 = 64;\n    float valueFloat = 1.23f;\n    double valueDouble = 3.21;\n    Color color = Color::BLUE;\n    char cstr[32] = { 0 };\n    string str;\n    wstring wstr;\n    vector\u003cbool\u003e dataVectorBool;\n    vector\u003cfloat\u003e dataVectorFloat;\n    vector\u003cDate*\u003e dataVectorPtr;\n    vector\u003cDate\u003e dataVectorValue;\n    vector\u003cint\u003e dataVectorInt;\n    list\u003cDate*\u003e dataListPtr;\n    list\u003cDate\u003e dataListValue;\n    list\u003cint\u003e dataListInt;\n    map\u003cint, Date*\u003e dataMapPtr;\n    map\u003cint, Date\u003e dataMapValue;\n    map\u003cint, int\u003e dataMapInt;\n    set\u003cDate*\u003e dataSetPtr;\n    set\u003cDate\u003e dataSetValue;\n    set\u003cint\u003e dataSetInt;\n};\n```\n\nSee `main.cpp` for more examples. \n\n## Error Handling \nErrors and parser progress are monitored by registering a callback function pointer.  \n\n```cpp\n#include \"serialize.h\"\n#include \u003csstream\u003e\n#include \u003cfstream\u003e\n#include \u003ciostream\u003e\n\nusing namespace std;\n\n// Message serializer instance\nstatic serialize ms;\n\nvoid ErrorHandlerCallback(serialize::ParsingError error, int line, const char* file)\n{\n    // Output parsing error message\n    cout \u003c\u003c \"PARSE ERROR: \" \u003c\u003c file \u003c\u003c \" \" \u003c\u003c line \u003c\u003c \" \" \u003c\u003c static_cast\u003cint\u003e(error) \u003c\u003c endl;\n}\n\nvoid ParseHandlerCallback(const type_info\u0026 typeId, size_t size)\n{\n    // Output parser progress\n    cout \u003c\u003c typeId.name() \u003c\u003c \" \" \u003c\u003c size \u003c\u003c endl;\n}\n\nint main(void)\n{\n    ms.setErrorHandler(\u0026ErrorHandlerCallback);\n    ms.setParseHandler(\u0026ParseHandlerCallback);\n\n    //...\n\n    return 0;\n}\n```\nCheck for errors with `getLastError()` to get the last parse error code.\n\n## Protocol Evolution\n\nThe `serialize` class parsing handles deserializing objects even if the number of object data fields don’t match the ones known at compile time due to protocol changes. \n\nFor instance, assume protocol version 1 data structure:\n\n```cpp\n// DataV1 is a version 1 data structure\nclass DataV1 : public serialize::I\n{\npublic:\n    virtual ostream\u0026 write(serialize\u0026 ms, ostream\u0026 os) override\n    {\n        ms.write(os, data);\n        return os;\n    }\n\n    virtual istream\u0026 read(serialize\u0026 ms, istream\u0026 is) override\n    {\n        ms.read(is, data);\n        return is;\n    }\n    int data = 0;\n};\n```\n\nLater, the protocol data structure changes to add one more data member:\n\n```cpp\n// DataV2 is version 2 data structure with a new data member added\nclass DataV2 : public serialize::I\n{\npublic:\n    virtual ostream\u0026 write(serialize\u0026 ms, ostream\u0026 os) override\n    {\n        ms.write(os, data);\n        ms.write(os, dataNew);\n        return os;\n    }\n\n    virtual istream\u0026 read(serialize\u0026 ms, istream\u0026 is) override\n    {\n        ms.read(is, data);\n        ms.read(is, dataNew);\n        return is;\n    }\n\n    int data = 0;\n    int dataNew = 0;    // NEW!\n};\n```\n\nThe `serialize` will not fail if a V1 system receives a V2 data structure, or vice versa. If V1 receives a V2 object, the extra data is not parsed and the bytes are skipped. If a V2 system receives a V1 object, the new V2 object data members are not set since the V1 received object does not contain the newly added V2 data.\n\nFor message protocol resiliency to message changes to work, certain code change rules must adhered to ensure  interoperability with prior protocol iterations. Once a protocol is released, the rules for making updates to the message objects are:\n\n* Do not delete an existing data field. \n* Do not change an existing data field type.\n* Do not change the data field serialize/deserialize order within `read()` and `write()`.\n* Introduce new data fields to the end of a message object.\n\n## Endianness\n\nThe C++ built-in data types are sent big-endian. Multibyte built-in data types are encoded in multiple octets. Each octet is 8-bits. All built-in multibyte data types are byte swapped for endianness by the sender or receiver as necessary based upon the detected CPU endianness. The serialize class automatically performs the byte swapping when marshalling the octet stream. No alignment bytes are added to the octet stream regardless of the built-in data type size. \n\n## Transport Protocol\n\nThe `serialize` binary output stream is typically used for a protocol payload. See the link below for an a compact, C language simple socket-like transport protocol with easy porting to any system.\n\n[Simple Socket Protocol](https://github.com/endurodave/SimpleSocketProtocol)\n\n## Implementation\n\nAll user defined data types inherit from `serialize::I`:\n\n```cpp\nclass serialize\n{\npublic:\n    /// @brief Abstract interface that all serialized user defined classes inherit.\n    class I\n    {\n    public:\n        /// Inheriting class implements the write function. Write each\n        /// class member to the ostream. Write in the same order as read().\n        /// Each level within the hierarchy must implement. Ensure base \n        /// write() implementation is called if necessary. \n        /// @param[in] ms - the message serialize instance\n        /// @param[in] is - the input stream\n        /// @return The input stream\n        virtual std::ostream\u0026 write(serialize\u0026 ms, std::ostream\u0026 os) = 0;\n\n        /// Inheriting class implements the read function. Read each\n        /// class member to the ostream. Read in the same order as write().\n        /// Each level within the hierarchy must implement. Ensure base \n        /// read() implementation is called if necessary. \n        /// @param[in] ms - the message serialize instance\n        /// @param[in] is - the input stream\n        /// @return The input stream\n        virtual std::istream\u0026 read(serialize\u0026 ms, std::istream\u0026 is) = 0;\n    };\n```\n\nNumerous `serialize` overloads handle `write`/`read` of different data types:\n\n```cpp\n// Write APIs\nstd::ostream\u0026 write(std::ostream\u0026 os, std::string\u0026 s) { ... }\n\nstd::ostream\u0026 write (std::ostream\u0026 os, const std::wstring\u0026 s) { ... }\n\ntemplate \u003cclass T\u003e\nstd::ostream\u0026 write(std::ostream\u0026 os, std::vector\u003cT\u003e\u0026 container) { ... }\n\ntemplate \u003cclass K, class V, class P\u003e\nstd::ostream\u0026 write(std::ostream\u0026 os, std::map\u003cK, V, P\u003e\u0026 container) { ... }\n// ...\n\n// Read APIs\nstd::istream\u0026 read (std::istream\u0026 is, std::string\u0026 s) { ... }\n\nstd::istream\u0026 read (std::istream\u0026 is, std::wstring\u0026 s) { ... }\n\ntemplate \u003cclass T\u003e\nstd::istream\u0026 read(std::istream\u0026 is, std::vector\u003cT\u003e\u0026 container) { ... }\n\ntemplate \u003cclass K, class V, class P\u003e\nstd::istream\u0026 read(std::istream\u0026 is, std::map\u003cK, V, P\u003e\u0026 container) { ... }\n// ...\n```\n\n### Encoding\n\nEach data types is prepended with an 8-bit type:\n\n```cpp\nenum class Type \n{\n    UNKNOWN = 0,\n    LITERAL = 1,\n    STRING = 8,\n    WSTRING = 9,\n    VECTOR = 20,\n    MAP = 21,\n    LIST = 22,\n    SET = 23,\n    ENDIAN = 30,\n    USER_DEFINED = 31,\n};\n```\n\n### Primitive Data Type Encoding\n\nThe `struct` definitions below are used to conveying the serialized data memory layout for primitive data types. The structures themselves do not exist within the source code. \n\nFor instance, a `short` is encoded as an 8-bit `Type` followed by 16-bit `short` value.\n\n```cpp\nstruct short_data {\n   Type type = LITERAL;     // 8-bits\n   short s;                 // 16-bits\n};\n```\n\nSimilarly, a `long` encoding is shown below.\n\n```cpp\nstruct long_data {\n   Type type = LITERAL;     // 8-bits\n   long l;                  // 32-bits\n};\n```\n\nAll other numeric primitive data types are encoded similarly (e.g. float, double, unsigned long, ...). Primitive numeric data types are automatically byte swapped to handle endianness.\n\n`char[]` string encoding (null terminated):\n\n```cpp\nstruct char_arr_data {\n   Type type = STRING;      // 8-bits\n   unsigned short size;     // 16-bits, size is strlen() + 1 \n   char str[length];        // size x 8-bits\n};\n```\n\nDo not use arrays of numeric values (e.g. `float[]`). Instead, use STL container classes (e.g. `std::list\u003cfloat\u003e`).\n\n### STL Container Encoding\n\n`xstring` encoding:\n```cpp\nstruct string_data {\n   Type type = STRING;      // 8-bits\n   unsigned short size;     // 16-bits, size is std::string::size()  \n   char str[size];          // size x 8-bits\n};\n```\n\n`xwstring` encoding:\n```cpp\nstruct wstring_data {\n   Type type = WSTRING;     // 8-bits\n   unsigned short size;     // 16-bits, size is std::wstring::size()  \n   wchar_t str[size];       // size x 16-bits\n};\n```\n\n`std::list\u003cT\u003e` encoding:\n```cpp\nstruct list_data {\n   Type type = LIST;        // 8-bits\n   unsigned short size;     // 16-bits, size is std::list::size()\n   T data[size];            // size x sizeof(T) x 8-bits \n};\n```\n\n`std::list\u003cT\u0026\u003e` encoding:\n```cpp\nstruct list_ref_data {\n   Type type = LIST;        // 8-bits\n   unsigned short size;     // 16-bits, size is std::list::size()\n   T data[size];            // size x sizeof(T) bits x 8-bits\n};\n```\n\n`std::list\u003cT*\u003e` encoding:\n```cpp\nstruct list_ptr_data {\n   Type type = LIST;        // 8-bits\n   unsigned short size;     // 16-bits, size is std::list::size()\n   T data[size];            // size x sizeof(T*) x 8-bits\n};\n```\n\nThe `std::map`, `std::set`, `std::vector` all follow a similar binary encoding mechanism to `std::list`. \n\n### User Defined Encoding\n\nAny user defined class that inherits from `serialize::I`. The size of a user defined type depends on the number of octets required to serialize the object (not `sizeof(T)`). The size is the total octet count of all data fields contained within the user defined object instance. \n\n```cpp\nstruct user_defined_data {\n   Type type = USER_DEFINED;    // 8-bits\n   unsigned short size;         // 16-bits, total size of message object octets\n   char data[size];             // size is the number of message object octets serialized\n};\n```\n\nEach user defined object is the aggregate octet count from any combination of:\n\n* Primitive data types\n* Container data types\n* User defined data types\n\nAny complex message object topology using inheritance and/or composition is supported.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fendurodave%2Fmessageserialize","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fendurodave%2Fmessageserialize","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fendurodave%2Fmessageserialize/lists"}