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_map_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
// `CustomMapValue` represents values of the primitive `map` type.
19
// `CustomMapValueView` is a non-owning view of `CustomMapValue`.
20
// `CustomMapValueInterface` is the abstract base class of implementations.
21
// `CustomMapValue` and `CustomMapValueView` act as smart pointers to
22
// `CustomMapValueInterface`.
23
24
#ifndef THIRD_PARTY_CEL_CPP_COMMON_VALUES_PARSED_MAP_VALUE_H_
25
#define THIRD_PARTY_CEL_CPP_COMMON_VALUES_PARSED_MAP_VALUE_H_
26
27
#include <cstddef>
28
#include <ostream>
29
#include <string>
30
#include <utility>
31
32
#include "absl/base/attributes.h"
33
#include "absl/base/nullability.h"
34
#include "absl/functional/function_ref.h"
35
#include "absl/log/absl_check.h"
36
#include "absl/status/status.h"
37
#include "absl/status/statusor.h"
38
#include "absl/strings/string_view.h"
39
#include "common/native_type.h"
40
#include "common/value_kind.h"
41
#include "common/values/custom_value.h"
42
#include "common/values/values.h"
43
#include "google/protobuf/arena.h"
44
#include "google/protobuf/descriptor.h"
45
#include "google/protobuf/io/zero_copy_stream.h"
46
#include "google/protobuf/message.h"
47
48
namespace cel {
49
50
class Value;
51
class ListValue;
52
class CustomMapValueInterface;
53
class CustomMapValueInterfaceKeysIterator;
54
class CustomMapValue;
55
using CustomMapValueContent = CustomValueContent;
56
57
struct CustomMapValueDispatcher {
58
  using GetTypeId =
59
      NativeTypeId (*)(const CustomMapValueDispatcher* absl_nonnull dispatcher,
60
                       CustomMapValueContent content);
61
62
  using GetArena = google::protobuf::Arena* absl_nullable (*)(
63
      const CustomMapValueDispatcher* absl_nonnull dispatcher,
64
      CustomMapValueContent content);
65
66
  using DebugString =
67
      std::string (*)(const CustomMapValueDispatcher* absl_nonnull dispatcher,
68
                      CustomMapValueContent content);
69
70
  using SerializeTo = absl::Status (*)(
71
      const CustomMapValueDispatcher* absl_nonnull dispatcher,
72
      CustomMapValueContent content,
73
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
74
      google::protobuf::MessageFactory* absl_nonnull message_factory,
75
      google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output);
76
77
  using ConvertToJsonObject = absl::Status (*)(
78
      const CustomMapValueDispatcher* absl_nonnull dispatcher,
79
      CustomMapValueContent content,
80
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
81
      google::protobuf::MessageFactory* absl_nonnull message_factory,
82
      google::protobuf::Message* absl_nonnull json);
83
84
  using Equal = absl::Status (*)(
85
      const CustomMapValueDispatcher* absl_nonnull dispatcher,
86
      CustomMapValueContent content, const MapValue& other,
87
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
88
      google::protobuf::MessageFactory* absl_nonnull message_factory,
89
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result);
90
91
  using IsZeroValue =
92
      bool (*)(const CustomMapValueDispatcher* absl_nonnull dispatcher,
93
               CustomMapValueContent content);
94
95
  using IsEmpty =
96
      bool (*)(const CustomMapValueDispatcher* absl_nonnull dispatcher,
97
               CustomMapValueContent content);
98
99
  using Size =
100
      size_t (*)(const CustomMapValueDispatcher* absl_nonnull dispatcher,
101
                 CustomMapValueContent content);
102
103
  using Find = absl::StatusOr<bool> (*)(
104
      const CustomMapValueDispatcher* absl_nonnull dispatcher,
105
      CustomMapValueContent content, const Value& key,
106
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
107
      google::protobuf::MessageFactory* absl_nonnull message_factory,
108
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result);
109
110
  using Has = absl::StatusOr<bool> (*)(
111
      const CustomMapValueDispatcher* absl_nonnull dispatcher,
112
      CustomMapValueContent content, const Value& key,
113
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
114
      google::protobuf::MessageFactory* absl_nonnull message_factory,
115
      google::protobuf::Arena* absl_nonnull arena);
116
117
  using ListKeys = absl::Status (*)(
118
      const CustomMapValueDispatcher* absl_nonnull dispatcher,
119
      CustomMapValueContent content,
120
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
121
      google::protobuf::MessageFactory* absl_nonnull message_factory,
122
      google::protobuf::Arena* absl_nonnull arena, ListValue* absl_nonnull result);
123
124
  using ForEach = absl::Status (*)(
125
      const CustomMapValueDispatcher* absl_nonnull dispatcher,
126
      CustomMapValueContent content,
127
      absl::FunctionRef<absl::StatusOr<bool>(const Value&, 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 NewIterator = absl::StatusOr<absl_nonnull ValueIteratorPtr> (*)(
134
      const CustomMapValueDispatcher* absl_nonnull dispatcher,
135
      CustomMapValueContent content);
136
137
  using Clone = CustomMapValue (*)(
138
      const CustomMapValueDispatcher* absl_nonnull dispatcher,
139
      CustomMapValueContent content, google::protobuf::Arena* absl_nonnull arena);
140
141
  absl_nonnull GetTypeId get_type_id;
142
143
  absl_nonnull GetArena get_arena;
144
145
  // If null, simply returns "map".
146
  absl_nullable DebugString debug_string = nullptr;
147
148
  // If null, attempts to serialize results in an UNIMPLEMENTED error.
149
  absl_nullable SerializeTo serialize_to = nullptr;
150
151
  // If null, attempts to convert to JSON results in an UNIMPLEMENTED error.
152
  absl_nullable ConvertToJsonObject convert_to_json_object = nullptr;
153
154
  // If null, an nonoptimal fallback implementation for equality is used.
155
  absl_nullable Equal equal = nullptr;
156
157
  absl_nonnull IsZeroValue is_zero_value;
158
159
  // If null, `size(...) == 0` is used.
160
  absl_nullable IsEmpty is_empty = nullptr;
161
162
  absl_nonnull Size size;
163
164
  absl_nonnull Find find;
165
166
  absl_nonnull Has has;
167
168
  absl_nonnull ListKeys list_keys;
169
170
  // If null, a fallback implementation based on `list_keys` is used.
171
  absl_nullable ForEach for_each = nullptr;
172
173
  // If null, a fallback implementation based on `list_keys` is used.
174
  absl_nullable NewIterator new_iterator = nullptr;
175
176
  absl_nonnull Clone clone;
177
};
178
179
class CustomMapValueInterface {
180
 public:
181
1.97k
  CustomMapValueInterface() = default;
182
  CustomMapValueInterface(const CustomMapValueInterface&) = delete;
183
  CustomMapValueInterface(CustomMapValueInterface&&) = delete;
184
185
283
  virtual ~CustomMapValueInterface() = default;
186
187
  CustomMapValueInterface& operator=(const CustomMapValueInterface&) = delete;
188
  CustomMapValueInterface& operator=(CustomMapValueInterface&&) = delete;
189
190
  using ForEachCallback =
191
      absl::FunctionRef<absl::StatusOr<bool>(const Value&, const Value&)>;
192
193
 private:
194
  friend class CustomMapValueInterfaceIterator;
195
  friend class CustomMapValue;
196
  friend absl::Status common_internal::MapValueEqual(
197
      const CustomMapValueInterface& lhs, const MapValue& 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;
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::Status Equal(
215
      const MapValue& other,
216
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
217
      google::protobuf::MessageFactory* absl_nonnull message_factory,
218
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const;
219
220
0
  virtual bool IsZeroValue() const { return IsEmpty(); }
221
222
  // Returns `true` if this map contains no entries, `false` otherwise.
223
0
  virtual bool IsEmpty() const { return Size() == 0; }
224
225
  // Returns the number of entries in this map.
226
  virtual size_t Size() const = 0;
227
228
  // See the corresponding member function of `MapValue` for
229
  // documentation.
230
  virtual absl::Status ListKeys(
231
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
232
      google::protobuf::MessageFactory* absl_nonnull message_factory,
233
      google::protobuf::Arena* absl_nonnull arena,
234
      ListValue* absl_nonnull result) const = 0;
235
236
  // See the corresponding member function of `MapValue` for
237
  // documentation.
238
  virtual absl::Status ForEach(
239
      ForEachCallback callback,
240
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
241
      google::protobuf::MessageFactory* absl_nonnull message_factory,
242
      google::protobuf::Arena* absl_nonnull arena) const;
243
244
  // By default, implementations do not guarantee any iteration order. Unless
245
  // specified otherwise, assume the iteration order is random.
246
  virtual absl::StatusOr<absl_nonnull ValueIteratorPtr> NewIterator() const;
247
248
  virtual CustomMapValue Clone(google::protobuf::Arena* absl_nonnull arena) const = 0;
249
250
  virtual absl::StatusOr<bool> Find(
251
      const Value& key,
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) const = 0;
255
256
  virtual absl::StatusOr<bool> Has(
257
      const Value& key,
258
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
259
      google::protobuf::MessageFactory* absl_nonnull message_factory,
260
      google::protobuf::Arena* absl_nonnull arena) const = 0;
261
262
  virtual NativeTypeId GetNativeTypeId() const = 0;
263
264
  struct Content {
265
    const CustomMapValueInterface* absl_nonnull interface;
266
    google::protobuf::Arena* absl_nullable arena;
267
  };
268
};
269
270
// Creates a custom map value from a manual dispatch table `dispatcher` and
271
// opaque data `content` whose format is only know to functions in the manual
272
// dispatch table. The dispatch table should probably be valid for the lifetime
273
// of the process, but at a minimum must outlive all instances of the resulting
274
// value.
275
//
276
// IMPORTANT: This approach to implementing CustomMapValue should only be
277
// used when you know exactly what you are doing. When in doubt, just implement
278
// CustomMapValueInterface.
279
CustomMapValue UnsafeCustomMapValue(const CustomMapValueDispatcher* absl_nonnull
280
                                    dispatcher ABSL_ATTRIBUTE_LIFETIME_BOUND,
281
                                    CustomMapValueContent content);
282
283
class CustomMapValue final
284
    : private common_internal::MapValueMixin<CustomMapValue> {
285
 public:
286
  static constexpr ValueKind kKind = ValueKind::kMap;
287
288
  // Constructs a custom map value from an implementation of
289
  // `CustomMapValueInterface` `interface` whose lifetime is tied to that of
290
  // the arena `arena`.
291
  CustomMapValue(const CustomMapValueInterface* absl_nonnull
292
                 interface ABSL_ATTRIBUTE_LIFETIME_BOUND,
293
                 google::protobuf::Arena* absl_nonnull arena
294
1.97k
                     ABSL_ATTRIBUTE_LIFETIME_BOUND) {
295
1.97k
    ABSL_DCHECK(interface != nullptr);
296
1.97k
    ABSL_DCHECK(arena != nullptr);
297
1.97k
    content_ = CustomMapValueContent::From(CustomMapValueInterface::Content{
298
1.97k
        .interface = interface, .arena = arena});
299
1.97k
  }
300
301
  // By default, this creates an empty map whose type is `map(dyn, dyn)`. Unless
302
  // you can help it, you should use a more specific typed map value.
303
  CustomMapValue();
304
  CustomMapValue(const CustomMapValue&) = default;
305
  CustomMapValue(CustomMapValue&&) = default;
306
  CustomMapValue& operator=(const CustomMapValue&) = default;
307
  CustomMapValue& operator=(CustomMapValue&&) = default;
308
309
0
  static constexpr ValueKind kind() { return kKind; }
310
311
  NativeTypeId GetTypeId() const;
312
313
  absl::string_view GetTypeName() const;
314
315
  std::string DebugString() const;
316
317
  // See Value::SerializeTo().
318
  absl::Status SerializeTo(
319
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
320
      google::protobuf::MessageFactory* absl_nonnull message_factory,
321
      google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const;
322
323
  // See Value::ConvertToJson().
324
  absl::Status ConvertToJson(
325
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
326
      google::protobuf::MessageFactory* absl_nonnull message_factory,
327
      google::protobuf::Message* absl_nonnull json) const;
328
329
  // See Value::ConvertToJsonObject().
330
  absl::Status ConvertToJsonObject(
331
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
332
      google::protobuf::MessageFactory* absl_nonnull message_factory,
333
      google::protobuf::Message* absl_nonnull json) const;
334
335
  absl::Status Equal(const Value& other,
336
                     const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
337
                     google::protobuf::MessageFactory* absl_nonnull message_factory,
338
                     google::protobuf::Arena* absl_nonnull arena,
339
                     Value* absl_nonnull result) const;
340
  using MapValueMixin::Equal;
341
342
  bool IsZeroValue() const;
343
344
  CustomMapValue Clone(google::protobuf::Arena* absl_nonnull arena) const;
345
346
  bool IsEmpty() const;
347
348
  size_t Size() const;
349
350
  // See the corresponding member function of `MapValue` for
351
  // documentation.
352
  absl::Status Get(const Value& key,
353
                   const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
354
                   google::protobuf::MessageFactory* absl_nonnull message_factory,
355
                   google::protobuf::Arena* absl_nonnull arena,
356
                   Value* absl_nonnull result) const;
357
  using MapValueMixin::Get;
358
359
  // See the corresponding member function of `MapValue` for
360
  // documentation.
361
  absl::StatusOr<bool> Find(
362
      const Value& key,
363
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
364
      google::protobuf::MessageFactory* absl_nonnull message_factory,
365
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const;
366
  using MapValueMixin::Find;
367
368
  // See the corresponding member function of `MapValue` for
369
  // documentation.
370
  absl::Status Has(const Value& key,
371
                   const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
372
                   google::protobuf::MessageFactory* absl_nonnull message_factory,
373
                   google::protobuf::Arena* absl_nonnull arena,
374
                   Value* absl_nonnull result) const;
375
  using MapValueMixin::Has;
376
377
  // See the corresponding member function of `MapValue` for
378
  // documentation.
379
  absl::Status ListKeys(
380
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
381
      google::protobuf::MessageFactory* absl_nonnull message_factory,
382
      google::protobuf::Arena* absl_nonnull arena, ListValue* absl_nonnull result) const;
383
  using MapValueMixin::ListKeys;
384
385
  // See the corresponding type declaration of `MapValueInterface` for
386
  // documentation.
387
  using ForEachCallback = typename CustomMapValueInterface::ForEachCallback;
388
389
  // See the corresponding member function of `MapValue` for
390
  // documentation.
391
  absl::Status ForEach(
392
      ForEachCallback callback,
393
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
394
      google::protobuf::MessageFactory* absl_nonnull message_factory,
395
      google::protobuf::Arena* absl_nonnull arena) const;
396
397
  // See the corresponding member function of `MapValue` for
398
  // documentation.
399
  absl::StatusOr<absl_nonnull ValueIteratorPtr> NewIterator() const;
400
401
0
  const CustomMapValueDispatcher* absl_nullable dispatcher() const {
402
0
    return dispatcher_;
403
0
  }
404
405
0
  CustomMapValueContent content() const {
406
0
    ABSL_DCHECK(dispatcher_ != nullptr);
407
0
    return content_;
408
0
  }
409
410
43
  const CustomMapValueInterface* absl_nullable interface() const {
411
43
    if (dispatcher_ == nullptr) {
412
43
      return content_.To<CustomMapValueInterface::Content>().interface;
413
43
    }
414
0
    return nullptr;
415
43
  }
416
417
0
  friend void swap(CustomMapValue& lhs, CustomMapValue& rhs) noexcept {
418
0
    using std::swap;
419
0
    swap(lhs.dispatcher_, rhs.dispatcher_);
420
0
    swap(lhs.content_, rhs.content_);
421
0
  }
422
423
 private:
424
  friend class common_internal::ValueMixin<CustomMapValue>;
425
  friend class common_internal::MapValueMixin<CustomMapValue>;
426
  friend CustomMapValue UnsafeCustomMapValue(
427
      const CustomMapValueDispatcher* absl_nonnull dispatcher
428
          ABSL_ATTRIBUTE_LIFETIME_BOUND,
429
      CustomMapValueContent content);
430
431
  CustomMapValue(const CustomMapValueDispatcher* absl_nonnull dispatcher,
432
                 CustomMapValueContent content)
433
0
      : dispatcher_(dispatcher), content_(content) {
434
0
    ABSL_DCHECK(dispatcher != nullptr);
435
0
    ABSL_DCHECK(dispatcher->get_type_id != nullptr);
436
0
    ABSL_DCHECK(dispatcher->get_arena != nullptr);
437
0
    ABSL_DCHECK(dispatcher->is_zero_value != nullptr);
438
0
    ABSL_DCHECK(dispatcher->size != nullptr);
439
0
    ABSL_DCHECK(dispatcher->find != nullptr);
440
0
    ABSL_DCHECK(dispatcher->has != nullptr);
441
0
    ABSL_DCHECK(dispatcher->list_keys != nullptr);
442
0
    ABSL_DCHECK(dispatcher->clone != nullptr);
443
0
  }
444
445
  const CustomMapValueDispatcher* absl_nullable dispatcher_ = nullptr;
446
  CustomMapValueContent content_ = CustomMapValueContent::Zero();
447
};
448
449
0
inline std::ostream& operator<<(std::ostream& out, const CustomMapValue& type) {
450
0
  return out << type.DebugString();
451
0
}
452
453
template <>
454
struct NativeTypeTraits<CustomMapValue> final {
455
43
  static NativeTypeId Id(const CustomMapValue& type) {
456
43
    return type.GetTypeId();
457
43
  }
458
};
459
460
inline CustomMapValue UnsafeCustomMapValue(
461
    const CustomMapValueDispatcher* absl_nonnull dispatcher
462
        ABSL_ATTRIBUTE_LIFETIME_BOUND,
463
0
    CustomMapValueContent content) {
464
0
  return CustomMapValue(dispatcher, content);
465
0
}
466
467
}  // namespace cel
468
469
#endif  // THIRD_PARTY_CEL_CPP_COMMON_VALUES_PARSED_MAP_VALUE_H_