Skip to content

# MessagePack

Glaze ships with first–class MessagePack support. You can read and write payloads using the same reflection metadata that drives JSON, BEVE, and TOML so there is no extra boilerplate.

## Specification Compliance

Glaze implements the MessagePack specification (2.0), providing full support for:

Feature | Description
--- | ---
Core types | nil, bool, integers, floats, strings, binary, arrays, maps
Extension types | Generic `ext` support and the standard timestamp extension
Timestamp extension | Type -1 per the MessagePack spec, all three formats (32, 64, 96 bit)

This ensures interoperability with MessagePack implementations in other languages (Python, Ruby, Go, JavaScript, etc.).

    #include "glaze/msgpack.hpp"

    struct point
    {
       double x{};
       double y{};
    };

    template <> struct glz::meta<point>
    {
       using T = point;
       static constexpr auto value = object(&T::x, &T::y);
    };

    point p{.x = 4.2, .y = 1.3};
    std::string buffer{};

    // Write MessagePack into a std::string
    auto write_error = glz::write_msgpack(p, buffer);
    if (write_error) {
       const auto message = glz::format_error(write_error, buffer);
       // handle serialization failure
    }

    // Read the buffer back
    point decoded{};
    auto read_error = glz::read_msgpack(decoded, std::string_view{buffer});
    if (read_error) {
       const auto message = glz::format_error(read_error, buffer);
       // handle parse problems
    }

`glz::write_msgpack` and `glz::read_msgpack` mirror the JSON helpers:

- They work with any reflected type, STL container, or custom specialization.
- Overloads exist for output buffers (`std::string`, `std::vector<std::byte>`, `std::vector<char>`, etc.).
- Write functions return `error_ctx` with `count` field for bytes written. Read functions also return `error_ctx`.
- Check for success with `if (!ec)` (falsy = success, truthy = error).

## `glz::msgpack::ext`

MessagePack “ext” values are supported through `glz::msgpack::ext`. The struct stores the type code and raw payload bytes. You can embed it inside your objects or work with it directly.

    glz::msgpack::ext payload{5, {std::byte{0xCA}, std::byte{0xFE}}};
    auto encoded = glz::write_msgpack(payload);

    if (encoded) {
       auto decoded = glz::read_msgpack<glz::msgpack::ext>(std::string_view{encoded.value()});
       // decoded->type == 5, decoded->data == {0xCA, 0xFE}
    }

## Timestamp Extension

Glaze supports the MessagePack timestamp extension (type -1), which is the standard way to represent timestamps in MessagePack. This enables interoperability with other MessagePack implementations.

### `glz::msgpack::timestamp`

The `glz::msgpack::timestamp` struct stores seconds since the Unix epoch and optional nanoseconds:

    glz::msgpack::timestamp ts{1700000000, 123456789}; // seconds, nanoseconds
    std::string buffer;
    auto ec = glz::write_msgpack(ts, buffer);

    glz::msgpack::timestamp decoded;
    ec = glz::read_msgpack(decoded, buffer);
    // decoded.seconds == 1700000000
    // decoded.nanoseconds == 123456789

### Timestamp Formats

Glaze automatically chooses the most compact format when writing:

Format | Condition | Wire Size
--- | --- | ---
Timestamp 32 | `nsec == 0` and `sec` fits in `uint32` | 6 bytes
Timestamp 64 | `sec` fits in 34 bits (0 to 17179869183) | 10 bytes
Timestamp 96 | All other cases (including negative seconds) | 15 bytes

When reading, all three formats are supported regardless of how the data was written.

### `std::chrono::system_clock::time_point`

Glaze provides automatic conversion between `std::chrono::system_clock::time_point` and the MessagePack timestamp extension:

    #include <chrono>

    // Write a time_point
    auto now = std::chrono::system_clock::now();
    std::string buffer;
    glz::write_msgpack(now, buffer);

    // Read back to time_point
    std::chrono::system_clock::time_point decoded;
    glz::read_msgpack(decoded, buffer);

This allows seamless serialization of C++ time points with nanosecond precision.

### Timestamps in Structs

Timestamps work naturally as struct members:

    struct event {
       std::string name;
       glz::msgpack::timestamp time;
    };

    event e{"user_login", {1700000000, 0}};
    auto encoded = glz::write_msgpack(e);

## Binary Buffers

Glaze automatically emits the compact MessagePack `bin*` tags for contiguous byte buffers such as `std::vector<std::byte>`, `std::vector<unsigned char>`, or `std::span<std::byte>`. Reads follow the same path, so you can round–trip arbitrary binary payloads without extra adapters.

    std::vector<std::byte> blob{std::byte{0x00}, std::byte{0x7F}};
    auto encoded = glz::write_msgpack(blob);

    std::vector<std::byte> restored;
    auto ec = glz::read_msgpack(restored, std::string_view{encoded.value()});

## Partial Write and Partial Read

The generic options system works for MessagePack as well. You can serialize only a subset of fields by leveraging JSON pointers, or short–circuit deserialization with `.partial_read`:

    struct user {
       std::string name;
       int64_t id{};
       bool active{};
    };

    template <> struct glz::meta<user>
    {
       using T = user;
       static constexpr auto value = object(&T::name, &T::id, &T::active);
    };

    static constexpr auto partial = glz::json_ptrs("/name");

    user u{.name = "Bailey", .id = 42, .active = true};
    auto encoded = glz::write_msgpack<partial>(u);

    user decoded{.id = 99};
    auto ec = glz::read_msgpack(decoded, std::string_view{encoded.value()});
    // decoded.name is populated, id remains 99, active stays default.

Partial reading reuses the `glz::opts` struct:

    auto ec = glz::read<glz::opts{.format = glz::MSGPACK, .partial_read = true}>(decoded, std::string_view{payload});

Glaze updates only the members present in the MessagePack map and stops parsing once every tracked field has been visited, which is helpful when you only need a few keys from a large document.

## File Helpers

Use `glz::write_file_msgpack` and `glz::read_file_msgpack` when you want to work with files. The helpers reuse the same error reporting pipeline as JSON/TOML:

    std::vector<std::byte> buffer{};
    glz::write_file_msgpack(u, "user.bin", buffer);

    user restored{};
    glz::read_file_msgpack(restored, "user.bin", buffer);

Because the helpers accept any contiguous buffer, you can reuse the same `std::vector<std::byte>` for both operations to avoid extra allocations.

## Low-Level API

When you need more control, the generic `glz::read`/`glz::write` templates accept `opts` with `.format = glz::MSGPACK`. This unlocks advanced scenarios such as:

- Disabling unknown-key errors (`.error_on_unknown_keys = false`)
- Structs-as-arrays (`.structs_as_arrays = true`)
- Enabling partial reads as shown earlier

    static constexpr glz::opts permissive{.format = glz::MSGPACK, .error_on_unknown_keys = false};
    user flexible{};
    glz::read<permissive>(flexible, std::string_view{payload});

The MessagePack reader/writer plug into the same core pipeline as the JSON and BEVE backends, so hooks such as custom read/write functions or wrappers continue to work.