Revision control
++ // Copyright (C) 2024 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++
++ #include <QtProtobuf/qprotobufregistration.h>
++
++ #include <QtProtobuf/private/qtprotobuf-config_p.h>
++ #include <QtProtobuf/private/qprotobufregistration_p.h>
++ #include <QtProtobuf/qtprotobuftypes.h>
++
++ #include <QtCore/qmutex.h>
++ #include <QtCore/qmetatype.h>
++ #if !QT_CONFIG(protobuf_unsafe_registry)
++ # include <QtCore/qreadwritelock.h>
++ #endif
++
++ #include <mutex>
++
++ QT_BEGIN_NAMESPACE
++
++ /*!
++ \relates QtProtobuf
++ \fn template<typename T, QtProtobuf::if_protobuf_message<T> = true> inline void qRegisterProtobufType()
++
++ Registers a Protobuf type \e T.
++ This function is normally called by generated code.
++ */
++
++ /*!
++ \relates QtProtobuf
++ \fn template<typename K, typename V, QtProtobuf::if_protobuf_map<K, V> = true> inline void qRegisterProtobufMapType();
++
++ Registers a Protobuf map type \c K and \c V.
++ \c V must be a QProtobufMessage.
++ This function is normally called by generated code.
++ */
++
++ /*!
++ \relates QtProtobuf
++ \fn template <typename T, typename std::enable_if_t<std::is_enum<T>::value, bool> = true> inline void qRegisterProtobufEnumType();
++
++ Registers serializers for enumeration type \c T in QtProtobuf global
++ serializers registry.
++
++ This function is normally called by generated code.
++ */
++
++ namespace {
++ std::vector<QtProtobuf::RegisterFunction> ®isterFunctions()
++ {
++ // no need for implicit sharing etc, so stick with std::vector
++ static std::vector<QtProtobuf::RegisterFunction> registrationList;
++ return registrationList;
++ }
++
++ template<typename T>
++ void registerBasicConverters()
++ {
++ QMetaType::registerConverter<int32_t, T>(T::fromType);
++ QMetaType::registerConverter<T, int32_t>(T::toType);
++ QMetaType::registerConverter<int64_t, T>(T::fromType);
++ QMetaType::registerConverter<T, int64_t>(T::toType);
++ QMetaType::registerConverter<uint32_t, T>(T::fromType);
++ QMetaType::registerConverter<T, uint32_t>(T::toType);
++ QMetaType::registerConverter<uint64_t, T>(T::fromType);
++ QMetaType::registerConverter<T, uint64_t>(T::toType);
++ if constexpr (!std::is_same_v<long long, int64_t>) {
++ QMetaType::registerConverter<long long, T>(T::fromType);
++ QMetaType::registerConverter<T, long long>(T::toType);
++ QMetaType::registerConverter<unsigned long long, T>(T::fromType);
++ QMetaType::registerConverter<T, unsigned long long>(T::toType);
++ }
++ QMetaType::registerConverter<double, T>(T::fromType);
++ QMetaType::registerConverter<T, double>(T::toType);
++ QMetaType::registerConverter<T, QString>(T::toString);
++ }
++
++ static void qRegisterBaseTypes()
++ {
++ [[maybe_unused]] // definitely unused
++ static bool registered = [] {
++ qRegisterMetaType<QtProtobuf::int32>();
++ qRegisterMetaType<QtProtobuf::int64>();
++ qRegisterMetaType<QtProtobuf::uint32>();
++ qRegisterMetaType<QtProtobuf::uint64>();
++ qRegisterMetaType<QtProtobuf::sint32>();
++ qRegisterMetaType<QtProtobuf::sint64>();
++ qRegisterMetaType<QtProtobuf::fixed32>();
++ qRegisterMetaType<QtProtobuf::fixed64>();
++ qRegisterMetaType<QtProtobuf::sfixed32>();
++ qRegisterMetaType<QtProtobuf::sfixed64>();
++ qRegisterMetaType<QtProtobuf::boolean>();
++
++ qRegisterMetaType<QtProtobuf::int32List>();
++ qRegisterMetaType<QtProtobuf::int64List>();
++ qRegisterMetaType<QtProtobuf::uint32List>();
++ qRegisterMetaType<QtProtobuf::uint64List>();
++ qRegisterMetaType<QtProtobuf::sint32List>();
++ qRegisterMetaType<QtProtobuf::sint64List>();
++ qRegisterMetaType<QtProtobuf::fixed32List>();
++ qRegisterMetaType<QtProtobuf::fixed64List>();
++ qRegisterMetaType<QtProtobuf::sfixed32List>();
++ qRegisterMetaType<QtProtobuf::sfixed64List>();
++
++ qRegisterMetaType<QtProtobuf::doubleList>();
++ qRegisterMetaType<QtProtobuf::floatList>();
++ qRegisterMetaType<QtProtobuf::boolList>();
++
++ registerBasicConverters<QtProtobuf::int32>();
++ registerBasicConverters<QtProtobuf::int64>();
++ registerBasicConverters<QtProtobuf::sfixed32>();
++ registerBasicConverters<QtProtobuf::sfixed64>();
++ registerBasicConverters<QtProtobuf::fixed32>();
++ registerBasicConverters<QtProtobuf::fixed64>();
++ return true;
++ }();
++ }
++
++ /*
++ \internal
++ \brief The HandlersRegistry is a container to store mapping between metatype
++ identifier and serialization handlers.
++ */
++ struct HandlersRegistry
++ {
++ void registerHandler(QMetaType type, QtProtobufPrivate::Serializer serializer,
++ QtProtobufPrivate::Deserializer deserializer)
++ {
++ #if !QT_CONFIG(protobuf_unsafe_registry)
++ QWriteLocker locker(&m_lock);
++ #endif
++ m_registry[type] = { serializer, deserializer };
++ }
++
++ QtProtobufPrivate::SerializationHandler findHandler(QMetaType type)
++ {
++ #if !QT_CONFIG(protobuf_unsafe_registry)
++ QReadLocker locker(&m_lock);
++ #endif
++ auto it = m_registry.constFind(type);
++ if (it != m_registry.constEnd())
++ return it.value();
++ return {};
++ }
++
++ private:
++ # if !QT_CONFIG(protobuf_unsafe_registry)
++ QReadWriteLock m_lock;
++ # endif
++ QHash<QMetaType, QtProtobufPrivate::SerializationHandler> m_registry;
++ };
++ Q_GLOBAL_STATIC(HandlersRegistry, handlersRegistry)
++
++
++ Q_CONSTINIT QBasicMutex registerMutex;
++ }
++
++ void QtProtobufPrivate::registerHandler(QMetaType type, Serializer serializer,
++ Deserializer deserializer)
++ {
++ handlersRegistry->registerHandler(type, serializer, deserializer);
++ }
++
++ QtProtobufPrivate::SerializationHandler QtProtobufPrivate::findHandler(QMetaType type)
++ {
++ if (!handlersRegistry.exists())
++ return {};
++ return handlersRegistry->findHandler(type);
++ }
++
++ namespace QtProtobuf {
++
++ ProtoTypeRegistrar::ProtoTypeRegistrar(QtProtobuf::RegisterFunction initializer)
++ {
++ std::scoped_lock lock(registerMutex);
++ registerFunctions().push_back(initializer);
++ }
++
++ }
++
++ /*!
++ \relates QtProtobuf
++ Calling this function registers all, currently known, protobuf types with
++ the serializer registry.
++
++ \note Only since Qt 6.6.3 version you don't have to call this function manually,
++ as it is called automatically. For earlier versions it's better to call it
++ before serialization/deserialization attempt.
++ */
++ void qRegisterProtobufTypes()
++ {
++ qRegisterBaseTypes();
++
++ std::scoped_lock lock(registerMutex);
++ std::vector<QtProtobuf::RegisterFunction> registrationList;
++ registrationList.swap(registerFunctions());
++
++ for (QtProtobuf::RegisterFunction registerFunc : registrationList)
++ registerFunc();
++ }
++
++ /*!
++ \class template <typename T, QtProtobuf::if_protobuf_message<T> = true> class QtProtobufPrivate::ListIterator
++ \internal
++ */
++
++ /*!
++ \class template <typename K, typename V, QtProtobuf::if_protobuf_map<K, V> = true> class QtProtobufPrivate::MapIterator
++ \internal
++ */
++
++ /*!
++ \struct QtProtobufPrivate::SerializationHandler
++ \internal
++ \brief SerializationHandlers contains set of objects that are required for
++ class serialization/deserialization.
++ */
++
++ QT_END_NAMESPACE