1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtProtobuf/qprotobufregistration.h>
5
6#include <QtProtobuf/private/qtprotobuf-config_p.h>
7#include <QtProtobuf/private/qprotobufregistration_p.h>
8#include <QtProtobuf/qtprotobuftypes.h>
9
10#include <QtCore/qmutex.h>
11#include <QtCore/qmetatype.h>
12#if !QT_CONFIG(protobuf_unsafe_registry)
13# include <QtCore/qreadwritelock.h>
14#endif
15
16#include <mutex>
17
18QT_BEGIN_NAMESPACE
19
20/*!
21 \relates QtProtobuf
22 \fn template<typename T, QtProtobuf::if_protobuf_message<T> = true> inline void qRegisterProtobufType()
23
24 Registers a Protobuf type \e T.
25 This function is normally called by generated code.
26*/
27
28/*!
29 \relates QtProtobuf
30 \fn template<typename K, typename V, QtProtobuf::if_protobuf_map<K, V> = true> inline void qRegisterProtobufMapType();
31
32 Registers a Protobuf map type \c K and \c V.
33 \c V must be a QProtobufMessage.
34 This function is normally called by generated code.
35*/
36
37/*!
38 \relates QtProtobuf
39 \fn template <typename T, typename std::enable_if_t<std::is_enum<T>::value, bool> = true> inline void qRegisterProtobufEnumType();
40
41 Registers serializers for enumeration type \c T in QtProtobuf global
42 serializers registry.
43
44 This function is normally called by generated code.
45*/
46
47namespace {
48std::vector<QtProtobuf::RegisterFunction> &registerFunctions()
49{
50 // no need for implicit sharing etc, so stick with std::vector
51 static std::vector<QtProtobuf::RegisterFunction> registrationList;
52 return registrationList;
53}
54
55template<typename T>
56void registerBasicConverters()
57{
58 QMetaType::registerConverter<int32_t, T>(T::fromType);
59 QMetaType::registerConverter<T, int32_t>(T::toType);
60 QMetaType::registerConverter<int64_t, T>(T::fromType);
61 QMetaType::registerConverter<T, int64_t>(T::toType);
62 QMetaType::registerConverter<uint32_t, T>(T::fromType);
63 QMetaType::registerConverter<T, uint32_t>(T::toType);
64 QMetaType::registerConverter<uint64_t, T>(T::fromType);
65 QMetaType::registerConverter<T, uint64_t>(T::toType);
66 if constexpr (!std::is_same_v<long long, int64_t>) {
67 QMetaType::registerConverter<long long, T>(T::fromType);
68 QMetaType::registerConverter<T, long long>(T::toType);
69 QMetaType::registerConverter<unsigned long long, T>(T::fromType);
70 QMetaType::registerConverter<T, unsigned long long>(T::toType);
71 }
72 QMetaType::registerConverter<double, T>(T::fromType);
73 QMetaType::registerConverter<T, double>(T::toType);
74 QMetaType::registerConverter<T, QString>(T::toString);
75}
76
77static void qRegisterBaseTypes()
78{
79 [[maybe_unused]] // definitely unused
80 static bool registered = [] {
81 qRegisterMetaType<QtProtobuf::int32>();
82 qRegisterMetaType<QtProtobuf::int64>();
83 qRegisterMetaType<QtProtobuf::uint32>();
84 qRegisterMetaType<QtProtobuf::uint64>();
85 qRegisterMetaType<QtProtobuf::sint32>();
86 qRegisterMetaType<QtProtobuf::sint64>();
87 qRegisterMetaType<QtProtobuf::fixed32>();
88 qRegisterMetaType<QtProtobuf::fixed64>();
89 qRegisterMetaType<QtProtobuf::sfixed32>();
90 qRegisterMetaType<QtProtobuf::sfixed64>();
91 qRegisterMetaType<QtProtobuf::boolean>();
92
93 qRegisterMetaType<QtProtobuf::int32List>();
94 qRegisterMetaType<QtProtobuf::int64List>();
95 qRegisterMetaType<QtProtobuf::uint32List>();
96 qRegisterMetaType<QtProtobuf::uint64List>();
97 qRegisterMetaType<QtProtobuf::sint32List>();
98 qRegisterMetaType<QtProtobuf::sint64List>();
99 qRegisterMetaType<QtProtobuf::fixed32List>();
100 qRegisterMetaType<QtProtobuf::fixed64List>();
101 qRegisterMetaType<QtProtobuf::sfixed32List>();
102 qRegisterMetaType<QtProtobuf::sfixed64List>();
103
104 qRegisterMetaType<QtProtobuf::doubleList>();
105 qRegisterMetaType<QtProtobuf::floatList>();
106 qRegisterMetaType<QtProtobuf::boolList>();
107
108 registerBasicConverters<QtProtobuf::int32>();
109 registerBasicConverters<QtProtobuf::int64>();
110 registerBasicConverters<QtProtobuf::sfixed32>();
111 registerBasicConverters<QtProtobuf::sfixed64>();
112 registerBasicConverters<QtProtobuf::fixed32>();
113 registerBasicConverters<QtProtobuf::fixed64>();
114 return true;
115 }();
116}
117
118/*
119 \internal
120 \brief The HandlersRegistry is a container to store mapping between metatype
121 identifier and serialization handlers.
122*/
123struct HandlersRegistry
124{
125 void registerHandler(QMetaType type, QtProtobufPrivate::Serializer serializer,
126 QtProtobufPrivate::Deserializer deserializer)
127 {
128#if !QT_CONFIG(protobuf_unsafe_registry)
129 QWriteLocker locker(&m_lock);
130#endif
131 m_registry[type] = { .serializer: serializer, .deserializer: deserializer };
132 }
133
134 QtProtobufPrivate::SerializationHandler findHandler(QMetaType type)
135 {
136#if !QT_CONFIG(protobuf_unsafe_registry)
137 QReadLocker locker(&m_lock);
138#endif
139 auto it = m_registry.constFind(key: type);
140 if (it != m_registry.constEnd())
141 return it.value();
142 return {};
143 }
144
145private:
146# if !QT_CONFIG(protobuf_unsafe_registry)
147 QReadWriteLock m_lock;
148# endif
149 QHash<QMetaType, QtProtobufPrivate::SerializationHandler> m_registry;
150};
151Q_GLOBAL_STATIC(HandlersRegistry, handlersRegistry)
152
153
154Q_CONSTINIT QBasicMutex registerMutex;
155}
156
157void QtProtobufPrivate::registerHandler(QMetaType type, Serializer serializer,
158 Deserializer deserializer)
159{
160 handlersRegistry->registerHandler(type, serializer, deserializer);
161}
162
163QtProtobufPrivate::SerializationHandler QtProtobufPrivate::findHandler(QMetaType type)
164{
165 if (!handlersRegistry.exists())
166 return {};
167 return handlersRegistry->findHandler(type);
168}
169
170namespace QtProtobuf {
171
172ProtoTypeRegistrar::ProtoTypeRegistrar(QtProtobuf::RegisterFunction initializer)
173{
174 std::scoped_lock lock(registerMutex);
175 registerFunctions().push_back(x: initializer);
176}
177
178}
179
180/*!
181 \relates QtProtobuf
182 Calling this function registers all, currently known, protobuf types with
183 the serializer registry.
184
185 \note Only since Qt 6.6.3 version you don't have to call this function manually,
186 as it is called automatically. For earlier versions it's better to call it
187 before serialization/deserialization attempt.
188*/
189void qRegisterProtobufTypes()
190{
191 qRegisterBaseTypes();
192
193 std::scoped_lock lock(registerMutex);
194 std::vector<QtProtobuf::RegisterFunction> registrationList;
195 registrationList.swap(x&: registerFunctions());
196
197 for (QtProtobuf::RegisterFunction registerFunc : registrationList)
198 registerFunc();
199}
200
201/*!
202 \class template <typename T, QtProtobuf::if_protobuf_message<T> = true> class QtProtobufPrivate::ListIterator
203 \internal
204*/
205
206/*!
207 \class template <typename K, typename V, QtProtobuf::if_protobuf_map<K, V> = true> class QtProtobufPrivate::MapIterator
208 \internal
209*/
210
211/*!
212 \struct QtProtobufPrivate::SerializationHandler
213 \internal
214 \brief SerializationHandlers contains set of objects that are required for
215 class serialization/deserialization.
216*/
217
218QT_END_NAMESPACE
219

source code of qtgrpc/src/protobuf/qprotobufregistration.cpp