// Protocol Buffers - Google's data interchange format // Copyright 2023 Google LLC. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd #ifndef PROTOBUF_HPB_HPB_H_ #define PROTOBUF_HPB_HPB_H_ #include #include #include #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "google/protobuf/hpb/arena.h" #include "google/protobuf/hpb/backend/upb/interop.h" #include "google/protobuf/hpb/extension.h" #include "google/protobuf/hpb/internal/internal.h" #include "google/protobuf/hpb/internal/template_help.h" #include "google/protobuf/hpb/ptr.h" #include "upb/base/status.hpp" #include "upb/mem/arena.hpp" #include "upb/message/copy.h" #include "upb/mini_table/extension.h" #include "upb/wire/decode.h" #include "upb/wire/encode.h" #ifdef HPB_BACKEND_UPB #include "google/protobuf/hpb/backend/upb/upb.h" #else #error hpb backend must be specified #endif namespace hpb { class ExtensionRegistry; // TODO: update bzl and move to upb runtime / protos.cc. inline upb_StringView UpbStrFromStringView(absl::string_view str, upb_Arena* arena) { const size_t str_size = str.size(); char* buffer = static_cast(upb_Arena_Malloc(arena, str_size)); memcpy(buffer, str.data(), str_size); return upb_StringView_FromDataAndSize(buffer, str_size); } // This type exists to work around an absl type that has not yet been // released. struct SourceLocation { static SourceLocation current() { return {}; } absl::string_view file_name() { return ""; } int line() { return 0; } }; absl::Status MessageAllocationError( SourceLocation loc = SourceLocation::current()); absl::Status ExtensionNotFoundError( int extension_number, SourceLocation loc = SourceLocation::current()); absl::Status MessageDecodeError(upb_DecodeStatus status, SourceLocation loc = SourceLocation::current()); absl::Status MessageEncodeError(upb_EncodeStatus status, SourceLocation loc = SourceLocation::current()); namespace internal { absl::StatusOr Serialize(const upb_Message* message, const upb_MiniTable* mini_table, upb_Arena* arena, int options); bool HasExtensionOrUnknown(const upb_Message* msg, const upb_MiniTableExtension* eid); bool GetOrPromoteExtension(upb_Message* msg, const upb_MiniTableExtension* eid, upb_Arena* arena, upb_MessageValue* value); void DeepCopy(upb_Message* target, const upb_Message* source, const upb_MiniTable* mini_table, upb_Arena* arena); upb_Message* DeepClone(const upb_Message* source, const upb_MiniTable* mini_table, upb_Arena* arena); absl::Status MoveExtension(upb_Message* message, upb_Arena* message_arena, const upb_MiniTableExtension* ext, upb_Message* extension, upb_Arena* extension_arena); absl::Status SetExtension(upb_Message* message, upb_Arena* message_arena, const upb_MiniTableExtension* ext, const upb_Message* extension); } // namespace internal #ifdef HPB_BACKEND_UPB namespace backend = ::hpb::internal::backend::upb; #endif template > ABSL_MUST_USE_RESULT bool HasExtension( Ptr message, const ::hpb::internal::ExtensionIdentifier& id) { return ::hpb::internal::HasExtensionOrUnknown( hpb::interop::upb::GetMessage(message), id.mini_table_ext()); } template > ABSL_MUST_USE_RESULT bool HasExtension( const T* message, const ::hpb::internal::ExtensionIdentifier& id) { return HasExtension(Ptr(message), id); } template , typename = hpb::internal::EnableIfMutableProto> void ClearExtension( Ptr message, const ::hpb::internal::ExtensionIdentifier& id) { static_assert(!std::is_const_v, ""); upb_Message_ClearExtension(hpb::interop::upb::GetMessage(message), id.mini_table_ext()); } template > void ClearExtension( T* message, const ::hpb::internal::ExtensionIdentifier& id) { ClearExtension(Ptr(message), id); } template , typename = hpb::internal::EnableIfMutableProto> absl::Status SetExtension( Ptr message, const ::hpb::internal::ExtensionIdentifier& id, const Extension& value) { static_assert(!std::is_const_v); auto* message_arena = hpb::interop::upb::GetArena(message); return ::hpb::internal::SetExtension(hpb::interop::upb::GetMessage(message), message_arena, id.mini_table_ext(), hpb::interop::upb::GetMessage(&value)); } template , typename = hpb::internal::EnableIfMutableProto> absl::Status SetExtension( Ptr message, const ::hpb::internal::ExtensionIdentifier& id, Ptr value) { static_assert(!std::is_const_v); auto* message_arena = hpb::interop::upb::GetArena(message); return ::hpb::internal::SetExtension(hpb::interop::upb::GetMessage(message), message_arena, id.mini_table_ext(), hpb::interop::upb::GetMessage(value)); } template , typename = hpb::internal::EnableIfMutableProto> absl::Status SetExtension( Ptr message, const ::hpb::internal::ExtensionIdentifier& id, Extension&& value) { Extension ext = std::move(value); static_assert(!std::is_const_v); auto* message_arena = hpb::interop::upb::GetArena(message); auto* extension_arena = hpb::interop::upb::GetArena(&ext); return ::hpb::internal::MoveExtension(hpb::interop::upb::GetMessage(message), message_arena, id.mini_table_ext(), hpb::interop::upb::GetMessage(&ext), extension_arena); } template > absl::Status SetExtension( T* message, const ::hpb::internal::ExtensionIdentifier& id, const Extension& value) { return ::hpb::SetExtension(Ptr(message), id, value); } template > absl::Status SetExtension( T* message, const ::hpb::internal::ExtensionIdentifier& id, Extension&& value) { return ::hpb::SetExtension(Ptr(message), id, std::forward(value)); } template > absl::Status SetExtension( T* message, const ::hpb::internal::ExtensionIdentifier& id, Ptr value) { return ::hpb::SetExtension(Ptr(message), id, value); } template > absl::StatusOr> GetExtension( Ptr message, const ::hpb::internal::ExtensionIdentifier& id) { // TODO: Fix const correctness issues. upb_MessageValue value; const bool ok = ::hpb::internal::GetOrPromoteExtension( const_cast(hpb::interop::upb::GetMessage(message)), id.mini_table_ext(), hpb::interop::upb::GetArena(message), &value); if (!ok) { return ExtensionNotFoundError( upb_MiniTableExtension_Number(id.mini_table_ext())); } return Ptr(::hpb::interop::upb::MakeCHandle( (upb_Message*)value.msg_val, hpb::interop::upb::GetArena(message))); } template > absl::StatusOr> GetExtension( const T* message, const ::hpb::internal::ExtensionIdentifier& id) { return GetExtension(Ptr(message), id); } template constexpr uint32_t ExtensionNumber( ::hpb::internal::ExtensionIdentifier id) { return ::hpb::internal::PrivateAccess::GetExtensionNumber(id); } template typename T::Proxy CreateMessage(::hpb::Arena& arena) { return typename T::Proxy(upb_Message_New(T::minitable(), arena.ptr()), arena.ptr()); } template typename T::Proxy CloneMessage(Ptr message, upb_Arena* arena) { return ::hpb::internal::PrivateAccess::Proxy( ::hpb::internal::DeepClone(hpb::interop::upb::GetMessage(message), T::minitable(), arena), arena); } template void DeepCopy(Ptr source_message, Ptr target_message) { static_assert(!std::is_const_v); ::hpb::internal::DeepCopy(hpb::interop::upb::GetMessage(target_message), hpb::interop::upb::GetMessage(source_message), T::minitable(), hpb::interop::upb::GetArena(target_message)); } template void DeepCopy(Ptr source_message, T* target_message) { static_assert(!std::is_const_v); DeepCopy(source_message, Ptr(target_message)); } template void DeepCopy(const T* source_message, Ptr target_message) { static_assert(!std::is_const_v); DeepCopy(Ptr(source_message), target_message); } template void DeepCopy(const T* source_message, T* target_message) { static_assert(!std::is_const_v); DeepCopy(Ptr(source_message), Ptr(target_message)); } template void ClearMessage(hpb::internal::PtrOrRaw message) { backend::ClearMessage(message); } template ABSL_MUST_USE_RESULT bool Parse(Ptr message, absl::string_view bytes) { static_assert(!std::is_const_v); upb_Message_Clear(hpb::interop::upb::GetMessage(message), ::hpb::interop::upb::GetMiniTable(message)); auto* arena = hpb::interop::upb::GetArena(message); return upb_Decode(bytes.data(), bytes.size(), hpb::interop::upb::GetMessage(message), ::hpb::interop::upb::GetMiniTable(message), /* extreg= */ nullptr, /* options= */ 0, arena) == kUpb_DecodeStatus_Ok; } template ABSL_MUST_USE_RESULT bool Parse( Ptr message, absl::string_view bytes, const ::hpb::ExtensionRegistry& extension_registry) { static_assert(!std::is_const_v); upb_Message_Clear(hpb::interop::upb::GetMessage(message), ::hpb::interop::upb::GetMiniTable(message)); auto* arena = hpb::interop::upb::GetArena(message); return upb_Decode(bytes.data(), bytes.size(), hpb::interop::upb::GetMessage(message), ::hpb::interop::upb::GetMiniTable(message), /* extreg= */ ::hpb::internal::GetUpbExtensions(extension_registry), /* options= */ 0, arena) == kUpb_DecodeStatus_Ok; } template ABSL_MUST_USE_RESULT bool Parse( T* message, absl::string_view bytes, const ::hpb::ExtensionRegistry& extension_registry) { static_assert(!std::is_const_v); return Parse(Ptr(message, bytes, extension_registry)); } template ABSL_MUST_USE_RESULT bool Parse(T* message, absl::string_view bytes) { static_assert(!std::is_const_v); upb_Message_Clear(hpb::interop::upb::GetMessage(message), ::hpb::interop::upb::GetMiniTable(message)); auto* arena = hpb::interop::upb::GetArena(message); return upb_Decode(bytes.data(), bytes.size(), hpb::interop::upb::GetMessage(message), ::hpb::interop::upb::GetMiniTable(message), /* extreg= */ nullptr, /* options= */ 0, arena) == kUpb_DecodeStatus_Ok; } template absl::StatusOr Parse(absl::string_view bytes, int options = 0) { T message; auto* arena = hpb::interop::upb::GetArena(&message); upb_DecodeStatus status = upb_Decode(bytes.data(), bytes.size(), message.msg(), ::hpb::interop::upb::GetMiniTable(&message), /* extreg= */ nullptr, /* options= */ 0, arena); if (status == kUpb_DecodeStatus_Ok) { return message; } return MessageDecodeError(status); } template absl::StatusOr Parse(absl::string_view bytes, const ::hpb::ExtensionRegistry& extension_registry, int options = 0) { T message; auto* arena = hpb::interop::upb::GetArena(&message); upb_DecodeStatus status = upb_Decode(bytes.data(), bytes.size(), message.msg(), ::hpb::interop::upb::GetMiniTable(&message), ::hpb::internal::GetUpbExtensions(extension_registry), /* options= */ 0, arena); if (status == kUpb_DecodeStatus_Ok) { return message; } return MessageDecodeError(status); } template absl::StatusOr Serialize(const T* message, upb::Arena& arena, int options = 0) { return ::hpb::internal::Serialize(hpb::interop::upb::GetMessage(message), ::hpb::interop::upb::GetMiniTable(message), arena.ptr(), options); } template absl::StatusOr Serialize(Ptr message, upb::Arena& arena, int options = 0) { return ::hpb::internal::Serialize(hpb::interop::upb::GetMessage(message), ::hpb::interop::upb::GetMiniTable(message), arena.ptr(), options); } } // namespace hpb #endif // PROTOBUF_HPB_HPB_H_