diff --git a/src/blackmisc/tuple.h b/src/blackmisc/tuple.h index f051f88b6..a263366da 100644 --- a/src/blackmisc/tuple.h +++ b/src/blackmisc/tuple.h @@ -63,11 +63,13 @@ static auto toMetaTuple(const T &o) -> decltype(BlackMisc::tieMeta MEMBERS) \ { \ auto tu = BlackMisc::tieMeta MEMBERS; \ + parser().extendMetaTuple(tu); \ return tu; \ } \ static auto toMetaTuple(T &o) -> decltype(BlackMisc::tieMeta MEMBERS) \ { \ auto tu = BlackMisc::tieMeta MEMBERS; \ + parser().extendMetaTuple(tu); \ return tu; \ } \ static const Parser &parser() \ @@ -111,11 +113,13 @@ static auto toMetaTuple(const T &o) -> decltype(BlackMisc::tieMeta MEMBERS) \ { \ auto tu = BlackMisc::tieMeta MEMBERS; \ + parser().extendMetaTuple(tu); \ return tu; \ } \ static auto toMetaTuple(T &o) -> decltype(BlackMisc::tieMeta MEMBERS) \ { \ auto tu = BlackMisc::tieMeta MEMBERS; \ + parser().extendMetaTuple(tu); \ return tu; \ } \ static const Parser &parser() \ @@ -169,11 +173,23 @@ namespace BlackMisc } //! \brief Create a tuple element with attached metadata. + //! @{ template static Private::Attribute attr(T &obj, std::integral_constant) { return { obj }; } + template + static Private::Attribute attr(T &obj, QString jsonName) + { + return { obj, jsonName }; + } + template + static Private::Attribute attr(T &obj, QString jsonName, std::integral_constant) + { + return { obj, jsonName }; + } + //! @} //! \brief Helper class which parses the stringified macro argument. struct Parser @@ -181,6 +197,14 @@ namespace BlackMisc Parser(QString); //!< Constructor. QStringList m_raw; //!< The raw macro argument, split by top-level commas. QStringList m_names; //!< The names of the tuple members, stripped of any o.m_ prefix. + + //! Fills in any incomplete metadata in a tuple using information from the Parser. + template + void extendMetaTuple(Tu &&tu) const + { + Private::extendMeta(std::forward(tu), m_names, + Private::make_index_sequence::type>::value>()); + } }; }; @@ -233,6 +257,7 @@ namespace BlackMisc /*! * \name Static Private Member Functions * \brief Returns a list of the names of the tuple members. + * \deprecated This information is now embedded in the meta tuples. */ static const QStringList &jsonMembers(); }; @@ -339,6 +364,7 @@ namespace BlackMisc /*! * \brief Convert to a JSON object * \ingroup Tuples + * \deprecated The QStringList members can be embedded in tuple metadata. */ template QJsonObject serializeJson(const QStringList &members, std::tuple tu) @@ -353,6 +379,7 @@ namespace BlackMisc /*! * \brief Convert from JSON to object * \ingroup Tuples + * \deprecated The QStringList members can be embedded in tuple metadata. */ template void deserializeJson(const QJsonObject &json, const QStringList &members, std::tuple tu) @@ -362,6 +389,30 @@ namespace BlackMisc Private::TupleHelper::deserializeJson(json, members, valueTu, Private::skipFlaggedIndices(metaTu)); } + /*! + * \brief Convert to a JSON object + * \ingroup Tuples + */ + template + QJsonObject serializeJson(std::tuple tu) + { + QJsonObject json; + Private::assertMeta>(); + Private::TupleHelper::serializeJson(json, tu, Private::skipFlaggedIndices(tu)); + return json; + } + + /*! + * \brief Convert from JSON to object + * \ingroup Tuples + */ + template + void deserializeJson(const QJsonObject &json, std::tuple tu) + { + Private::assertMeta>(); + Private::TupleHelper::deserializeJson(json, tu, Private::skipFlaggedIndices(tu)); + } + } // namespace BlackMisc #endif // guard diff --git a/src/blackmisc/tuple_private.h b/src/blackmisc/tuple_private.h index f0b95b23a..115c9d986 100644 --- a/src/blackmisc/tuple_private.h +++ b/src/blackmisc/tuple_private.h @@ -138,8 +138,10 @@ namespace BlackMisc typedef T type; static const quint64 flags = Flags; - Attribute(T &obj) : m_obj(obj) {} + Attribute(T &obj, QString jsonName = {}) : m_obj(obj), m_jsonName(jsonName) {} + void extend(QString jsonName) { if (m_jsonName.isEmpty()) m_jsonName = jsonName; } T &m_obj; + QString m_jsonName; bool operator ==(const Attribute &other) const { return m_obj == other.m_obj; } bool operator !=(const Attribute &other) const { return m_obj != other.m_obj; } @@ -174,6 +176,12 @@ namespace BlackMisc return attr; } + // Compile-time assert for functions which require a meta tuple + template + struct assertMeta { static_assert(std::is_void::value, "Function expected a meta tuple, got a value tuple"); }; + template + struct assertMeta...>> {}; + // Convert a meta tuple to a value tuple template auto stripMeta(Tu &&tu, index_sequence) -> decltype(std::make_tuple(tieHelper(std::get(std::forward(tu)))...)) @@ -188,6 +196,13 @@ namespace BlackMisc return std::make_tuple(tieMetaHelper(std::get(std::forward(tu)))...); } + // Fill in any incomplete metadata in a meta tuple, from an appropriate source + template + void extendMeta(Tu &&tu, const QStringList &jsonNames, index_sequence) + { + [](...){}((std::get(std::forward(tu)).extend(jsonNames[Is]), 0)...); + } + // Applying operations to all elements in a tuple, using index_sequence for clean recursion class TupleHelper { @@ -237,11 +252,23 @@ namespace BlackMisc deserializeJsonImpl(json, std::make_pair(names[Is], get_ref(tu))...); } - private: - template - static auto get_ref(T &&tu) -> decltype(std::ref(std::get(std::forward(tu)))) + template + static void serializeJson(QJsonObject &json, const Tu &tu, index_sequence) { - return std::ref(std::get(std::forward(tu))); + serializeJsonImpl(json, std::make_pair(std::get(tu).m_jsonName, std::get(tu).m_obj)...); + } + + template + static void deserializeJson(const QJsonObject &json, Tu &tu, index_sequence) + { + deserializeJsonImpl(json, std::make_pair(std::get(tu).m_jsonName, get_ref(tu))...); + } + + private: + template + static auto get_ref(Tu &&tu) -> decltype(tieHelper(std::get(std::forward(tu)))) + { + return tieHelper(std::get(std::forward(tu))); } static int compareImpl() { return 0; }