Program Listing for File deserialization.h#

↰ Return to documentation for file (include/nodes-graph/deserialization.h)

#pragma once


#include <cstring>
#include <map>
#include <set>
#include <string>
#include <vector>
#include "nodes-graph/serialization.h"


namespace ng::deserialization {

    namespace sr = ng::serialization;

    struct ReadHead {
        const sr::buffer_t& buffer;
        std::size_t pos = 0;

        ReadHead(const sr::buffer_t& buffer) : buffer(buffer) {}

        inline std::size_t remaining() const { return (pos < buffer.size()) ? buffer.size() - pos : 0; }

        inline void require(std::size_t n) const {
            if (n > remaining()) { throw std::runtime_error("Unexpected end of buffer"); }
        }

        inline const char* c_str() const { return buffer.data() + pos; }

        inline void read(void* dst, std::size_t n) {
            require(n);
            std::memcpy(dst, c_str(), n);
            pos += n;
        }
    };

    // --- Base types
    sr::len_t deserialize_len(ReadHead& head);
    sr::bound_t deserialize_bound(ReadHead& head);
    bool deserialize_bool(ReadHead& head);
    socket_t deserialize_socket_type(ReadHead& head);

    // --- Strings and identifiers
    std::string deserialize_string(ReadHead& head);

    template <std::size_t N>
    std::array<char, N> deserialize_array(ReadHead& head);

    qualifier_t deserialize_qualifier(ReadHead& head);
    socket_uuid_t deserialize_socket_uuid(ReadHead& head);
    link_t deserialize_link(ReadHead& head);

    // --- Graph components
    struct SocketAttributes {
        sr::len_t len;
        std::size_t start;
        std::string name;
        socket_id_t id;
        socket_t type;
        bool active;
        std::set<qualifier_t> on_added_link_callbacks;
        std::set<qualifier_t> on_broken_link_callbacks;
    };

    SocketAttributes deserialize_socket_base(ReadHead& head);
    InputSocket deserialize_input_socket(ReadHead& head);
    OutputSocket deserialize_output_socket(ReadHead& head);
    Node deserialize_node(ReadHead& head);
    Graph::InterfaceProperties deserialize_interface_properties(ReadHead& head);

    // --- Collections
    template <typename T>
    std::set<T> deserialize_set(ReadHead& head, T(*deserialize_item)(ReadHead&), sr::bound_t bound);

    template <typename U, typename V>
    std::map<U, V> deserialize_map(ReadHead& head, U(*deserialize_key)(ReadHead&), V(*deserialize_value)(ReadHead&), sr::bound_t bound);

    // ---

    class Deserializer {
        const sr::buffer_t& buffer_;
        Graph graph_;

    public:
        Deserializer(const sr::buffer_t& buffer) : buffer_(buffer) {}

        void deserialize_graph();

        inline const Graph& get_graph() const { return graph_; }
    };


    // -------------------------------------------------------------------------


    template <std::size_t N>
    std::array<char, N> deserialize_array(ReadHead& head) {
        sr::len_t len = deserialize_len(head);
        if (len != N)
            throw std::runtime_error("Array length does not match the expected size");

        std::array<char, N> result;
        head.read(result.data(), N);
        return result;
    }


    template <typename T>
    std::set<T> deserialize_set(ReadHead& head, T(*deserialize_item)(ReadHead&), sr::bound_t bound) {
        std::size_t start = head.pos;
        sr::len_t len = deserialize_len(head);
        if (deserialize_bound(head) != bound)
            throw std::runtime_error("Bound does not match the expected value");

        sr::len_t n_items = deserialize_len(head);
        std::set<T> result;
        for (sr::len_t i = 0; i < n_items; ++i) {
            result.insert(deserialize_item(head));
        }

        if (deserialize_bound(head) != bound)
            throw std::runtime_error("Bound does not match the expected value at the end of the set");

        if (result.size() != n_items)
            throw std::runtime_error("Number of deserialized items does not match the expected count");

        if (len != head.pos - start)
            throw std::runtime_error("Set length does not match the expected size");

        return result;
    }


    template <typename U, typename V>
    std::map<U, V> deserialize_map(ReadHead& head, U(*deserialize_key)(ReadHead&), V(*deserialize_value)(ReadHead&), sr::bound_t bound) {
        std::size_t start = head.pos;
        sr::len_t len = deserialize_len(head);
        if (deserialize_bound(head) != bound)
            throw std::runtime_error("Bound does not match the expected value");

        sr::len_t n_items = deserialize_len(head);
        std::map<U, V> result;
        for (sr::len_t i = 0; i < n_items; ++i) {
            U key = deserialize_key(head);
            V value = deserialize_value(head);
            result.emplace(std::move(key), std::move(value));
        }

        if (deserialize_bound(head) != bound)
            throw std::runtime_error("Bound does not match the expected value at the end of the map");

        if (result.size() != n_items)
            throw std::runtime_error("Number of deserialized items does not match the expected count");

        if (len != head.pos - start)
            throw std::runtime_error("Map length does not match the expected size");

        return result;
    }

} // namespace ng::deserialization