1 | // Copyright (C) 2024 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include <QtGrpc/qgrpcserializationformat.h> |
5 | |
6 | #include <QtProtobuf/qprotobufjsonserializer.h> |
7 | #include <QtProtobuf/qprotobufserializer.h> |
8 | |
9 | #include <QtCore/qbytearray.h> |
10 | #include <QtCore/qdebug.h> |
11 | #include <QtCore/qvariant.h> |
12 | |
13 | using namespace QtGrpc; |
14 | |
15 | QT_BEGIN_NAMESPACE |
16 | |
17 | /*! |
18 | \class QGrpcSerializationFormat |
19 | \inmodule QtGrpc |
20 | \compares equality |
21 | \since 6.8 |
22 | \brief The QGrpcSerializationFormat class holds the protobuf message |
23 | serializer and the associated content-type suffix. |
24 | |
25 | The QGrpcSerializationFormat class contains the \l{serializer} used for |
26 | serializing and deserializing protobuf messages, as well as the associated |
27 | content-type \l{suffix}, which indicates the message encoding in transport. |
28 | For HTTP/2 specific details see the \l{Content-Type} section. |
29 | |
30 | \note The content-type is transport, and therefore implementation specific. |
31 | |
32 | The class can be constructed using one of the |
33 | \l{QtGrpc::}{SerializationFormat} presets or a custom suffix and |
34 | serializer: |
35 | |
36 | \code |
37 | QGrpcSerializationFormat jsonFormat(QtGrpc::SerializationFormat::Json); |
38 | \endcode |
39 | |
40 | This creates a QProtobufJsonSerializer with the \c{json} suffix. For HTTP/2 |
41 | transportation this results in the \c{application/grpc+json} content-type. |
42 | |
43 | //! [custom-serializer-code] |
44 | \code |
45 | class DummySerializer : public QAbstractProtobufSerializer |
46 | { |
47 | ... |
48 | }; |
49 | QGrpcSerializationFormat dummyFormat("dummy", std::make_shared<DummySerializer>()); |
50 | \endcode |
51 | //! [custom-serializer-code] |
52 | |
53 | //! [custom-serializer-desc] |
54 | This uses \c{DummySerializer} for encoding and decoding messages with the |
55 | \c{dummy} suffix. For HTTP/2 transportation this results in the |
56 | \c{application/grpc+dummy} content-type. |
57 | |
58 | \note Custom serializers require server support for the specified format. |
59 | //! [custom-serializer-desc] |
60 | |
61 | \sa QGrpcChannelOptions::serializationFormat |
62 | */ |
63 | |
64 | class QGrpcSerializationFormatPrivate : public QSharedData |
65 | { |
66 | public: |
67 | QGrpcSerializationFormatPrivate(QByteArrayView suffix_, |
68 | std::shared_ptr<QAbstractProtobufSerializer> serializer_) |
69 | : suffix(suffix_.toByteArray()), serializer(std::move(serializer_)) |
70 | { |
71 | } |
72 | |
73 | QByteArray suffix; |
74 | std::shared_ptr<QAbstractProtobufSerializer> serializer; |
75 | }; |
76 | |
77 | QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QGrpcSerializationFormatPrivate) |
78 | |
79 | /*! |
80 | Constructs a new QGrpcSerializationFormat with the specified preset \a |
81 | format. |
82 | |
83 | The default format used is \l {QtGrpc::} {SerializationFormat::Default}. |
84 | */ |
85 | QGrpcSerializationFormat::QGrpcSerializationFormat(SerializationFormat format) |
86 | : d_ptr(format == SerializationFormat::Json |
87 | ? new QGrpcSerializationFormatPrivate("json" , |
88 | std::make_shared<QProtobufJsonSerializer>()) |
89 | : new QGrpcSerializationFormatPrivate(format == SerializationFormat::Protobuf |
90 | ? "proto" |
91 | : "" , |
92 | std::make_shared<QProtobufSerializer>())) |
93 | { |
94 | } |
95 | |
96 | /*! |
97 | Destroys the QGrpcSerializationFormat. |
98 | */ |
99 | QGrpcSerializationFormat::~QGrpcSerializationFormat() = default; |
100 | |
101 | /*! |
102 | Constructs a new QGrpcSerializationFormat with a custom content type |
103 | specified by \a suffix and a protobuf message \a serializer. |
104 | */ |
105 | QGrpcSerializationFormat::QGrpcSerializationFormat(QByteArrayView suffix, |
106 | std::shared_ptr<QAbstractProtobufSerializer> |
107 | serializer) |
108 | : d_ptr(new QGrpcSerializationFormatPrivate(suffix, std::move(serializer))) |
109 | { |
110 | } |
111 | |
112 | /*! |
113 | Constructs a copy of \a other. |
114 | */ |
115 | QGrpcSerializationFormat::QGrpcSerializationFormat(const QGrpcSerializationFormat &other) = default; |
116 | |
117 | /*! |
118 | Assigns the \a other QGrpcSerializationFormat object to this one. |
119 | */ |
120 | QGrpcSerializationFormat & |
121 | QGrpcSerializationFormat::operator=(const QGrpcSerializationFormat &other) = default; |
122 | |
123 | /*! |
124 | \fn QGrpcSerializationFormat::QGrpcSerializationFormat(QGrpcSerializationFormat &&other) noexcept |
125 | Move-constructs a new QGrpcSerializationFormat from \a other. |
126 | |
127 | \include qtgrpc-shared.qdocinc move-note-desc |
128 | */ |
129 | |
130 | /*! |
131 | \fn QGrpcSerializationFormat &QGrpcSerializationFormat::operator=(QGrpcSerializationFormat &&other) noexcept |
132 | Move-assigns \a other to this QGrpcSerializationFormat instance and returns |
133 | a reference to it. |
134 | |
135 | \include qtgrpc-shared.qdocinc move-note-desc |
136 | */ |
137 | |
138 | /*! |
139 | \since 6.8 |
140 | \fn void QGrpcSerializationFormat::swap(QGrpcSerializationFormat &other) noexcept |
141 | |
142 | \include qtgrpc-shared.qdocinc swap-desc |
143 | */ |
144 | |
145 | /*! |
146 | \since 6.8 |
147 | |
148 | \include qtgrpc-shared.qdocinc qvariant-desc |
149 | */ |
150 | QGrpcSerializationFormat::operator QVariant() const |
151 | { |
152 | return QVariant::fromValue(value: *this); |
153 | } |
154 | |
155 | /*! |
156 | Returns the content type suffix for this serialization format. |
157 | */ |
158 | QByteArrayView QGrpcSerializationFormat::suffix() const noexcept |
159 | { |
160 | Q_D(const QGrpcSerializationFormat); |
161 | return d->suffix; |
162 | } |
163 | |
164 | /*! |
165 | Returns the serializer for this serialization format. |
166 | |
167 | /sa QAbstractProtobufSerializer |
168 | */ |
169 | std::shared_ptr<QAbstractProtobufSerializer> QGrpcSerializationFormat::serializer() const |
170 | { |
171 | Q_D(const QGrpcSerializationFormat); |
172 | return d->serializer; |
173 | } |
174 | |
175 | #ifndef QT_NO_DEBUG_STREAM |
176 | /*! |
177 | \since 6.8 |
178 | \fn QDebug QGrpcSerializationFormat::operator<<(QDebug debug, const QGrpcSerializationFormat &sfmt) |
179 | Writes \a sfmt to the specified stream \a debug. |
180 | */ |
181 | QDebug operator<<(QDebug debug, const QGrpcSerializationFormat &sfmt) |
182 | { |
183 | const QDebugStateSaver save(debug); |
184 | debug.nospace().noquote(); |
185 | debug << "QGrpcSerializationFormat(suffix: " << sfmt.suffix() << ", serializer: { " |
186 | << static_cast<void *>(sfmt.serializer().get()) |
187 | << ", useCount: " << sfmt.serializer().use_count() << " })" ; |
188 | return debug; |
189 | } |
190 | #endif |
191 | |
192 | bool comparesEqual(const QGrpcSerializationFormat &lhs, |
193 | const QGrpcSerializationFormat &rhs) noexcept |
194 | { |
195 | return lhs.d_func()->suffix == rhs.d_func()->suffix |
196 | && lhs.d_func()->serializer == rhs.d_func()->serializer; |
197 | } |
198 | |
199 | size_t qHash(const QGrpcSerializationFormat &key, size_t seed) noexcept |
200 | { |
201 | return qHashMulti(seed, args: key.d_func()->suffix, args: key.d_func()->serializer.get()); |
202 | } |
203 | |
204 | QT_END_NAMESPACE |
205 | |