blob: 888bbb4bbdf1d40a4535e2111d8f1e2aa3565429 [file] [log] [blame]
Adam Cozzette501ecec2023-09-26 14:36:20 -07001// Protocol Buffers - Google's data interchange format
2// Copyright 2023 Google LLC. All rights reserved.
Adam Cozzette501ecec2023-09-26 14:36:20 -07003//
Protobuf Team Bot0fab7732023-11-20 13:38:15 -08004// 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
Adam Cozzette501ecec2023-09-26 14:36:20 -07007
8#include "protos/protos.h"
9
10#include <atomic>
11#include <cstddef>
12
13#include "absl/status/status.h"
14#include "absl/status/statusor.h"
15#include "absl/strings/str_format.h"
16#include "absl/strings/string_view.h"
17#include "protos/protos_extension_lock.h"
18#include "upb/mem/arena.h"
19#include "upb/message/copy.h"
20#include "upb/message/internal/extension.h"
21#include "upb/message/promote.h"
22#include "upb/message/types.h"
23#include "upb/mini_table/extension.h"
24#include "upb/mini_table/extension_registry.h"
25#include "upb/mini_table/message.h"
26#include "upb/wire/decode.h"
27#include "upb/wire/encode.h"
28
29namespace protos {
30
31// begin:google_only
32// absl::Status MessageAllocationError(SourceLocation loc) {
33// return absl::Status(absl::StatusCode::kInternal,
34// "Upb message allocation error", loc);
35// }
36//
37// absl::Status ExtensionNotFoundError(int extension_number, SourceLocation loc) {
38// return absl::Status(
39// absl::StatusCode::kInternal,
40// absl::StrFormat("Extension %d not found", extension_number), loc);
41// }
42//
43// absl::Status MessageEncodeError(upb_EncodeStatus status, SourceLocation loc) {
44// return absl::Status(absl::StatusCode::kInternal,
45// absl::StrFormat("Upb message encoding error %d", status),
46// loc
47//
48// );
49// }
50//
51// absl::Status MessageDecodeError(upb_DecodeStatus status, SourceLocation loc
52//
53// ) {
54// return absl::Status(absl::StatusCode::kInternal,
55// absl::StrFormat("Upb message parse error %d", status), loc
56//
57// );
58// }
59// end:google_only
60
61// begin:github_only
62absl::Status MessageAllocationError(SourceLocation loc) {
63 return absl::Status(absl::StatusCode::kUnknown,
64 "Upb message allocation error");
65}
66
67absl::Status ExtensionNotFoundError(int ext_number, SourceLocation loc) {
68 return absl::Status(absl::StatusCode::kUnknown,
69 absl::StrFormat("Extension %d not found", ext_number));
70}
71
72absl::Status MessageEncodeError(upb_EncodeStatus s, SourceLocation loc) {
73 return absl::Status(absl::StatusCode::kUnknown, "Encoding error");
74}
75
76absl::Status MessageDecodeError(upb_DecodeStatus status, SourceLocation loc
77
78) {
79 return absl::Status(absl::StatusCode::kUnknown, "Upb message parse error");
80}
81// end:github_only
82
83namespace internal {
84
85upb_ExtensionRegistry* GetUpbExtensions(
86 const ExtensionRegistry& extension_registry) {
87 return extension_registry.registry_;
88}
89
90/**
91 * MessageLock(msg) acquires lock on msg when constructed and releases it when
92 * destroyed.
93 */
94class MessageLock {
95 public:
96 explicit MessageLock(const upb_Message* msg) : msg_(msg) {
97 UpbExtensionLocker locker =
98 upb_extension_locker_global.load(std::memory_order_acquire);
99 unlocker_ = (locker != nullptr) ? locker(msg) : nullptr;
100 }
101 MessageLock(const MessageLock&) = delete;
102 void operator=(const MessageLock&) = delete;
103 ~MessageLock() {
104 if (unlocker_ != nullptr) {
105 unlocker_(msg_);
106 }
107 }
108
109 private:
110 const upb_Message* msg_;
111 UpbExtensionUnlocker unlocker_;
112};
113
114bool HasExtensionOrUnknown(const upb_Message* msg,
115 const upb_MiniTableExtension* eid) {
116 MessageLock msg_lock(msg);
117 return _upb_Message_Getext(msg, eid) != nullptr ||
Eric Saloa8c3eb72023-12-05 10:39:53 -0800118 upb_Message_FindUnknown(msg, upb_MiniTableExtension_Number(eid), 0)
Eric Salo21133d52023-11-27 18:40:50 -0800119 .status == kUpb_FindUnknown_Ok;
Adam Cozzette501ecec2023-09-26 14:36:20 -0700120}
121
122const upb_Message_Extension* GetOrPromoteExtension(
123 upb_Message* msg, const upb_MiniTableExtension* eid, upb_Arena* arena) {
124 MessageLock msg_lock(msg);
125 const upb_Message_Extension* ext = _upb_Message_Getext(msg, eid);
126 if (ext == nullptr) {
127 upb_GetExtension_Status ext_status = upb_MiniTable_GetOrPromoteExtension(
128 (upb_Message*)msg, eid, 0, arena, &ext);
129 if (ext_status != kUpb_GetExtension_Ok) {
130 ext = nullptr;
131 }
132 }
133 return ext;
134}
135
136absl::StatusOr<absl::string_view> Serialize(const upb_Message* message,
137 const upb_MiniTable* mini_table,
138 upb_Arena* arena, int options) {
139 MessageLock msg_lock(message);
140 size_t len;
141 char* ptr;
142 upb_EncodeStatus status =
143 upb_Encode(message, mini_table, options, arena, &ptr, &len);
144 if (status == kUpb_EncodeStatus_Ok) {
145 return absl::string_view(ptr, len);
146 }
147 return MessageEncodeError(status);
148}
149
150void DeepCopy(upb_Message* target, const upb_Message* source,
151 const upb_MiniTable* mini_table, upb_Arena* arena) {
152 MessageLock msg_lock(source);
153 upb_Message_DeepCopy(target, source, mini_table, arena);
154}
155
156upb_Message* DeepClone(const upb_Message* source,
157 const upb_MiniTable* mini_table, upb_Arena* arena) {
158 MessageLock msg_lock(source);
159 return upb_Message_DeepClone(source, mini_table, arena);
160}
161
162absl::Status MoveExtension(upb_Message* message, upb_Arena* message_arena,
163 const upb_MiniTableExtension* ext,
164 upb_Message* extension, upb_Arena* extension_arena) {
165 upb_Message_Extension* msg_ext =
166 _upb_Message_GetOrCreateExtension(message, ext, message_arena);
167 if (!msg_ext) {
168 return MessageAllocationError();
169 }
170 if (message_arena != extension_arena) {
171 // Try fuse, if fusing is not allowed or fails, create copy of extension.
172 if (!upb_Arena_Fuse(message_arena, extension_arena)) {
Eric Salo21133d52023-11-27 18:40:50 -0800173 msg_ext->data.ptr = DeepClone(
174 extension, upb_MiniTableExtension_GetSubMessage(msg_ext->ext),
175 message_arena);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700176 return absl::OkStatus();
177 }
178 }
179 msg_ext->data.ptr = extension;
180 return absl::OkStatus();
181}
182
183absl::Status SetExtension(upb_Message* message, upb_Arena* message_arena,
184 const upb_MiniTableExtension* ext,
185 const upb_Message* extension) {
186 upb_Message_Extension* msg_ext =
187 _upb_Message_GetOrCreateExtension(message, ext, message_arena);
188 if (!msg_ext) {
189 return MessageAllocationError();
190 }
191 // Clone extension into target message arena.
192 msg_ext->data.ptr =
Eric Salo21133d52023-11-27 18:40:50 -0800193 DeepClone(extension, upb_MiniTableExtension_GetSubMessage(msg_ext->ext),
194 message_arena);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700195 return absl::OkStatus();
196}
197
198} // namespace internal
199
200} // namespace protos