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.h
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
// IWYU pragma: private, include "common/value.h"
16
// IWYU pragma: friend "common/value.h"
17
18
#ifndef THIRD_PARTY_CEL_CPP_COMMON_VALUES_PARSED_STRUCT_VALUE_H_
19
#define THIRD_PARTY_CEL_CPP_COMMON_VALUES_PARSED_STRUCT_VALUE_H_
20
21
#include <cstdint>
22
#include <ostream>
23
#include <string>
24
#include <utility>
25
26
#include "absl/base/attributes.h"
27
#include "absl/base/nullability.h"
28
#include "absl/functional/function_ref.h"
29
#include "absl/log/absl_check.h"
30
#include "absl/status/status.h"
31
#include "absl/status/statusor.h"
32
#include "absl/strings/string_view.h"
33
#include "absl/types/span.h"
34
#include "base/attribute.h"
35
#include "common/native_type.h"
36
#include "common/type.h"
37
#include "common/value_kind.h"
38
#include "common/values/custom_value.h"
39
#include "common/values/values.h"
40
#include "runtime/runtime_options.h"
41
#include "google/protobuf/arena.h"
42
#include "google/protobuf/descriptor.h"
43
#include "google/protobuf/io/zero_copy_stream.h"
44
#include "google/protobuf/message.h"
45
46
namespace cel {
47
48
class CustomStructValueInterface;
49
class CustomStructValue;
50
class Value;
51
struct CustomStructValueDispatcher;
52
using CustomStructValueContent = CustomValueContent;
53
54
struct CustomStructValueDispatcher {
55
  using GetTypeId = NativeTypeId (*)(
56
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
57
      CustomStructValueContent content);
58
59
  using GetArena = google::protobuf::Arena* absl_nullable (*)(
60
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
61
      CustomStructValueContent content);
62
63
  using GetTypeName = absl::string_view (*)(
64
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
65
      CustomStructValueContent content);
66
67
  using DebugString = std::string (*)(
68
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
69
      CustomStructValueContent content);
70
71
  using GetRuntimeType =
72
      StructType (*)(const CustomStructValueDispatcher* absl_nonnull dispatcher,
73
                     CustomStructValueContent content);
74
75
  using SerializeTo = absl::Status (*)(
76
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
77
      CustomStructValueContent content,
78
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
79
      google::protobuf::MessageFactory* absl_nonnull message_factory,
80
      google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output);
81
82
  using ConvertToJsonObject = absl::Status (*)(
83
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
84
      CustomStructValueContent content,
85
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
86
      google::protobuf::MessageFactory* absl_nonnull message_factory,
87
      google::protobuf::Message* absl_nonnull json);
88
89
  using Equal = absl::Status (*)(
90
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
91
      CustomStructValueContent content, const StructValue& other,
92
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
93
      google::protobuf::MessageFactory* absl_nonnull message_factory,
94
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result);
95
96
  using IsZeroValue =
97
      bool (*)(const CustomStructValueDispatcher* absl_nonnull dispatcher,
98
               CustomStructValueContent content);
99
100
  using GetFieldByName = absl::Status (*)(
101
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
102
      CustomStructValueContent content, absl::string_view name,
103
      ProtoWrapperTypeOptions unboxing_options,
104
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
105
      google::protobuf::MessageFactory* absl_nonnull message_factory,
106
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result);
107
108
  using GetFieldByNumber = absl::Status (*)(
109
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
110
      CustomStructValueContent content, int64_t number,
111
      ProtoWrapperTypeOptions unboxing_options,
112
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
113
      google::protobuf::MessageFactory* absl_nonnull message_factory,
114
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result);
115
116
  using HasFieldByName = absl::StatusOr<bool> (*)(
117
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
118
      CustomStructValueContent content, absl::string_view name);
119
120
  using HasFieldByNumber = absl::StatusOr<bool> (*)(
121
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
122
      CustomStructValueContent content, int64_t number);
123
124
  using ForEachField = absl::Status (*)(
125
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
126
      CustomStructValueContent content,
127
      absl::FunctionRef<absl::StatusOr<bool>(absl::string_view, const Value&)>
128
          callback,
129
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
130
      google::protobuf::MessageFactory* absl_nonnull message_factory,
131
      google::protobuf::Arena* absl_nonnull arena);
132
133
  using Quality = absl::Status (*)(
134
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
135
      CustomStructValueContent content,
136
      absl::Span<const SelectQualifier> qualifiers, bool presence_test,
137
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
138
      google::protobuf::MessageFactory* absl_nonnull message_factory,
139
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result,
140
      int* absl_nonnull count);
141
142
  using Clone = CustomStructValue (*)(
143
      const CustomStructValueDispatcher* absl_nonnull dispatcher,
144
      CustomStructValueContent content, google::protobuf::Arena* absl_nonnull arena);
145
146
  absl_nonnull GetTypeId get_type_id;
147
148
  absl_nonnull GetArena get_arena;
149
150
  absl_nonnull GetTypeName get_type_name;
151
152
  absl_nullable DebugString debug_string = nullptr;
153
154
  absl_nullable GetRuntimeType get_runtime_type = nullptr;
155
156
  absl_nullable SerializeTo serialize_to = nullptr;
157
158
  absl_nullable ConvertToJsonObject convert_to_json_object = nullptr;
159
160
  absl_nullable Equal equal = nullptr;
161
162
  absl_nonnull IsZeroValue is_zero_value;
163
164
  absl_nonnull GetFieldByName get_field_by_name;
165
166
  absl_nullable GetFieldByNumber get_field_by_number = nullptr;
167
168
  absl_nonnull HasFieldByName has_field_by_name;
169
170
  absl_nullable HasFieldByNumber has_field_by_number = nullptr;
171
172
  absl_nonnull ForEachField for_each_field;
173
174
  absl_nullable Quality qualify = nullptr;
175
176
  absl_nonnull Clone clone;
177
};
178
179
class CustomStructValueInterface {
180
 public:
181
  CustomStructValueInterface() = default;
182
  CustomStructValueInterface(const CustomStructValueInterface&) = delete;
183
  CustomStructValueInterface(CustomStructValueInterface&&) = delete;
184
185
0
  virtual ~CustomStructValueInterface() = default;
186
187
  CustomStructValueInterface& operator=(const CustomStructValueInterface&) =
188
      delete;
189
  CustomStructValueInterface& operator=(CustomStructValueInterface&&) = delete;
190
191
  using ForEachFieldCallback =
192
      absl::FunctionRef<absl::StatusOr<bool>(absl::string_view, const Value&)>;
193
194
 private:
195
  friend class CustomStructValue;
196
  friend absl::Status common_internal::StructValueEqual(
197
      const CustomStructValueInterface& lhs, const StructValue& rhs,
198
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
199
      google::protobuf::MessageFactory* absl_nonnull message_factory,
200
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result);
201
202
  virtual std::string DebugString() const = 0;
203
204
  virtual absl::Status SerializeTo(
205
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
206
      google::protobuf::MessageFactory* absl_nonnull message_factory,
207
      google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const = 0;
208
209
  virtual absl::Status ConvertToJsonObject(
210
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
211
      google::protobuf::MessageFactory* absl_nonnull message_factory,
212
      google::protobuf::Message* absl_nonnull json) const = 0;
213
214
  virtual absl::string_view GetTypeName() const = 0;
215
216
0
  virtual StructType GetRuntimeType() const {
217
0
    return common_internal::MakeBasicStructType(GetTypeName());
218
0
  }
219
220
  virtual absl::Status Equal(
221
      const StructValue& other,
222
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
223
      google::protobuf::MessageFactory* absl_nonnull message_factory,
224
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const;
225
226
  virtual bool IsZeroValue() const = 0;
227
228
  virtual absl::Status GetFieldByName(
229
      absl::string_view name, ProtoWrapperTypeOptions unboxing_options,
230
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
231
      google::protobuf::MessageFactory* absl_nonnull message_factory,
232
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const = 0;
233
234
  virtual absl::Status GetFieldByNumber(
235
      int64_t number, ProtoWrapperTypeOptions unboxing_options,
236
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
237
      google::protobuf::MessageFactory* absl_nonnull message_factory,
238
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const = 0;
239
240
  virtual absl::StatusOr<bool> HasFieldByName(absl::string_view name) const = 0;
241
242
  virtual absl::StatusOr<bool> HasFieldByNumber(int64_t number) const = 0;
243
244
  virtual absl::Status ForEachField(
245
      ForEachFieldCallback callback,
246
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
247
      google::protobuf::MessageFactory* absl_nonnull message_factory,
248
      google::protobuf::Arena* absl_nonnull arena) const = 0;
249
250
  virtual absl::Status Qualify(
251
      absl::Span<const SelectQualifier> qualifiers, bool presence_test,
252
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
253
      google::protobuf::MessageFactory* absl_nonnull message_factory,
254
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result,
255
      int* absl_nonnull count) const;
256
257
  virtual CustomStructValue Clone(google::protobuf::Arena* absl_nonnull arena) const = 0;
258
259
  virtual NativeTypeId GetNativeTypeId() const = 0;
260
261
  struct Content {
262
    const CustomStructValueInterface* absl_nonnull interface;
263
    google::protobuf::Arena* absl_nonnull arena;
264
  };
265
};
266
267
// Creates a custom struct value from a manual dispatch table `dispatcher` and
268
// opaque data `content` whose format is only know to functions in the manual
269
// dispatch table. The dispatch table should probably be valid for the lifetime
270
// of the process, but at a minimum must outlive all instances of the resulting
271
// value.
272
//
273
// IMPORTANT: This approach to implementing CustomStructValues should only be
274
// used when you know exactly what you are doing. When in doubt, just implement
275
// CustomStructValueInterface.
276
CustomStructValue UnsafeCustomStructValue(
277
    const CustomStructValueDispatcher* absl_nonnull dispatcher
278
        ABSL_ATTRIBUTE_LIFETIME_BOUND,
279
    CustomStructValueContent content);
280
281
class CustomStructValue final
282
    : private common_internal::StructValueMixin<CustomStructValue> {
283
 public:
284
  static constexpr ValueKind kKind = ValueKind::kStruct;
285
286
  // Constructs a custom struct value from an implementation of
287
  // `CustomStructValueInterface` `interface` whose lifetime is tied to that of
288
  // the arena `arena`.
289
  CustomStructValue(const CustomStructValueInterface* absl_nonnull
290
                    interface ABSL_ATTRIBUTE_LIFETIME_BOUND,
291
                    google::protobuf::Arena* absl_nonnull arena
292
0
                        ABSL_ATTRIBUTE_LIFETIME_BOUND) {
293
0
    ABSL_DCHECK(interface != nullptr);
294
0
    ABSL_DCHECK(arena != nullptr);
295
0
    content_ =
296
0
        CustomStructValueContent::From(CustomStructValueInterface::Content{
297
0
            .interface = interface, .arena = arena});
298
0
  }
299
300
  CustomStructValue() = default;
301
  CustomStructValue(const CustomStructValue&) = default;
302
  CustomStructValue(CustomStructValue&&) = default;
303
  CustomStructValue& operator=(const CustomStructValue&) = default;
304
  CustomStructValue& operator=(CustomStructValue&&) = default;
305
306
0
  static constexpr ValueKind kind() { return kKind; }
307
308
  NativeTypeId GetTypeId() const;
309
310
  StructType GetRuntimeType() const;
311
312
  absl::string_view GetTypeName() const;
313
314
  std::string DebugString() const;
315
316
  // See Value::SerializeTo().
317
  absl::Status SerializeTo(
318
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
319
      google::protobuf::MessageFactory* absl_nonnull message_factory,
320
      google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const;
321
322
  // See Value::ConvertToJson().
323
  absl::Status ConvertToJson(
324
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
325
      google::protobuf::MessageFactory* absl_nonnull message_factory,
326
      google::protobuf::Message* absl_nonnull json) const;
327
328
  // See Value::ConvertToJsonObject().
329
  absl::Status ConvertToJsonObject(
330
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
331
      google::protobuf::MessageFactory* absl_nonnull message_factory,
332
      google::protobuf::Message* absl_nonnull json) const;
333
334
  absl::Status Equal(const Value& other,
335
                     const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
336
                     google::protobuf::MessageFactory* absl_nonnull message_factory,
337
                     google::protobuf::Arena* absl_nonnull arena,
338
                     Value* absl_nonnull result) const;
339
  using StructValueMixin::Equal;
340
341
  bool IsZeroValue() const;
342
343
  CustomStructValue Clone(google::protobuf::Arena* absl_nonnull arena) const;
344
345
  absl::Status GetFieldByName(
346
      absl::string_view name, ProtoWrapperTypeOptions unboxing_options,
347
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
348
      google::protobuf::MessageFactory* absl_nonnull message_factory,
349
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const;
350
  using StructValueMixin::GetFieldByName;
351
352
  absl::Status GetFieldByNumber(
353
      int64_t number, ProtoWrapperTypeOptions unboxing_options,
354
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
355
      google::protobuf::MessageFactory* absl_nonnull message_factory,
356
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const;
357
  using StructValueMixin::GetFieldByNumber;
358
359
  absl::StatusOr<bool> HasFieldByName(absl::string_view name) const;
360
361
  absl::StatusOr<bool> HasFieldByNumber(int64_t number) const;
362
363
  using ForEachFieldCallback = CustomStructValueInterface::ForEachFieldCallback;
364
365
  absl::Status ForEachField(
366
      ForEachFieldCallback callback,
367
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
368
      google::protobuf::MessageFactory* absl_nonnull message_factory,
369
      google::protobuf::Arena* absl_nonnull arena) const;
370
371
  absl::Status Qualify(
372
      absl::Span<const SelectQualifier> qualifiers, bool presence_test,
373
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
374
      google::protobuf::MessageFactory* absl_nonnull message_factory,
375
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result,
376
      int* absl_nonnull count) const;
377
  using StructValueMixin::Qualify;
378
379
0
  const CustomStructValueDispatcher* absl_nullable dispatcher() const {
380
0
    return dispatcher_;
381
0
  }
382
383
0
  CustomStructValueContent content() const {
384
0
    ABSL_DCHECK(dispatcher_ != nullptr);
385
0
    return content_;
386
0
  }
387
388
0
  const CustomStructValueInterface* absl_nullable interface() const {
389
0
    if (dispatcher_ == nullptr) {
390
0
      return content_.To<CustomStructValueInterface::Content>().interface;
391
0
    }
392
0
    return nullptr;
393
0
  }
394
395
0
  explicit operator bool() const {
396
0
    if (dispatcher_ == nullptr) {
397
0
      return content_.To<CustomStructValueInterface::Content>().interface !=
398
0
             nullptr;
399
0
    }
400
0
    return true;
401
0
  }
402
403
0
  friend void swap(CustomStructValue& lhs, CustomStructValue& rhs) noexcept {
404
0
    using std::swap;
405
0
    swap(lhs.dispatcher_, rhs.dispatcher_);
406
0
    swap(lhs.content_, rhs.content_);
407
0
  }
408
409
 private:
410
  friend class common_internal::ValueMixin<CustomStructValue>;
411
  friend class common_internal::StructValueMixin<CustomStructValue>;
412
  friend CustomStructValue UnsafeCustomStructValue(
413
      const CustomStructValueDispatcher* absl_nonnull dispatcher
414
          ABSL_ATTRIBUTE_LIFETIME_BOUND,
415
      CustomStructValueContent content);
416
417
  // Constructs a custom struct value from a dispatcher and content. Only
418
  // accessible from `UnsafeCustomStructValue`.
419
  CustomStructValue(const CustomStructValueDispatcher* absl_nonnull dispatcher
420
                        ABSL_ATTRIBUTE_LIFETIME_BOUND,
421
                    CustomStructValueContent content)
422
0
      : dispatcher_(dispatcher), content_(content) {
423
0
    ABSL_DCHECK(dispatcher != nullptr);
424
0
    ABSL_DCHECK(dispatcher->get_type_id != nullptr);
425
0
    ABSL_DCHECK(dispatcher->get_arena != nullptr);
426
0
    ABSL_DCHECK(dispatcher->get_type_name != nullptr);
427
0
    ABSL_DCHECK(dispatcher->is_zero_value != nullptr);
428
0
    ABSL_DCHECK(dispatcher->get_field_by_name != nullptr);
429
0
    ABSL_DCHECK(dispatcher->has_field_by_name != nullptr);
430
0
    ABSL_DCHECK(dispatcher->for_each_field != nullptr);
431
0
    ABSL_DCHECK(dispatcher->clone != nullptr);
432
0
  }
433
434
  const CustomStructValueDispatcher* absl_nullable dispatcher_ = nullptr;
435
  CustomStructValueContent content_ = CustomStructValueContent::Zero();
436
};
437
438
inline std::ostream& operator<<(std::ostream& out,
439
0
                                const CustomStructValue& value) {
440
0
  return out << value.DebugString();
441
0
}
442
443
template <>
444
struct NativeTypeTraits<CustomStructValue> final {
445
0
  static NativeTypeId Id(const CustomStructValue& type) {
446
0
    return type.GetTypeId();
447
0
  }
448
};
449
450
inline CustomStructValue UnsafeCustomStructValue(
451
    const CustomStructValueDispatcher* absl_nonnull dispatcher
452
        ABSL_ATTRIBUTE_LIFETIME_BOUND,
453
0
    CustomStructValueContent content) {
454
0
  return CustomStructValue(dispatcher, content);
455
0
}
456
457
}  // namespace cel
458
459
#endif  // THIRD_PARTY_CEL_CPP_COMMON_VALUES_PARSED_STRUCT_VALUE_H_