Glaze C++ Serialization Library

repository·main·Indexed 25 days ago

https://github.com/stephenberry/glaze

A high-performance C++ serialization library for fast JSON and binary data processing. It utilizes compile-time reflection, including support for C++26 P2996, to enable seamless serialization of structs. Supported formats include JSON, BEVE, CBOR, JSONB, BSON, CSV, MessagePack, Stencil/Mustache, TOML 1.1, YAML, and EETF.

Tokens
166.4K
Snippets
481
Records
673
Agent score
83%

What's inside Glaze

  1. Overview of Glaze supported formats

    main

    Glaze is a high-performance C++ serialization library that supports multiple data formats. Each format is provided via a specific header to minimize compilation overhead. Supported formats include:

    • JSON: glaze/json.hpp
    • BEVE (Binary Efficient Versatile Encoding): glaze/beve.hpp
    • CBOR: glaze/json/cbor.hpp
    • JSONB (SQLite Binary JSON): glaze/jsonb.hpp
    • BSON (MongoDB Binary JSON): glaze/bson.hpp
    • CSV: glaze/csv.hpp
    • MessagePack: glaze/msgpack.hpp
    • Stencil/Mustache (string interpolation): glaze/stencil/stencil.hpp
    • TOML 1.1: glaze/toml.hpp
    • YAML: glaze/yaml.hpp
    • EETF (Erlang External Term Format): glaze/eetf.hpp
  2. Identify features requiring ASIO in Glaze

    main

    Glaze's core serialization (JSON/BEVE, CSV/TOML) has no external dependencies. ASIO is only required for networking features:

    FeatureHeaderASIO Required
    JSON/BEVE serializationglaze/glaze.hppNo
    CSV/TOML parsingglaze/csv.hpp, glaze/toml.hppNo
    HTTP Serverglaze/net/http_server.hppYes
    HTTP Clientglaze/net/http_client.hppYes
    WebSocket Clientglaze/net/websocket_client.hppYes
    REPE RPC (asio_server/client)glaze/ext/glaze_asio.hppYes
  3. Glaze core features and requirements

    main

    Glaze is a header-only, extremely fast JSON and reflection library for modern C++. Key features include:

    • Compile-time reflection: Uses pure compile-time reflection for structs (with optional C++26 P2996 backend support).
    • JSON Compliance: Fully JSON RFC 8259 compliant with UTF-8 validation.
    • Performance: Direct-to-memory serialization/deserialization and compile-time maps with constant time lookups.
    • Binary Support: Includes MessagePack serialization with binary extension and partial read/write support.
    • Low Overhead: Can be compiled with -fno-exceptions and -fno-rtti as it does not require exceptions or runtime type information.
  4. Use the Glaze API for shared library interfaces

    main
    Glaze provides a generic interface system designed for shared libraries. It uses a single header (glaze/api/api.hpp) to allow type-safe access to data structures and member functions across shared library boundaries using JSON pointer syntax. This enables cross-compilation access with compile-time type checking and supports both JSON and BEVE (Binary Efficient Versatile Encoding) serialization.
  5. Understand Glaze reflection concepts

    main

    Glaze uses C++ compile-time reflection to handle data structures. It distinguishes between types that are automatically reflected (aggregates) and types that have explicit metadata provided via glz::meta specializations.

    • reflectable<T>: A concept that identifies aggregate types that can be automatically reflected without any glz::meta specialization.
    • has_reflect<T>: A concept that detects if glz::reflect<T> can be instantiated. This is a broader check that includes aggregate types, types with glz::meta specializations (like glaze_object_t, glaze_array_t, glaze_enum_t), and readable map types (e.g., std::map).
  6. Get started with YAML in Glaze

    main

    Glaze provides a YAML 1.2 reader and writer. To use YAML support, you must include glaze/yaml.hpp as it is not included in the main glaze/glaze.hpp header. You can reuse the same glz::meta specializations used for JSON.

    Use glz::write_yaml to serialize a structure to a string and glz::read_yaml to deserialize a string into a structure. Both functions return an error_ctx which is truthy if an error occurred. Use glz::format_error to convert the error context into a human-readable message.

    #include "glaze/yaml.hpp"
    
    struct retry_policy
    {
       int attempts = 5;
       int backoff_ms = 250;
    };
    
    template <>
    struct glz::meta<retry_policy>
    {
       using T = retry_policy;
       static constexpr auto value = object(&T::attempts, &T::backoff_ms);
    };
    
    struct app_config
    {
       std::string host = "127.0.0.1";
       int port = 8080;
       retry_policy retry{};
       std::vector<std::string> features{"metrics"};
    };
    
    template <>
    struct glz::meta<app_config>
    {
       using T = app_config;
       static constexpr auto value = object(&T::host, &T::port, &T::retry, &T::features);
    };
    
    app_config cfg{};
    std::string yaml{};
    auto write_error = glz::write_yaml(cfg, yaml);
    if (write_error) {
       const auto message = glz::format_error(write_error, yaml);
       // handle the error message
    }
    
    app_config loaded{};
    auto read_error = glz::read_yaml(loaded, yaml);
    if (read_error) {
       const auto message = glz::format_error(read_error, yaml);
       // handle the error message
    }
  7. Use Wildcard and Catch-All Routes

    main

    Wildcard routes use the *param syntax to match everything after a certain segment. These are useful for static file serving or dynamic API versioning. Captured segments are available in req.params.

    // Static file serving
    router.get("/static/*path", [](const glz::request& req, glz::response& res) {
        std::string file_path = req.params.at("path");
        // file_path contains everything after /static/
        serve_file("public/" + file_path, res);
    });
    
    // API versioning catch-all
    router.get("/api/*version", [](const glz::request& req, glz::response& res) {
        std::string version = req.params.at("version");
        handle_api_request(version, req, res);
    });
  8. Write and Read SQLite JSONB with Glaze

    main

    Glaze provides native support for the SQLite JSONB binary format. This allows you to produce JSONB blobs directly in C++, which can be inserted into SQLite without an intermediate JSON-to-JSONB conversion pass.

    Writing JSONB

    Use glz::write_jsonb to serialize a C++ object into a buffer containing a valid SQLite JSONB blob.

    Reading JSONB

    Use glz::read_jsonb to deserialize a JSONB buffer into a C++ object.

    Converting JSONB to JSON

    If you need to convert a JSONB blob back into a standard JSON string, use glz::jsonb_to_json.

    #include "glaze/jsonb.hpp"
    
    // Write JSONB
    my_struct s{};
    std::string buffer{};
    auto ec = glz::write_jsonb(s, buffer);
    if (!ec) {
       // buffer now contains a valid SQLite JSONB blob, ready to INSERT.
    }
    
    // Read JSONB
    my_struct s_in{};
    auto ec_read = glz::read_jsonb(s_in, buffer);
    if (!ec_read) {
       // Success
    }
    
    // Convert JSONB -> JSON
    auto json = glz::jsonb_to_json(buffer);
    if (json) {
       // json.value() is a std::string containing JSON text
    }
  9. Navigate data structures using JSON Pointer (RFC 6901)

    main

    Glaze uses JSON Pointer syntax for navigating data structures via the API.

    • Basic Paths: Use /key to access members.
    • Nested Objects: Use /parent/child to traverse nested structures.
    • Array Access: Use /array/index (e.g., /ports/0) to access elements by index.
    • Escaping Special Characters: If keys contain special characters, use the following escapes:
      • ~0 represents ~
      • ~1 represents / (e.g., a key named a/b is accessed as /a~1b).
  10. Parse Form POST data in Glaze HTTP Server

    main

    To handle application/x-www-form-urlencoded POST requests, check the Content-Type header and then call glz::parse_urlencoded on the req.body.

    server.post("/login", [](const glz::request& req, glz::response& res) {
        // Check content type
        auto ct = req.headers.find("content-type");
        if (ct == req.headers.end() ||
            ct->second.find("application/x-www-form-urlencoded") == std::string::npos) {
            res.status(415).json({{"error", "Unsupported content type"}});
            return;
        }
    
        // Parse form data from body
        auto form = glz::parse_urlencoded(req.body);
    
        std::string username = form["username"];
        std::string password = form["password"];
    
        // Authenticate...
    });