Coverage Report

Created: 2026-05-27 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/common/values/parsed_message_value.cc
Line
Count
Source
1
// Copyright 2024 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "common/values/parsed_message_value.h"
16
17
#include <cstdint>
18
#include <limits>
19
#include <string>
20
#include <type_traits>
21
#include <utility>
22
#include <vector>
23
24
#include "google/protobuf/empty.pb.h"
25
#include "absl/base/nullability.h"
26
#include "absl/base/optimization.h"
27
#include "absl/log/absl_check.h"
28
#include "absl/status/status.h"
29
#include "absl/status/statusor.h"
30
#include "absl/strings/str_cat.h"
31
#include "absl/strings/string_view.h"
32
#include "absl/types/optional.h"
33
#include "absl/types/span.h"
34
#include "base/attribute.h"
35
#include "common/memory.h"
36
#include "common/value.h"
37
#include "extensions/protobuf/internal/qualify.h"
38
#include "internal/empty_descriptors.h"
39
#include "internal/json.h"
40
#include "internal/message_equality.h"
41
#include "internal/status_macros.h"
42
#include "internal/well_known_types.h"
43
#include "runtime/runtime_options.h"
44
#include "google/protobuf/arena.h"
45
#include "google/protobuf/descriptor.h"
46
#include "google/protobuf/io/zero_copy_stream.h"
47
#include "google/protobuf/message.h"
48
#include "google/protobuf/message_lite.h"
49
50
namespace cel {
51
52
namespace {
53
54
using ::cel::well_known_types::ValueReflection;
55
56
template <typename T>
57
std::enable_if_t<std::is_base_of_v<google::protobuf::Message, T>,
58
                 const google::protobuf::Message* absl_nonnull>
59
0
EmptyParsedMessageValue() {
60
0
  return &T::default_instance();
61
0
}
62
63
template <typename T>
64
std::enable_if_t<
65
    std::conjunction_v<std::is_base_of<google::protobuf::MessageLite, T>,
66
                       std::negation<std::is_base_of<google::protobuf::Message, T>>>,
67
    const google::protobuf::Message* absl_nonnull>
68
EmptyParsedMessageValue() {
69
  return internal::GetEmptyDefaultInstance();
70
}
71
72
}  // namespace
73
74
ParsedMessageValue::ParsedMessageValue()
75
0
    : value_(EmptyParsedMessageValue<google::protobuf::Empty>()),
76
0
      arena_(nullptr) {}
77
78
0
bool ParsedMessageValue::IsZeroValue() const {
79
0
  const auto* reflection = GetReflection();
80
0
  if (!reflection->GetUnknownFields(*value_).empty()) {
81
0
    return false;
82
0
  }
83
0
  std::vector<const google::protobuf::FieldDescriptor*> fields;
84
0
  reflection->ListFields(*value_, &fields);
85
0
  return fields.empty();
86
0
}
87
88
0
std::string ParsedMessageValue::DebugString() const {
89
0
  return absl::StrCat(*value_);
90
0
}
91
92
absl::Status ParsedMessageValue::SerializeTo(
93
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
94
    google::protobuf::MessageFactory* absl_nonnull message_factory,
95
0
    google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const {
96
0
  ABSL_DCHECK(descriptor_pool != nullptr);
97
0
  ABSL_DCHECK(message_factory != nullptr);
98
0
  ABSL_DCHECK(output != nullptr);
99
100
0
  if (!value_->SerializePartialToZeroCopyStream(output)) {
101
0
    return absl::UnknownError(
102
0
        absl::StrCat("failed to serialize message: ", value_->GetTypeName()));
103
0
  }
104
0
  return absl::OkStatus();
105
0
}
106
107
absl::Status ParsedMessageValue::ConvertToJson(
108
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
109
    google::protobuf::MessageFactory* absl_nonnull message_factory,
110
0
    google::protobuf::Message* absl_nonnull json) const {
111
0
  ABSL_DCHECK(descriptor_pool != nullptr);
112
0
  ABSL_DCHECK(message_factory != nullptr);
113
0
  ABSL_DCHECK(json != nullptr);
114
0
  ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(),
115
0
                 google::protobuf::Descriptor::WELLKNOWNTYPE_VALUE);
116
117
0
  ValueReflection value_reflection;
118
0
  CEL_RETURN_IF_ERROR(value_reflection.Initialize(json->GetDescriptor()));
119
0
  google::protobuf::Message* json_object = value_reflection.MutableStructValue(json);
120
121
0
  return internal::MessageToJson(*value_, descriptor_pool, message_factory,
122
0
                                 json_object);
123
0
}
124
125
absl::Status ParsedMessageValue::ConvertToJsonObject(
126
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
127
    google::protobuf::MessageFactory* absl_nonnull message_factory,
128
0
    google::protobuf::Message* absl_nonnull json) const {
129
0
  ABSL_DCHECK(descriptor_pool != nullptr);
130
0
  ABSL_DCHECK(message_factory != nullptr);
131
0
  ABSL_DCHECK(json != nullptr);
132
0
  ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(),
133
0
                 google::protobuf::Descriptor::WELLKNOWNTYPE_STRUCT);
134
135
0
  return internal::MessageToJson(*value_, descriptor_pool, message_factory,
136
0
                                 json);
137
0
}
138
139
absl::Status ParsedMessageValue::Equal(
140
    const Value& other,
141
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
142
    google::protobuf::MessageFactory* absl_nonnull message_factory,
143
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
144
0
  ABSL_DCHECK(descriptor_pool != nullptr);
145
0
  ABSL_DCHECK(message_factory != nullptr);
146
0
  ABSL_DCHECK(arena != nullptr);
147
0
  ABSL_DCHECK(result != nullptr);
148
149
0
  if (auto other_message = other.AsParsedMessage(); other_message) {
150
0
    CEL_ASSIGN_OR_RETURN(
151
0
        auto equal, internal::MessageEquals(*value_, **other_message,
152
0
                                            descriptor_pool, message_factory));
153
0
    *result = BoolValue(equal);
154
0
    return absl::OkStatus();
155
0
  }
156
0
  if (auto other_struct = other.AsStruct(); other_struct) {
157
0
    return common_internal::StructValueEqual(StructValue(*this), *other_struct,
158
0
                                             descriptor_pool, message_factory,
159
0
                                             arena, result);
160
0
  }
161
0
  *result = BoolValue(false);
162
0
  return absl::OkStatus();
163
0
}
164
165
ParsedMessageValue ParsedMessageValue::Clone(
166
0
    google::protobuf::Arena* absl_nonnull arena) const {
167
0
  ABSL_DCHECK(arena != nullptr);
168
169
0
  if (arena_ == arena) {
170
0
    return *this;
171
0
  }
172
0
  auto* cloned = value_->New(arena);
173
0
  cloned->CopyFrom(*value_);
174
0
  return ParsedMessageValue(cloned, arena);
175
0
}
176
177
absl::Status ParsedMessageValue::GetFieldByName(
178
    absl::string_view name, ProtoWrapperTypeOptions unboxing_options,
179
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
180
    google::protobuf::MessageFactory* absl_nonnull message_factory,
181
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
182
0
  ABSL_DCHECK(descriptor_pool != nullptr);
183
0
  ABSL_DCHECK(message_factory != nullptr);
184
0
  ABSL_DCHECK(arena != nullptr);
185
0
  ABSL_DCHECK(result != nullptr);
186
187
0
  const auto* descriptor = GetDescriptor();
188
0
  const auto* field = descriptor->FindFieldByName(name);
189
0
  if (field == nullptr) {
190
0
    field = descriptor->file()->pool()->FindExtensionByPrintableName(descriptor,
191
0
                                                                     name);
192
0
    if (field == nullptr) {
193
0
      *result = NoSuchFieldError(name);
194
0
      return absl::OkStatus();
195
0
    }
196
0
  }
197
0
  return GetField(field, unboxing_options, descriptor_pool, message_factory,
198
0
                  arena, result);
199
0
}
200
201
absl::Status ParsedMessageValue::GetFieldByNumber(
202
    int64_t number, ProtoWrapperTypeOptions unboxing_options,
203
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
204
    google::protobuf::MessageFactory* absl_nonnull message_factory,
205
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
206
0
  ABSL_DCHECK(descriptor_pool != nullptr);
207
0
  ABSL_DCHECK(message_factory != nullptr);
208
0
  ABSL_DCHECK(arena != nullptr);
209
0
  ABSL_DCHECK(result != nullptr);
210
211
0
  const auto* descriptor = GetDescriptor();
212
0
  if (number < std::numeric_limits<int32_t>::min() ||
213
0
      number > std::numeric_limits<int32_t>::max()) {
214
0
    *result = NoSuchFieldError(absl::StrCat(number));
215
0
    return absl::OkStatus();
216
0
  }
217
0
  const auto* field = descriptor->FindFieldByNumber(static_cast<int>(number));
218
0
  if (field == nullptr) {
219
0
    *result = NoSuchFieldError(absl::StrCat(number));
220
0
    return absl::OkStatus();
221
0
  }
222
0
  return GetField(field, unboxing_options, descriptor_pool, message_factory,
223
0
                  arena, result);
224
0
}
225
226
absl::StatusOr<bool> ParsedMessageValue::HasFieldByName(
227
0
    absl::string_view name) const {
228
0
  const auto* descriptor = GetDescriptor();
229
0
  const auto* field = descriptor->FindFieldByName(name);
230
0
  if (field == nullptr) {
231
0
    field = descriptor->file()->pool()->FindExtensionByPrintableName(descriptor,
232
0
                                                                     name);
233
0
    if (field == nullptr) {
234
0
      return NoSuchFieldError(name).NativeValue();
235
0
    }
236
0
  }
237
0
  return HasField(field);
238
0
}
239
240
absl::StatusOr<bool> ParsedMessageValue::HasFieldByNumber(
241
0
    int64_t number) const {
242
0
  const auto* descriptor = GetDescriptor();
243
0
  if (number < std::numeric_limits<int32_t>::min() ||
244
0
      number > std::numeric_limits<int32_t>::max()) {
245
0
    return NoSuchFieldError(absl::StrCat(number)).NativeValue();
246
0
  }
247
0
  const auto* field = descriptor->FindFieldByNumber(static_cast<int>(number));
248
0
  if (field == nullptr) {
249
0
    return NoSuchFieldError(absl::StrCat(number)).NativeValue();
250
0
  }
251
0
  return HasField(field);
252
0
}
253
254
absl::Status ParsedMessageValue::ForEachField(
255
    ForEachFieldCallback callback,
256
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
257
    google::protobuf::MessageFactory* absl_nonnull message_factory,
258
0
    google::protobuf::Arena* absl_nonnull arena) const {
259
0
  ABSL_DCHECK(descriptor_pool != nullptr);
260
0
  ABSL_DCHECK(message_factory != nullptr);
261
0
  ABSL_DCHECK(arena != nullptr);
262
263
0
  std::vector<const google::protobuf::FieldDescriptor*> fields;
264
0
  const auto* reflection = GetReflection();
265
0
  reflection->ListFields(*value_, &fields);
266
0
  for (const auto* field : fields) {
267
0
    auto value = Value::WrapField(value_, field, descriptor_pool,
268
0
                                  message_factory, arena);
269
0
    CEL_ASSIGN_OR_RETURN(auto ok, callback(field->name(), value));
270
0
    if (!ok) {
271
0
      break;
272
0
    }
273
0
  }
274
0
  return absl::OkStatus();
275
0
}
276
277
namespace {
278
279
class ParsedMessageValueQualifyState final
280
    : public extensions::protobuf_internal::ProtoQualifyState {
281
 public:
282
  ParsedMessageValueQualifyState(
283
      const google::protobuf::Message* absl_nonnull message,
284
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
285
      google::protobuf::MessageFactory* absl_nonnull message_factory,
286
      google::protobuf::Arena* absl_nonnull arena)
287
0
      : ProtoQualifyState(message, message->GetDescriptor(),
288
0
                          message->GetReflection()),
289
0
        descriptor_pool_(descriptor_pool),
290
0
        message_factory_(message_factory),
291
0
        arena_(arena) {}
292
293
0
  absl::optional<Value>& result() { return result_; }
294
295
 private:
296
0
  void SetResultFromError(absl::Status status, cel::MemoryManagerRef) override {
297
0
    result_ = ErrorValue(std::move(status));
298
0
  }
299
300
0
  void SetResultFromBool(bool value) override { result_ = BoolValue(value); }
301
302
  absl::Status SetResultFromField(const google::protobuf::Message* message,
303
                                  const google::protobuf::FieldDescriptor* field,
304
                                  ProtoWrapperTypeOptions unboxing_option,
305
0
                                  cel::MemoryManagerRef) override {
306
0
    result_ = Value::WrapField(unboxing_option, message, field,
307
0
                               descriptor_pool_, message_factory_, arena_);
308
0
    return absl::OkStatus();
309
0
  }
310
311
  absl::Status SetResultFromRepeatedField(const google::protobuf::Message* message,
312
                                          const google::protobuf::FieldDescriptor* field,
313
                                          int index,
314
0
                                          cel::MemoryManagerRef) override {
315
0
    result_ = Value::WrapRepeatedField(index, message, field, descriptor_pool_,
316
0
                                       message_factory_, arena_);
317
0
    return absl::OkStatus();
318
0
  }
319
320
  absl::Status SetResultFromMapField(const google::protobuf::Message* message,
321
                                     const google::protobuf::FieldDescriptor* field,
322
                                     const google::protobuf::MapValueConstRef& value,
323
0
                                     cel::MemoryManagerRef) override {
324
0
    result_ = Value::WrapMapFieldValue(value, message, field, descriptor_pool_,
325
0
                                       message_factory_, arena_);
326
0
    return absl::OkStatus();
327
0
  }
328
329
  const google::protobuf::DescriptorPool* absl_nonnull const descriptor_pool_;
330
  google::protobuf::MessageFactory* absl_nonnull const message_factory_;
331
  google::protobuf::Arena* absl_nonnull const arena_;
332
  absl::optional<Value> result_;
333
};
334
335
}  // namespace
336
337
absl::Status ParsedMessageValue::Qualify(
338
    absl::Span<const SelectQualifier> qualifiers, bool presence_test,
339
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
340
    google::protobuf::MessageFactory* absl_nonnull message_factory,
341
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result,
342
0
    int* absl_nonnull count) const {
343
0
  ABSL_DCHECK(!qualifiers.empty());
344
0
  ABSL_DCHECK(descriptor_pool != nullptr);
345
0
  ABSL_DCHECK(message_factory != nullptr);
346
0
  ABSL_DCHECK(arena != nullptr);
347
0
  ABSL_DCHECK(result != nullptr);
348
0
  ABSL_DCHECK(count != nullptr);
349
350
0
  if (ABSL_PREDICT_FALSE(qualifiers.empty())) {
351
0
    return absl::InvalidArgumentError("invalid select qualifier path.");
352
0
  }
353
0
  ParsedMessageValueQualifyState qualify_state(value_, descriptor_pool,
354
0
                                               message_factory, arena);
355
0
  for (int i = 0; i < qualifiers.size() - 1; i++) {
356
0
    const auto& qualifier = qualifiers[i];
357
0
    CEL_RETURN_IF_ERROR(qualify_state.ApplySelectQualifier(
358
0
        qualifier, MemoryManagerRef::Pooling(arena)));
359
0
    if (qualify_state.result().has_value()) {
360
0
      *result = std::move(qualify_state.result()).value();
361
0
      *count = result->Is<ErrorValue>() ? -1 : i + 1;
362
0
      return absl::OkStatus();
363
0
    }
364
0
  }
365
0
  const auto& last_qualifier = qualifiers.back();
366
0
  if (presence_test) {
367
0
    CEL_RETURN_IF_ERROR(qualify_state.ApplyLastQualifierHas(
368
0
        last_qualifier, MemoryManagerRef::Pooling(arena)));
369
0
  } else {
370
0
    CEL_RETURN_IF_ERROR(qualify_state.ApplyLastQualifierGet(
371
0
        last_qualifier, MemoryManagerRef::Pooling(arena)));
372
0
  }
373
0
  *result = std::move(qualify_state.result()).value();
374
0
  *count = -1;
375
0
  return absl::OkStatus();
376
0
}
377
378
absl::Status ParsedMessageValue::GetField(
379
    const google::protobuf::FieldDescriptor* absl_nonnull field,
380
    ProtoWrapperTypeOptions unboxing_options,
381
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
382
    google::protobuf::MessageFactory* absl_nonnull message_factory,
383
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
384
0
  ABSL_DCHECK(field != nullptr);
385
0
  ABSL_DCHECK(descriptor_pool != nullptr);
386
0
  ABSL_DCHECK(message_factory != nullptr);
387
0
  ABSL_DCHECK(arena != nullptr);
388
0
  ABSL_DCHECK(result != nullptr);
389
390
0
  if (arena_ == nullptr) {
391
0
    *result = Value::WrapFieldUnsafe(unboxing_options, value_, field,
392
0
                                     descriptor_pool, message_factory, arena);
393
0
  } else {
394
0
    *result = Value::WrapField(unboxing_options, value_, field, descriptor_pool,
395
0
                               message_factory, arena);
396
0
  }
397
0
  return absl::OkStatus();
398
0
}
399
400
bool ParsedMessageValue::HasField(
401
0
    const google::protobuf::FieldDescriptor* absl_nonnull field) const {
402
0
  ABSL_DCHECK(field != nullptr);
403
404
0
  const auto* reflection = GetReflection();
405
0
  if (field->is_map() || field->is_repeated()) {
406
0
    return reflection->FieldSize(*value_, field) > 0;
407
0
  }
408
0
  return reflection->HasField(*value_, field);
409
0
}
410
411
}  // namespace cel