• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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