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