|  | // 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 | 
|  |  | 
|  | #include "hpb/internal/message_lock.h" | 
|  |  | 
|  | #include <atomic> | 
|  | #include <cstddef> | 
|  | #include <cstdint> | 
|  |  | 
|  | #include "absl/status/statusor.h" | 
|  | #include "absl/strings/string_view.h" | 
|  | #include "hpb/status.h" | 
|  | #include "upb/mem/arena.h" | 
|  | #include "upb/message/accessors.h" | 
|  | #include "upb/message/array.h" | 
|  | #include "upb/message/copy.h" | 
|  | #include "upb/message/message.h" | 
|  | #include "upb/message/promote.h" | 
|  | #include "upb/mini_table/extension.h" | 
|  | #include "upb/mini_table/message.h" | 
|  | #include "upb/wire/encode.h" | 
|  |  | 
|  | namespace hpb::internal { | 
|  |  | 
|  | std::atomic<UpbExtensionLocker> upb_extension_locker_global; | 
|  |  | 
|  | /** | 
|  | * MessageLock(msg) acquires lock on msg when constructed and releases it when | 
|  | * destroyed. | 
|  | */ | 
|  | class MessageLock { | 
|  | public: | 
|  | explicit MessageLock(const upb_Message* msg) : msg_(msg) { | 
|  | UpbExtensionLocker locker = | 
|  | upb_extension_locker_global.load(std::memory_order_acquire); | 
|  | unlocker_ = (locker != nullptr) ? locker(msg) : nullptr; | 
|  | } | 
|  | MessageLock(const MessageLock&) = delete; | 
|  | void operator=(const MessageLock&) = delete; | 
|  | ~MessageLock() { | 
|  | if (unlocker_ != nullptr) { | 
|  | unlocker_(msg_); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | const upb_Message* msg_; | 
|  | UpbExtensionUnlocker unlocker_; | 
|  | }; | 
|  |  | 
|  | bool HasExtensionOrUnknown(const upb_Message* msg, | 
|  | const upb_MiniTableExtension* eid) { | 
|  | MessageLock msg_lock(msg); | 
|  | if (upb_Message_HasExtension(msg, eid)) return true; | 
|  |  | 
|  | const uint32_t number = upb_MiniTableExtension_Number(eid); | 
|  | return upb_Message_FindUnknown(msg, number, 0).status == kUpb_FindUnknown_Ok; | 
|  | } | 
|  |  | 
|  | bool GetOrPromoteExtension(const upb_Message* msg, | 
|  | const upb_MiniTableExtension* eid, upb_Arena* arena, | 
|  | upb_MessageValue* value) { | 
|  | // TODO: Fix const correctness issues. | 
|  | auto mutable_msg = const_cast<upb_Message*>(msg); | 
|  | MessageLock msg_lock(mutable_msg); | 
|  | upb_GetExtension_Status ext_status = | 
|  | upb_Message_GetOrPromoteExtension(mutable_msg, eid, 0, arena, value); | 
|  | return ext_status == kUpb_GetExtension_Ok; | 
|  | } | 
|  |  | 
|  | absl::StatusOr<absl::string_view> Serialize(const upb_Message* message, | 
|  | const upb_MiniTable* mini_table, | 
|  | upb_Arena* arena, int options) { | 
|  | MessageLock msg_lock(message); | 
|  | size_t len; | 
|  | char* ptr; | 
|  | upb_EncodeStatus status = | 
|  | upb_Encode(message, mini_table, options, arena, &ptr, &len); | 
|  | if (status == kUpb_EncodeStatus_Ok) { | 
|  | return absl::string_view(ptr, len); | 
|  | } | 
|  | return MessageEncodeError(status); | 
|  | } | 
|  |  | 
|  | void DeepCopy(upb_Message* target, const upb_Message* source, | 
|  | const upb_MiniTable* mini_table, upb_Arena* arena) { | 
|  | MessageLock msg_lock(source); | 
|  | upb_Message_DeepCopy(target, source, mini_table, arena); | 
|  | } | 
|  |  | 
|  | upb_Message* DeepClone(const upb_Message* source, | 
|  | const upb_MiniTable* mini_table, upb_Arena* arena) { | 
|  | MessageLock msg_lock(source); | 
|  | return upb_Message_DeepClone(source, mini_table, arena); | 
|  | } | 
|  |  | 
|  | }  // namespace hpb::internal |