blob: bb5a10d451eb78a6e067e97a0d0db1700343410c [file] [log] [blame]
// 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 "google/protobuf/hpb/internal/message_lock.h"
#include <atomic>
#include <cstddef>
#include <cstdint>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/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