Skip to content
Snippets Groups Projects
Streamer.h 3.45 KiB
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/Support/XML/Streamer.h
//! @brief     Defines class Streamer
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2021
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#ifndef BORNAGAIN_GUI_SUPPORT_XML_STREAMER_H
#define BORNAGAIN_GUI_SUPPORT_XML_STREAMER_H

#include "Base/Util/Assert.h"
#include <QXmlStreamWriter> // used in every including file
#include <functional>
#include <heinz/Vectors3D.h>

namespace StreamerXML {
namespace Tags {
constexpr auto Id("id");
constexpr auto Value("value");
constexpr auto Decimals("decimals");
constexpr auto Version("version");
} // namespace Tags
} // namespace XML

//! Supports serialization to or deserialization from QXmlStream.
//!
//! Can be either a writer or a reader, depending on the constructor.

class Streamer {
public:
    Streamer(QXmlStreamWriter* w)
        : m_w(w)
    {
    }
    Streamer(QXmlStreamReader* r)
        : m_r(r)
    {
    }

    QXmlStreamWriter* xmlWriter() { return m_w; } //!< Returns stream writer or nullptr.
    QXmlStreamReader* xmlReader() { return m_r; } //!< Returns stream reader or nullptr.

    //! As writer, serializes the given version number. As reader, does nothing.
    void writeVersion(unsigned version) const;

    //! As reader, throws DeserializationException unless the expected version is read.
    //! As writer, does nothing.
    void assertVersion(unsigned expectedVersion) const;

    template <typename Catalog>
    void write(const QString& tag, typename Catalog::CatalogedType* p);

    template <typename Catalog, typename... Args>
    void read(const QString& tag, typename Catalog::CatalogedType*& p, Args... argsForConstructor);

    void gotoStartElementOfTag(const QString& tag);
    void gotoEndElementOfTag(const QString& tag);
    void assertCurrentTag(const QString& expectedTag) const;

    void start(const QString& tag);
    void finish(const QString& tag);

private:
    void assertCurrentToken(QXmlStreamReader::TokenType token) const;

    QXmlStreamWriter* m_w = nullptr;
    QXmlStreamReader* m_r = nullptr;
};

//  ************************************************************************************************
//  Templates implementation
//  ************************************************************************************************

template <typename Catalog>
void Streamer::write(const QString& tag, typename Catalog::CatalogedType* p)
{
    ASSERT(m_w);
    m_w->writeStartElement(tag);
    m_w->writeAttribute("type", QString::number(static_cast<uint8_t>(Catalog::type(p))));
    if (p != nullptr)
        p->serialize(*this);
    m_w->writeEndElement();
}

template <typename Catalog, typename... Args>
void Streamer::read(const QString& tag, typename Catalog::CatalogedType*& p,
                    Args... argsForConstructor)
{
    ASSERT(m_r);
    gotoStartElementOfTag(tag);
    const auto type = static_cast<typename Catalog::Type>(m_r->attributes().value("type").toUInt());
    p = Catalog::create(type, argsForConstructor...);
    if (p != nullptr)
        p->serialize(*this);
    gotoEndElementOfTag(tag);
}

#endif // BORNAGAIN_GUI_SUPPORT_XML_STREAMER_H