Program Listing for File serialization.cc#

↰ Return to documentation for file (src/serialization.cc)

#include "nodes-graph/serialization.h"


namespace ng::serialization {

static_assert(sizeof(bool) == 1, "Booleans are serialized on a single byte");

namespace {

    template <typename T>
    void append_raw(buffer_t& buffer, const T& value) {
        buffer.insert(
            buffer.end(),
            reinterpret_cast<const char*>(&value),
            reinterpret_cast<const char*>(&value) + sizeof(T)
        );
    }

} // namespace


bool is_sup_or_equal(const version_t& a, const version_t& b) {
    for (std::size_t i = 0; i < a.size(); ++i) {
        if (a[i] > b[i]) return true;
        if (a[i] < b[i]) return false;
    }
    return true;
}


void add_length_prefix(buffer_t& buffer) {
    len_t len = buffer.size() + LEN;
    buffer.insert(
        buffer.begin(),
        reinterpret_cast<char*>(&len),
        reinterpret_cast<char*>(&len) + LEN
    );
}


// --- Base types are just added to the buffer as such, they are not prefixed by their length in bytes.

void serialize(buffer_t& buffer, len_t l) { append_raw(buffer, l); }

void serialize(buffer_t& buffer, bound_t b) { append_raw(buffer, b); }

void serialize(buffer_t& buffer, bool s) { append_raw(buffer, s); }

void serialize(buffer_t& buffer, socket_t type) { append_raw(buffer, type); }


// --- Strings are serialized as a sequence of characters including the null terminator, prefixed by their length in bytes.

void serialize_bytes(buffer_t& buffer, const char* s, len_t l) {
    serialize(buffer, l);
    buffer.insert(buffer.end(), s, s + l);
}


void serialize(buffer_t& buffer, const std::string& s) {
    serialize_bytes(buffer, s.c_str(), static_cast<len_t>(s.size() + 1));
}


void serialize(buffer_t& buffer, const qualifier_t& qualifier) {
    buffer_t b;
    for (std::size_t i = 0 ; i < qualifier_t::N_CHUNKS; ++i) {
        serialize(b, qualifier.chunks[i]);
    }
    add_length_prefix(b);
    buffer.insert(buffer.end(), b.begin(), b.end());
}


void serialize(buffer_t& buffer, const socket_uuid_t& socket_uuid) {
    buffer_t b;
    serialize(b, socket_uuid.first);
    serialize(b, socket_uuid.second);
    add_length_prefix(b);
    buffer.insert(buffer.end(), b.begin(), b.end());
}


void serialize(buffer_t& buffer, const link_t& link) {
    buffer_t b;
    serialize(b, link.first);
    serialize(b, link.second);
    add_length_prefix(b);
    buffer.insert(buffer.end(), b.begin(), b.end());
}


// --- Graph components

void serialize_socket_base(buffer_t& buffer, const Socket& socket) {
    serialize(buffer, socket.get_name());
    serialize(buffer, socket.get_id());
    serialize(buffer, socket.get_type());
    serialize(buffer, socket.is_active());
    serialize(buffer, socket.get_on_added_link_callbacks(), Bounds::callbacks);
    serialize(buffer, socket.get_on_broken_link_callbacks(), Bounds::callbacks);
}


void serialize(buffer_t& buffer, const InputSocket& socket) {
    buffer_t b;
    serialize_socket_base(b, socket);
    serialize(b, socket.get_value());
    serialize(b, socket.get_allowed_values(), Bounds::whitelist);
    serialize(b, socket.is_linkable());
    serialize(b, socket.get_on_value_changed_callbacks(), Bounds::callbacks);
    add_length_prefix(b);
    buffer.insert(buffer.end(), b.begin(), b.end());
}


void serialize(buffer_t& buffer, const OutputSocket& socket) {
    buffer_t b;
    serialize_socket_base(b, socket);
    add_length_prefix(b);
    buffer.insert(buffer.end(), b.begin(), b.end());
}


void serialize(buffer_t& buffer, const Node& node) {
    buffer_t b;
    serialize(b, node.get_id());
    serialize(b, node.get_qualifier());
    serialize(b, node.get_name());
    serialize(b, node.get_input_sockets(), Bounds::sockets);
    serialize(b, node.get_output_sockets(), Bounds::sockets);
    serialize(b, node.is_proxy());
    add_length_prefix(b);
    buffer.insert(buffer.end(), b.begin(), b.end());
}


void serialize(buffer_t& buffer, const Graph::InterfaceProperties& interface_ppts) {
    buffer_t b;
    serialize(b, interface_ppts.socket_id);
    serialize(b, interface_ppts.show_as);
    add_length_prefix(b);
    buffer.insert(buffer.end(), b.begin(), b.end());
}


// ---


Serializer::Serializer(const Graph& graph) : graph_(graph) {
    if (!graph_.get_qualifier().has_value())
        throw std::runtime_error("Graph must have a qualifier for serialization.");
}


void Serializer::serialize_graph() {
    buffer_.clear();

    serialize(buffer_, Bounds::graph);
    serialize(buffer_, graph_.get_qualifier().value());
    serialize(buffer_, get_parser_version());
    serialize(buffer_, get_app_name());

    serialize(buffer_, graph_.get_name());
    serialize(buffer_, graph_.get_links(), Bounds::links);
    serialize(buffer_, graph_.get_nodes(), Bounds::nodes);
    serialize(buffer_, graph_.get_input_sockets(), Bounds::sockets);
    serialize(buffer_, graph_.get_output_sockets(), Bounds::sockets);
    serialize(buffer_, graph_.get_parameters(), Bounds::interface);
    serialize(buffer_, graph_.get_results(), Bounds::interface);

    serialize(buffer_, Bounds::graph);
    add_length_prefix(buffer_);
}

} // namespace ng::serialization