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/custom_struct_value.cc
Line
Count
Source
1
// Copyright 2023 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 <cstdint>
16
#include <string>
17
18
#include "absl/base/nullability.h"
19
#include "absl/base/optimization.h"
20
#include "absl/functional/function_ref.h"
21
#include "absl/log/absl_check.h"
22
#include "absl/status/status.h"
23
#include "absl/status/statusor.h"
24
#include "absl/strings/str_cat.h"
25
#include "absl/strings/string_view.h"
26
#include "absl/types/span.h"
27
#include "base/attribute.h"
28
#include "common/native_type.h"
29
#include "common/type.h"
30
#include "common/value.h"
31
#include "common/values/values.h"
32
#include "internal/status_macros.h"
33
#include "internal/well_known_types.h"
34
#include "runtime/runtime_options.h"
35
#include "google/protobuf/arena.h"
36
#include "google/protobuf/descriptor.h"
37
#include "google/protobuf/io/zero_copy_stream.h"
38
#include "google/protobuf/message.h"
39
40
namespace cel {
41
42
namespace {
43
44
using ::cel::well_known_types::ValueReflection;
45
46
}  // namespace
47
48
absl::Status CustomStructValueInterface::Equal(
49
    const StructValue& other,
50
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
51
    google::protobuf::MessageFactory* absl_nonnull message_factory,
52
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
53
0
  return common_internal::StructValueEqual(*this, other, descriptor_pool,
54
0
                                           message_factory, arena, result);
55
0
}
56
57
absl::Status CustomStructValueInterface::Qualify(
58
    absl::Span<const SelectQualifier> qualifiers, bool presence_test,
59
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
60
    google::protobuf::MessageFactory* absl_nonnull message_factory,
61
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result,
62
0
    int* absl_nonnull count) const {
63
0
  return absl::UnimplementedError(absl::StrCat(
64
0
      GetTypeName(), " does not implement field selection optimization"));
65
0
}
66
67
0
NativeTypeId CustomStructValue::GetTypeId() const {
68
0
  if (dispatcher_ == nullptr) {
69
0
    CustomStructValueInterface::Content content =
70
0
        content_.To<CustomStructValueInterface::Content>();
71
0
    if (content.interface == nullptr) {
72
0
      return NativeTypeId();
73
0
    }
74
0
    return content.interface->GetNativeTypeId();
75
0
  }
76
0
  return dispatcher_->get_type_id(dispatcher_, content_);
77
0
}
78
79
0
StructType CustomStructValue::GetRuntimeType() const {
80
0
  ABSL_DCHECK(*this);
81
82
0
  if (dispatcher_ == nullptr) {
83
0
    CustomStructValueInterface::Content content =
84
0
        content_.To<CustomStructValueInterface::Content>();
85
0
    ABSL_DCHECK(content.interface != nullptr);
86
0
    return content.interface->GetRuntimeType();
87
0
  }
88
0
  if (dispatcher_->get_runtime_type != nullptr) {
89
0
    return dispatcher_->get_runtime_type(dispatcher_, content_);
90
0
  }
91
0
  return common_internal::MakeBasicStructType(GetTypeName());
92
0
}
93
94
0
absl::string_view CustomStructValue::GetTypeName() const {
95
0
  ABSL_DCHECK(*this);
96
97
0
  if (dispatcher_ == nullptr) {
98
0
    CustomStructValueInterface::Content content =
99
0
        content_.To<CustomStructValueInterface::Content>();
100
0
    ABSL_DCHECK(content.interface != nullptr);
101
0
    return content.interface->GetTypeName();
102
0
  }
103
0
  return dispatcher_->get_type_name(dispatcher_, content_);
104
0
}
105
106
0
std::string CustomStructValue::DebugString() const {
107
0
  ABSL_DCHECK(*this);
108
109
0
  if (dispatcher_ == nullptr) {
110
0
    CustomStructValueInterface::Content content =
111
0
        content_.To<CustomStructValueInterface::Content>();
112
0
    ABSL_DCHECK(content.interface != nullptr);
113
0
    return content.interface->DebugString();
114
0
  }
115
0
  if (dispatcher_->debug_string != nullptr) {
116
0
    return dispatcher_->debug_string(dispatcher_, content_);
117
0
  }
118
0
  return std::string(GetTypeName());
119
0
}
120
121
absl::Status CustomStructValue::SerializeTo(
122
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
123
    google::protobuf::MessageFactory* absl_nonnull message_factory,
124
0
    google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const {
125
0
  ABSL_DCHECK(*this);
126
127
0
  if (dispatcher_ == nullptr) {
128
0
    CustomStructValueInterface::Content content =
129
0
        content_.To<CustomStructValueInterface::Content>();
130
0
    ABSL_DCHECK(content.interface != nullptr);
131
0
    return content.interface->SerializeTo(descriptor_pool, message_factory,
132
0
                                          output);
133
0
  }
134
0
  if (dispatcher_->serialize_to != nullptr) {
135
0
    return dispatcher_->serialize_to(dispatcher_, content_, descriptor_pool,
136
0
                                     message_factory, output);
137
0
  }
138
0
  return absl::UnimplementedError(
139
0
      absl::StrCat(GetTypeName(), " is unserializable"));
140
0
}
141
142
absl::Status CustomStructValue::ConvertToJson(
143
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
144
    google::protobuf::MessageFactory* absl_nonnull message_factory,
145
0
    google::protobuf::Message* absl_nonnull json) const {
146
0
  ABSL_DCHECK(descriptor_pool != nullptr);
147
0
  ABSL_DCHECK(message_factory != nullptr);
148
0
  ABSL_DCHECK(json != nullptr);
149
0
  ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(),
150
0
                 google::protobuf::Descriptor::WELLKNOWNTYPE_VALUE);
151
0
  ABSL_DCHECK(*this);
152
153
0
  ValueReflection value_reflection;
154
0
  CEL_RETURN_IF_ERROR(value_reflection.Initialize(json->GetDescriptor()));
155
0
  google::protobuf::Message* json_object = value_reflection.MutableStructValue(json);
156
157
0
  return ConvertToJsonObject(descriptor_pool, message_factory, json_object);
158
0
}
159
160
absl::Status CustomStructValue::ConvertToJsonObject(
161
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
162
    google::protobuf::MessageFactory* absl_nonnull message_factory,
163
0
    google::protobuf::Message* absl_nonnull json) const {
164
0
  ABSL_DCHECK(descriptor_pool != nullptr);
165
0
  ABSL_DCHECK(message_factory != nullptr);
166
0
  ABSL_DCHECK(json != nullptr);
167
0
  ABSL_DCHECK(*this);
168
169
0
  if (dispatcher_ == nullptr) {
170
0
    CustomStructValueInterface::Content content =
171
0
        content_.To<CustomStructValueInterface::Content>();
172
0
    if (ABSL_PREDICT_FALSE(content.interface == nullptr)) {
173
0
      json->Clear();
174
0
      return absl::OkStatus();
175
0
    }
176
0
    return content.interface->ConvertToJsonObject(descriptor_pool,
177
0
                                                  message_factory, json);
178
0
  }
179
0
  if (dispatcher_->convert_to_json_object != nullptr) {
180
0
    return dispatcher_->convert_to_json_object(
181
0
        dispatcher_, content_, descriptor_pool, message_factory, json);
182
0
  }
183
0
  return absl::UnimplementedError(
184
0
      absl::StrCat(GetTypeName(), " is not convertable to JSON"));
185
0
}
186
187
absl::Status CustomStructValue::Equal(
188
    const Value& other,
189
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
190
    google::protobuf::MessageFactory* absl_nonnull message_factory,
191
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
192
0
  ABSL_DCHECK(descriptor_pool != nullptr);
193
0
  ABSL_DCHECK(message_factory != nullptr);
194
0
  ABSL_DCHECK(arena != nullptr);
195
0
  ABSL_DCHECK(result != nullptr);
196
0
  ABSL_DCHECK(*this);
197
198
0
  if (auto other_struct_value = other.AsStruct(); other_struct_value) {
199
0
    if (dispatcher_ == nullptr) {
200
0
      CustomStructValueInterface::Content content =
201
0
          content_.To<CustomStructValueInterface::Content>();
202
0
      ABSL_DCHECK(content.interface != nullptr);
203
0
      return content.interface->Equal(*other_struct_value, descriptor_pool,
204
0
                                      message_factory, arena, result);
205
0
    }
206
0
    if (dispatcher_->equal != nullptr) {
207
0
      return dispatcher_->equal(dispatcher_, content_, *other_struct_value,
208
0
                                descriptor_pool, message_factory, arena,
209
0
                                result);
210
0
    }
211
0
    return common_internal::StructValueEqual(*this, *other_struct_value,
212
0
                                             descriptor_pool, message_factory,
213
0
                                             arena, result);
214
0
  }
215
0
  *result = FalseValue();
216
0
  return absl::OkStatus();
217
0
}
218
219
0
bool CustomStructValue::IsZeroValue() const {
220
0
  ABSL_DCHECK(*this);
221
222
0
  if (dispatcher_ == nullptr) {
223
0
    CustomStructValueInterface::Content content =
224
0
        content_.To<CustomStructValueInterface::Content>();
225
0
    if (content.interface == nullptr) {
226
0
      return true;
227
0
    }
228
0
    return content.interface->IsZeroValue();
229
0
  }
230
0
  return dispatcher_->is_zero_value(dispatcher_, content_);
231
0
}
232
233
CustomStructValue CustomStructValue::Clone(
234
0
    google::protobuf::Arena* absl_nonnull arena) const {
235
0
  ABSL_DCHECK(arena != nullptr);
236
0
  ABSL_DCHECK(*this);
237
238
0
  if (dispatcher_ == nullptr) {
239
0
    CustomStructValueInterface::Content content =
240
0
        content_.To<CustomStructValueInterface::Content>();
241
0
    if (content.interface == nullptr) {
242
0
      return *this;
243
0
    }
244
0
    if (content.arena != arena) {
245
0
      return content.interface->Clone(arena);
246
0
    }
247
0
    return *this;
248
0
  }
249
0
  return dispatcher_->clone(dispatcher_, content_, arena);
250
0
}
251
252
absl::Status CustomStructValue::GetFieldByName(
253
    absl::string_view name, ProtoWrapperTypeOptions unboxing_options,
254
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
255
    google::protobuf::MessageFactory* absl_nonnull message_factory,
256
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
257
0
  ABSL_DCHECK(descriptor_pool != nullptr);
258
0
  ABSL_DCHECK(message_factory != nullptr);
259
0
  ABSL_DCHECK(arena != nullptr);
260
0
  ABSL_DCHECK(result != nullptr);
261
0
  ABSL_DCHECK(*this);
262
263
0
  if (dispatcher_ == nullptr) {
264
0
    CustomStructValueInterface::Content content =
265
0
        content_.To<CustomStructValueInterface::Content>();
266
0
    ABSL_DCHECK(content.interface != nullptr);
267
0
    return content.interface->GetFieldByName(name, unboxing_options,
268
0
                                             descriptor_pool, message_factory,
269
0
                                             arena, result);
270
0
  }
271
0
  return dispatcher_->get_field_by_name(dispatcher_, content_, name,
272
0
                                        unboxing_options, descriptor_pool,
273
0
                                        message_factory, arena, result);
274
0
}
275
276
absl::Status CustomStructValue::GetFieldByNumber(
277
    int64_t number, ProtoWrapperTypeOptions unboxing_options,
278
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
279
    google::protobuf::MessageFactory* absl_nonnull message_factory,
280
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
281
0
  ABSL_DCHECK(descriptor_pool != nullptr);
282
0
  ABSL_DCHECK(message_factory != nullptr);
283
0
  ABSL_DCHECK(arena != nullptr);
284
0
  ABSL_DCHECK(result != nullptr);
285
0
  ABSL_DCHECK(*this);
286
287
0
  if (dispatcher_ == nullptr) {
288
0
    CustomStructValueInterface::Content content =
289
0
        content_.To<CustomStructValueInterface::Content>();
290
0
    ABSL_DCHECK(content.interface != nullptr);
291
0
    return content.interface->GetFieldByNumber(number, unboxing_options,
292
0
                                               descriptor_pool, message_factory,
293
0
                                               arena, result);
294
0
  }
295
0
  if (dispatcher_->get_field_by_number != nullptr) {
296
0
    return dispatcher_->get_field_by_number(dispatcher_, content_, number,
297
0
                                            unboxing_options, descriptor_pool,
298
0
                                            message_factory, arena, result);
299
0
  }
300
0
  return absl::UnimplementedError(absl::StrCat(
301
0
      GetTypeName(), " does not implement access by field number"));
302
0
}
303
304
absl::StatusOr<bool> CustomStructValue::HasFieldByName(
305
0
    absl::string_view name) const {
306
0
  ABSL_DCHECK(*this);
307
308
0
  if (dispatcher_ == nullptr) {
309
0
    CustomStructValueInterface::Content content =
310
0
        content_.To<CustomStructValueInterface::Content>();
311
0
    ABSL_DCHECK(content.interface != nullptr);
312
0
    return content.interface->HasFieldByName(name);
313
0
  }
314
0
  return dispatcher_->has_field_by_name(dispatcher_, content_, name);
315
0
}
316
317
0
absl::StatusOr<bool> CustomStructValue::HasFieldByNumber(int64_t number) const {
318
0
  ABSL_DCHECK(*this);
319
320
0
  if (dispatcher_ == nullptr) {
321
0
    CustomStructValueInterface::Content content =
322
0
        content_.To<CustomStructValueInterface::Content>();
323
0
    ABSL_DCHECK(content.interface != nullptr);
324
0
    return content.interface->HasFieldByNumber(number);
325
0
  }
326
0
  if (dispatcher_->has_field_by_number != nullptr) {
327
0
    return dispatcher_->has_field_by_number(dispatcher_, content_, number);
328
0
  }
329
0
  return absl::UnimplementedError(absl::StrCat(
330
0
      GetTypeName(), " does not implement access by field number"));
331
0
}
332
333
absl::Status CustomStructValue::ForEachField(
334
    ForEachFieldCallback callback,
335
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
336
    google::protobuf::MessageFactory* absl_nonnull message_factory,
337
0
    google::protobuf::Arena* absl_nonnull arena) const {
338
0
  ABSL_DCHECK(descriptor_pool != nullptr);
339
0
  ABSL_DCHECK(message_factory != nullptr);
340
0
  ABSL_DCHECK(arena != nullptr);
341
0
  ABSL_DCHECK(*this);
342
343
0
  if (dispatcher_ == nullptr) {
344
0
    CustomStructValueInterface::Content content =
345
0
        content_.To<CustomStructValueInterface::Content>();
346
0
    ABSL_DCHECK(content.interface != nullptr);
347
0
    return content.interface->ForEachField(callback, descriptor_pool,
348
0
                                           message_factory, arena);
349
0
  }
350
0
  return dispatcher_->for_each_field(dispatcher_, content_, callback,
351
0
                                     descriptor_pool, message_factory, arena);
352
0
}
353
354
absl::Status CustomStructValue::Qualify(
355
    absl::Span<const SelectQualifier> qualifiers, bool presence_test,
356
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
357
    google::protobuf::MessageFactory* absl_nonnull message_factory,
358
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result,
359
0
    int* absl_nonnull count) const {
360
0
  ABSL_DCHECK_GT(qualifiers.size(), 0);
361
0
  ABSL_DCHECK(descriptor_pool != nullptr);
362
0
  ABSL_DCHECK(message_factory != nullptr);
363
0
  ABSL_DCHECK(arena != nullptr);
364
0
  ABSL_DCHECK(result != nullptr);
365
0
  ABSL_DCHECK(count != nullptr);
366
0
  ABSL_DCHECK(*this);
367
368
0
  if (dispatcher_ == nullptr) {
369
0
    CustomStructValueInterface::Content content =
370
0
        content_.To<CustomStructValueInterface::Content>();
371
0
    ABSL_DCHECK(content.interface != nullptr);
372
0
    return content.interface->Qualify(qualifiers, presence_test,
373
0
                                      descriptor_pool, message_factory, arena,
374
0
                                      result, count);
375
0
  }
376
0
  if (dispatcher_->qualify != nullptr) {
377
0
    return dispatcher_->qualify(dispatcher_, content_, qualifiers,
378
0
                                presence_test, descriptor_pool, message_factory,
379
0
                                arena, result, count);
380
0
  }
381
0
  return absl::UnimplementedError(absl::StrCat(
382
0
      GetTypeName(), " does not implement field selection optimization"));
383
0
}
384
385
}  // namespace cel