1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #ifndef PROTOBUF_HPB_HPB_H_
9 #define PROTOBUF_HPB_HPB_H_
10
11 #include <cstdint>
12 #include <type_traits>
13 #include <vector>
14
15 #include "absl/status/status.h"
16 #include "absl/status/statusor.h"
17 #include "absl/strings/string_view.h"
18 #include "google/protobuf/hpb/arena.h"
19 #include "google/protobuf/hpb/backend/upb/interop.h"
20 #include "google/protobuf/hpb/extension.h"
21 #include "google/protobuf/hpb/internal/internal.h"
22 #include "google/protobuf/hpb/internal/template_help.h"
23 #include "google/protobuf/hpb/ptr.h"
24 #include "upb/base/status.hpp"
25 #include "upb/mem/arena.hpp"
26 #include "upb/message/copy.h"
27 #include "upb/mini_table/extension.h"
28 #include "upb/wire/decode.h"
29 #include "upb/wire/encode.h"
30
31 #ifdef HPB_BACKEND_UPB
32 #include "google/protobuf/hpb/backend/upb/upb.h"
33 #else
34 #error hpb backend must be specified
35 #endif
36
37 namespace hpb {
38 class ExtensionRegistry;
39
40 // This type exists to work around an absl type that has not yet been
41 // released.
42 struct SourceLocation {
currentSourceLocation43 static SourceLocation current() { return {}; }
file_nameSourceLocation44 absl::string_view file_name() { return "<unknown>"; }
lineSourceLocation45 int line() { return 0; }
46 };
47
48 absl::Status MessageAllocationError(
49 SourceLocation loc = SourceLocation::current());
50
51 absl::Status ExtensionNotFoundError(
52 int extension_number, SourceLocation loc = SourceLocation::current());
53
54 absl::Status MessageDecodeError(upb_DecodeStatus status,
55 SourceLocation loc = SourceLocation::current());
56
57 absl::Status MessageEncodeError(upb_EncodeStatus status,
58 SourceLocation loc = SourceLocation::current());
59
60 namespace internal {
61
62 absl::StatusOr<absl::string_view> Serialize(const upb_Message* message,
63 const upb_MiniTable* mini_table,
64 upb_Arena* arena, int options);
65
66 bool HasExtensionOrUnknown(const upb_Message* msg,
67 const upb_MiniTableExtension* eid);
68
69 bool GetOrPromoteExtension(upb_Message* msg, const upb_MiniTableExtension* eid,
70 upb_Arena* arena, upb_MessageValue* value);
71
72 void DeepCopy(upb_Message* target, const upb_Message* source,
73 const upb_MiniTable* mini_table, upb_Arena* arena);
74
75 upb_Message* DeepClone(const upb_Message* source,
76 const upb_MiniTable* mini_table, upb_Arena* arena);
77
78 absl::Status MoveExtension(upb_Message* message, upb_Arena* message_arena,
79 const upb_MiniTableExtension* ext,
80 upb_Message* extension, upb_Arena* extension_arena);
81
82 absl::Status SetExtension(upb_Message* message, upb_Arena* message_arena,
83 const upb_MiniTableExtension* ext,
84 const upb_Message* extension);
85
86 } // namespace internal
87
88 #ifdef HPB_BACKEND_UPB
89 namespace backend = ::hpb::internal::backend::upb;
90 #endif
91
92 template <typename T, typename Extendee, typename Extension,
93 typename = hpb::internal::EnableIfHpbClass<T>>
HasExtension(Ptr<T> message,const::hpb::internal::ExtensionIdentifier<Extendee,Extension> & id)94 ABSL_MUST_USE_RESULT bool HasExtension(
95 Ptr<T> message,
96 const ::hpb::internal::ExtensionIdentifier<Extendee, Extension>& id) {
97 return ::hpb::internal::HasExtensionOrUnknown(
98 hpb::interop::upb::GetMessage(message), id.mini_table_ext());
99 }
100
101 template <typename T, typename Extendee, typename Extension,
102 typename = hpb::internal::EnableIfHpbClass<T>>
HasExtension(const T * message,const::hpb::internal::ExtensionIdentifier<Extendee,Extension> & id)103 ABSL_MUST_USE_RESULT bool HasExtension(
104 const T* message,
105 const ::hpb::internal::ExtensionIdentifier<Extendee, Extension>& id) {
106 return HasExtension(Ptr(message), id);
107 }
108
109 template <typename T, typename Extension,
110 typename = hpb::internal::EnableIfHpbClass<T>,
111 typename = hpb::internal::EnableIfMutableProto<T>>
ClearExtension(Ptr<T> message,const::hpb::internal::ExtensionIdentifier<T,Extension> & id)112 void ClearExtension(
113 Ptr<T> message,
114 const ::hpb::internal::ExtensionIdentifier<T, Extension>& id) {
115 static_assert(!std::is_const_v<T>, "");
116 upb_Message_ClearExtension(hpb::interop::upb::GetMessage(message),
117 id.mini_table_ext());
118 }
119
120 template <typename T, typename Extension,
121 typename = hpb::internal::EnableIfHpbClass<T>>
ClearExtension(T * message,const::hpb::internal::ExtensionIdentifier<T,Extension> & id)122 void ClearExtension(
123 T* message, const ::hpb::internal::ExtensionIdentifier<T, Extension>& id) {
124 ClearExtension(Ptr(message), id);
125 }
126
127 template <typename T, typename Extension,
128 typename = hpb::internal::EnableIfHpbClass<T>,
129 typename = hpb::internal::EnableIfMutableProto<T>>
SetExtension(Ptr<T> message,const::hpb::internal::ExtensionIdentifier<T,Extension> & id,const Extension & value)130 absl::Status SetExtension(
131 Ptr<T> message,
132 const ::hpb::internal::ExtensionIdentifier<T, Extension>& id,
133 const Extension& value) {
134 static_assert(!std::is_const_v<T>);
135 auto* message_arena = hpb::interop::upb::GetArena(message);
136 return ::hpb::internal::SetExtension(hpb::interop::upb::GetMessage(message),
137 message_arena, id.mini_table_ext(),
138 hpb::interop::upb::GetMessage(&value));
139 }
140
141 template <typename T, typename Extension,
142 typename = hpb::internal::EnableIfHpbClass<T>,
143 typename = hpb::internal::EnableIfMutableProto<T>>
SetExtension(Ptr<T> message,const::hpb::internal::ExtensionIdentifier<T,Extension> & id,Ptr<Extension> value)144 absl::Status SetExtension(
145 Ptr<T> message,
146 const ::hpb::internal::ExtensionIdentifier<T, Extension>& id,
147 Ptr<Extension> value) {
148 static_assert(!std::is_const_v<T>);
149 auto* message_arena = hpb::interop::upb::GetArena(message);
150 return ::hpb::internal::SetExtension(hpb::interop::upb::GetMessage(message),
151 message_arena, id.mini_table_ext(),
152 hpb::interop::upb::GetMessage(value));
153 }
154
155 template <typename T, typename Extension,
156 typename = hpb::internal::EnableIfHpbClass<T>,
157 typename = hpb::internal::EnableIfMutableProto<T>>
SetExtension(Ptr<T> message,const::hpb::internal::ExtensionIdentifier<T,Extension> & id,Extension && value)158 absl::Status SetExtension(
159 Ptr<T> message,
160 const ::hpb::internal::ExtensionIdentifier<T, Extension>& id,
161 Extension&& value) {
162 Extension ext = std::move(value);
163 static_assert(!std::is_const_v<T>);
164 auto* message_arena = hpb::interop::upb::GetArena(message);
165 auto* extension_arena = hpb::interop::upb::GetArena(&ext);
166 return ::hpb::internal::MoveExtension(hpb::interop::upb::GetMessage(message),
167 message_arena, id.mini_table_ext(),
168 hpb::interop::upb::GetMessage(&ext),
169 extension_arena);
170 }
171
172 template <typename T, typename Extension,
173 typename = hpb::internal::EnableIfHpbClass<T>>
SetExtension(T * message,const::hpb::internal::ExtensionIdentifier<T,Extension> & id,const Extension & value)174 absl::Status SetExtension(
175 T* message, const ::hpb::internal::ExtensionIdentifier<T, Extension>& id,
176 const Extension& value) {
177 return ::hpb::SetExtension(Ptr(message), id, value);
178 }
179
180 template <typename T, typename Extension,
181 typename = hpb::internal::EnableIfHpbClass<T>>
SetExtension(T * message,const::hpb::internal::ExtensionIdentifier<T,Extension> & id,Extension && value)182 absl::Status SetExtension(
183 T* message, const ::hpb::internal::ExtensionIdentifier<T, Extension>& id,
184 Extension&& value) {
185 return ::hpb::SetExtension(Ptr(message), id, std::forward<Extension>(value));
186 }
187
188 template <typename T, typename Extension,
189 typename = hpb::internal::EnableIfHpbClass<T>>
SetExtension(T * message,const::hpb::internal::ExtensionIdentifier<T,Extension> & id,Ptr<Extension> value)190 absl::Status SetExtension(
191 T* message, const ::hpb::internal::ExtensionIdentifier<T, Extension>& id,
192 Ptr<Extension> value) {
193 return ::hpb::SetExtension(Ptr(message), id, value);
194 }
195
196 template <typename T, typename Extendee, typename Extension,
197 typename = hpb::internal::EnableIfHpbClass<T>>
GetExtension(Ptr<T> message,const::hpb::internal::ExtensionIdentifier<Extendee,Extension> & id)198 absl::StatusOr<Ptr<const Extension>> GetExtension(
199 Ptr<T> message,
200 const ::hpb::internal::ExtensionIdentifier<Extendee, Extension>& id) {
201 // TODO: Fix const correctness issues.
202 upb_MessageValue value;
203 const bool ok = ::hpb::internal::GetOrPromoteExtension(
204 const_cast<upb_Message*>(hpb::interop::upb::GetMessage(message)),
205 id.mini_table_ext(), hpb::interop::upb::GetArena(message), &value);
206 if (!ok) {
207 return ExtensionNotFoundError(
208 upb_MiniTableExtension_Number(id.mini_table_ext()));
209 }
210 return Ptr<const Extension>(::hpb::interop::upb::MakeCHandle<Extension>(
211 (upb_Message*)value.msg_val, hpb::interop::upb::GetArena(message)));
212 }
213
214 template <typename T, typename Extendee, typename Extension,
215 typename = hpb::internal::EnableIfHpbClass<T>>
GetExtension(const T * message,const::hpb::internal::ExtensionIdentifier<Extendee,Extension> & id)216 absl::StatusOr<Ptr<const Extension>> GetExtension(
217 const T* message,
218 const ::hpb::internal::ExtensionIdentifier<Extendee, Extension>& id) {
219 return GetExtension(Ptr(message), id);
220 }
221
222 template <typename T, typename Extension>
ExtensionNumber(::hpb::internal::ExtensionIdentifier<T,Extension> id)223 constexpr uint32_t ExtensionNumber(
224 ::hpb::internal::ExtensionIdentifier<T, Extension> id) {
225 return ::hpb::internal::PrivateAccess::GetExtensionNumber(id);
226 }
227
228 template <typename T>
CreateMessage(::hpb::Arena & arena)229 typename T::Proxy CreateMessage(::hpb::Arena& arena) {
230 return typename T::Proxy(upb_Message_New(T::minitable(), arena.ptr()),
231 arena.ptr());
232 }
233
234 template <typename T>
CloneMessage(Ptr<T> message,upb_Arena * arena)235 typename T::Proxy CloneMessage(Ptr<T> message, upb_Arena* arena) {
236 return ::hpb::internal::PrivateAccess::Proxy<T>(
237 ::hpb::internal::DeepClone(hpb::interop::upb::GetMessage(message),
238 T::minitable(), arena),
239 arena);
240 }
241
242 template <typename T>
DeepCopy(Ptr<const T> source_message,Ptr<T> target_message)243 void DeepCopy(Ptr<const T> source_message, Ptr<T> target_message) {
244 static_assert(!std::is_const_v<T>);
245 ::hpb::internal::DeepCopy(hpb::interop::upb::GetMessage(target_message),
246 hpb::interop::upb::GetMessage(source_message),
247 T::minitable(),
248 hpb::interop::upb::GetArena(target_message));
249 }
250
251 template <typename T>
DeepCopy(Ptr<const T> source_message,T * target_message)252 void DeepCopy(Ptr<const T> source_message, T* target_message) {
253 static_assert(!std::is_const_v<T>);
254 DeepCopy(source_message, Ptr(target_message));
255 }
256
257 template <typename T>
DeepCopy(const T * source_message,Ptr<T> target_message)258 void DeepCopy(const T* source_message, Ptr<T> target_message) {
259 static_assert(!std::is_const_v<T>);
260 DeepCopy(Ptr(source_message), target_message);
261 }
262
263 template <typename T>
DeepCopy(const T * source_message,T * target_message)264 void DeepCopy(const T* source_message, T* target_message) {
265 static_assert(!std::is_const_v<T>);
266 DeepCopy(Ptr(source_message), Ptr(target_message));
267 }
268
269 template <typename T>
ClearMessage(hpb::internal::PtrOrRaw<T> message)270 void ClearMessage(hpb::internal::PtrOrRaw<T> message) {
271 backend::ClearMessage(message);
272 }
273
274 template <typename T>
Parse(Ptr<T> message,absl::string_view bytes)275 ABSL_MUST_USE_RESULT bool Parse(Ptr<T> message, absl::string_view bytes) {
276 static_assert(!std::is_const_v<T>);
277 upb_Message_Clear(hpb::interop::upb::GetMessage(message),
278 ::hpb::interop::upb::GetMiniTable(message));
279 auto* arena = hpb::interop::upb::GetArena(message);
280 return upb_Decode(bytes.data(), bytes.size(),
281 hpb::interop::upb::GetMessage(message),
282 ::hpb::interop::upb::GetMiniTable(message),
283 /* extreg= */ nullptr, /* options= */ 0,
284 arena) == kUpb_DecodeStatus_Ok;
285 }
286
287 template <typename T>
Parse(Ptr<T> message,absl::string_view bytes,const::hpb::ExtensionRegistry & extension_registry)288 ABSL_MUST_USE_RESULT bool Parse(
289 Ptr<T> message, absl::string_view bytes,
290 const ::hpb::ExtensionRegistry& extension_registry) {
291 static_assert(!std::is_const_v<T>);
292 upb_Message_Clear(hpb::interop::upb::GetMessage(message),
293 ::hpb::interop::upb::GetMiniTable(message));
294 auto* arena = hpb::interop::upb::GetArena(message);
295 return upb_Decode(bytes.data(), bytes.size(),
296 hpb::interop::upb::GetMessage(message),
297 ::hpb::interop::upb::GetMiniTable(message),
298 /* extreg= */
299 ::hpb::internal::GetUpbExtensions(extension_registry),
300 /* options= */ 0, arena) == kUpb_DecodeStatus_Ok;
301 }
302
303 template <typename T>
Parse(T * message,absl::string_view bytes,const::hpb::ExtensionRegistry & extension_registry)304 ABSL_MUST_USE_RESULT bool Parse(
305 T* message, absl::string_view bytes,
306 const ::hpb::ExtensionRegistry& extension_registry) {
307 static_assert(!std::is_const_v<T>);
308 return Parse(Ptr(message, bytes, extension_registry));
309 }
310
311 template <typename T>
Parse(T * message,absl::string_view bytes)312 ABSL_MUST_USE_RESULT bool Parse(T* message, absl::string_view bytes) {
313 static_assert(!std::is_const_v<T>);
314 upb_Message_Clear(hpb::interop::upb::GetMessage(message),
315 ::hpb::interop::upb::GetMiniTable(message));
316 auto* arena = hpb::interop::upb::GetArena(message);
317 return upb_Decode(bytes.data(), bytes.size(),
318 hpb::interop::upb::GetMessage(message),
319 ::hpb::interop::upb::GetMiniTable(message),
320 /* extreg= */ nullptr, /* options= */ 0,
321 arena) == kUpb_DecodeStatus_Ok;
322 }
323
324 template <typename T>
325 absl::StatusOr<T> Parse(absl::string_view bytes, int options = 0) {
326 T message;
327 auto* arena = hpb::interop::upb::GetArena(&message);
328 upb_DecodeStatus status =
329 upb_Decode(bytes.data(), bytes.size(), message.msg(),
330 ::hpb::interop::upb::GetMiniTable(&message),
331 /* extreg= */ nullptr, /* options= */ 0, arena);
332 if (status == kUpb_DecodeStatus_Ok) {
333 return message;
334 }
335 return MessageDecodeError(status);
336 }
337
338 template <typename T>
339 absl::StatusOr<T> Parse(absl::string_view bytes,
340 const ::hpb::ExtensionRegistry& extension_registry,
341 int options = 0) {
342 T message;
343 auto* arena = hpb::interop::upb::GetArena(&message);
344 upb_DecodeStatus status =
345 upb_Decode(bytes.data(), bytes.size(), message.msg(),
346 ::hpb::interop::upb::GetMiniTable(&message),
347 ::hpb::internal::GetUpbExtensions(extension_registry),
348 /* options= */ 0, arena);
349 if (status == kUpb_DecodeStatus_Ok) {
350 return message;
351 }
352 return MessageDecodeError(status);
353 }
354
355 template <typename T>
356 absl::StatusOr<absl::string_view> Serialize(const T* message, upb::Arena& arena,
357 int options = 0) {
358 return ::hpb::internal::Serialize(hpb::interop::upb::GetMessage(message),
359 ::hpb::interop::upb::GetMiniTable(message),
360 arena.ptr(), options);
361 }
362
363 template <typename T>
364 absl::StatusOr<absl::string_view> Serialize(Ptr<T> message, upb::Arena& arena,
365 int options = 0) {
366 return ::hpb::internal::Serialize(hpb::interop::upb::GetMessage(message),
367 ::hpb::interop::upb::GetMiniTable(message),
368 arena.ptr(), options);
369 }
370
371 } // namespace hpb
372
373 #endif // PROTOBUF_HPB_HPB_H_
374