Coverage Report

Created: 2026-10-09 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/common/values/custom_map_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 <cstddef>
16
#include <memory>
17
#include <optional>
18
#include <string>
19
#include <utility>
20
21
#include "absl/base/attributes.h"
22
#include "absl/base/no_destructor.h"
23
#include "absl/base/nullability.h"
24
#include "absl/base/optimization.h"
25
#include "absl/log/absl_check.h"
26
#include "absl/status/status.h"
27
#include "absl/status/statusor.h"
28
#include "absl/strings/str_cat.h"
29
#include "absl/strings/string_view.h"
30
#include "absl/types/optional.h"
31
#include "common/native_type.h"
32
#include "common/value.h"
33
#include "common/value_kind.h"
34
#include "common/values/list_value_builder.h"
35
#include "common/values/map_value_builder.h"
36
#include "common/values/values.h"
37
#include "eval/public/cel_value.h"
38
#include "internal/status_macros.h"
39
#include "internal/well_known_types.h"
40
#include "google/protobuf/arena.h"
41
#include "google/protobuf/descriptor.h"
42
#include "google/protobuf/io/zero_copy_stream.h"
43
#include "google/protobuf/message.h"
44
45
namespace cel {
46
47
namespace {
48
49
using ::cel::well_known_types::StructReflection;
50
using ::cel::well_known_types::ValueReflection;
51
using ::google::api::expr::runtime::CelList;
52
using ::google::api::expr::runtime::CelValue;
53
54
46.0k
absl::Status NoSuchKeyError(const Value& key) {
55
46.0k
  return absl::NotFoundError(
56
46.0k
      absl::StrCat("Key not found in map : ", key.DebugString()));
57
46.0k
}
58
59
485
absl::Status InvalidMapKeyTypeError(ValueKind kind) {
60
485
  return absl::InvalidArgumentError(
61
485
      absl::StrCat("Invalid map key type: '", ValueKindToString(kind), "'"));
62
485
}
63
64
class EmptyMapValue final : public common_internal::CompatMapValue {
65
 public:
66
401k
  static const EmptyMapValue& Get() {
67
401k
    static const absl::NoDestructor<EmptyMapValue> empty;
68
401k
    return *empty;
69
401k
  }
70
71
1
  EmptyMapValue() = default;
72
73
0
  std::string DebugString() const override { return "{}"; }
74
75
0
  bool IsEmpty() const override { return true; }
76
77
16.6k
  size_t Size() const override { return 0; }
78
79
  absl::Status ListKeys(
80
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
81
      google::protobuf::MessageFactory* absl_nonnull message_factory,
82
      google::protobuf::Arena* absl_nonnull arena,
83
0
      ListValue* absl_nonnull result) const override {
84
0
    *result = ListValue();
85
0
    return absl::OkStatus();
86
0
  }
87
88
6.28k
  absl::StatusOr<absl_nonnull ValueIteratorPtr> NewIterator() const override {
89
6.28k
    return NewEmptyValueIterator();
90
6.28k
  }
91
92
  absl::Status ConvertToJsonObject(
93
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
94
      google::protobuf::MessageFactory* absl_nonnull message_factory,
95
1.34k
      google::protobuf::Message* absl_nonnull json) const override {
96
1.34k
    ABSL_DCHECK(descriptor_pool != nullptr);
97
1.34k
    ABSL_DCHECK(message_factory != nullptr);
98
1.34k
    ABSL_DCHECK(json != nullptr);
99
1.34k
    ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(),
100
1.34k
                   google::protobuf::Descriptor::WELLKNOWNTYPE_STRUCT);
101
102
1.34k
    json->Clear();
103
1.34k
    return absl::OkStatus();
104
1.34k
  }
105
106
0
  CustomMapValue Clone(google::protobuf::Arena* absl_nonnull) const override {
107
0
    return CustomMapValue();
108
0
  }
109
110
0
  absl::optional<CelValue> operator[](CelValue key) const override {
111
0
    return std::nullopt;
112
0
  }
113
114
  using CompatMapValue::Get;
115
  absl::optional<CelValue> Get(google::protobuf::Arena* arena,
116
0
                               CelValue key) const override {
117
0
    return std::nullopt;
118
0
  }
119
120
0
  absl::StatusOr<bool> Has(const CelValue& key) const override { return false; }
121
122
0
  int size() const override { return static_cast<int>(Size()); }
123
124
0
  absl::StatusOr<const CelList*> ListKeys() const override {
125
0
    return common_internal::EmptyCompatListValue();
126
0
  }
127
128
0
  absl::StatusOr<const CelList*> ListKeys(google::protobuf::Arena*) const override {
129
0
    return ListKeys();
130
0
  }
131
132
 private:
133
  absl::StatusOr<bool> Find(
134
      const Value& key,
135
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
136
      google::protobuf::MessageFactory* absl_nonnull message_factory,
137
      google::protobuf::Arena* absl_nonnull arena,
138
481k
      Value* absl_nonnull result) const override {
139
481k
    return false;
140
481k
  }
141
142
  absl::StatusOr<bool> Has(
143
      const Value& key,
144
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
145
      google::protobuf::MessageFactory* absl_nonnull message_factory,
146
4.01k
      google::protobuf::Arena* absl_nonnull arena) const override {
147
4.01k
    return false;
148
4.01k
  }
149
};
150
151
}  // namespace
152
153
namespace common_internal {
154
155
0
const CompatMapValue* absl_nonnull EmptyCompatMapValue() {
156
0
  return &EmptyMapValue::Get();
157
0
}
158
159
}  // namespace common_internal
160
161
class CustomMapValueInterfaceIterator final : public ValueIterator {
162
 public:
163
  explicit CustomMapValueInterfaceIterator(
164
      const CustomMapValueInterface* absl_nonnull interface)
165
0
      : interface_(interface) {}
166
167
0
  bool HasNext() override {
168
0
    if (keys_iterator_ == nullptr) {
169
0
      return !interface_->IsEmpty();
170
0
    }
171
0
    return keys_iterator_->HasNext();
172
0
  }
173
174
  absl::Status Next(const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
175
                    google::protobuf::MessageFactory* absl_nonnull message_factory,
176
                    google::protobuf::Arena* absl_nonnull arena,
177
0
                    Value* absl_nonnull result) override {
178
0
    if (keys_iterator_ == nullptr) {
179
0
      if (interface_->IsEmpty()) {
180
0
        return absl::FailedPreconditionError(
181
0
            "ValueIterator::Next() called when "
182
0
            "ValueIterator::HasNext() returns false");
183
0
      }
184
0
      CEL_RETURN_IF_ERROR(ProjectKeys(descriptor_pool, message_factory, arena));
185
0
    }
186
0
    return keys_iterator_->Next(descriptor_pool, message_factory, arena,
187
0
                                result);
188
0
  }
189
190
  absl::StatusOr<bool> Next1(
191
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
192
      google::protobuf::MessageFactory* absl_nonnull message_factory,
193
      google::protobuf::Arena* absl_nonnull arena,
194
0
      Value* absl_nonnull key_or_value) override {
195
0
    ABSL_DCHECK(descriptor_pool != nullptr);
196
0
    ABSL_DCHECK(message_factory != nullptr);
197
0
    ABSL_DCHECK(arena != nullptr);
198
0
    ABSL_DCHECK(key_or_value != nullptr);
199
200
0
    if (keys_iterator_ == nullptr) {
201
0
      if (interface_->IsEmpty()) {
202
0
        return false;
203
0
      }
204
0
      CEL_RETURN_IF_ERROR(ProjectKeys(descriptor_pool, message_factory, arena));
205
0
    }
206
207
0
    return keys_iterator_->Next1(descriptor_pool, message_factory, arena,
208
0
                                 key_or_value);
209
0
  }
210
211
  absl::StatusOr<bool> Next2(
212
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
213
      google::protobuf::MessageFactory* absl_nonnull message_factory,
214
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull key,
215
0
      Value* absl_nullable value) override {
216
0
    ABSL_DCHECK(descriptor_pool != nullptr);
217
0
    ABSL_DCHECK(message_factory != nullptr);
218
0
    ABSL_DCHECK(arena != nullptr);
219
0
    ABSL_DCHECK(key != nullptr);
220
221
0
    if (keys_iterator_ == nullptr) {
222
0
      if (interface_->IsEmpty()) {
223
0
        return false;
224
0
      }
225
0
      CEL_RETURN_IF_ERROR(ProjectKeys(descriptor_pool, message_factory, arena));
226
0
    }
227
228
0
    CEL_ASSIGN_OR_RETURN(
229
0
        bool ok,
230
0
        keys_iterator_->Next1(descriptor_pool, message_factory, arena, key));
231
0
    if (!ok) {
232
0
      return false;
233
0
    }
234
0
    if (value != nullptr) {
235
0
      CEL_ASSIGN_OR_RETURN(ok, interface_->Find(*key, descriptor_pool,
236
0
                                                message_factory, arena, value));
237
0
      if (!ok) {
238
0
        return absl::DataLossError(
239
0
            "map iterator returned key that was not present in the map");
240
0
      }
241
0
    }
242
0
    return true;
243
0
  }
244
245
 private:
246
  // Projects the keys from the map, setting `keys_` and `keys_iterator_`. If
247
  // this returns OK it is guaranteed that `keys_iterator_` is not null.
248
  absl::Status ProjectKeys(
249
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
250
      google::protobuf::MessageFactory* absl_nonnull message_factory,
251
0
      google::protobuf::Arena* absl_nonnull arena) {
252
0
    ABSL_DCHECK(keys_iterator_ == nullptr);
253
254
0
    CEL_RETURN_IF_ERROR(
255
0
        interface_->ListKeys(descriptor_pool, message_factory, arena, &keys_));
256
0
    CEL_ASSIGN_OR_RETURN(keys_iterator_, keys_.NewIterator());
257
0
    ABSL_CHECK(keys_iterator_->HasNext());  // Crash OK
258
0
    return absl::OkStatus();
259
0
  }
260
261
  const CustomMapValueInterface* absl_nonnull const interface_;
262
  ListValue keys_;
263
  absl_nullable ValueIteratorPtr keys_iterator_;
264
};
265
266
namespace {
267
268
class CustomMapValueDispatcherIterator final : public ValueIterator {
269
 public:
270
  explicit CustomMapValueDispatcherIterator(
271
      const CustomMapValueDispatcher* absl_nonnull dispatcher,
272
      CustomMapValueContent content)
273
0
      : dispatcher_(dispatcher), content_(content) {}
274
275
0
  bool HasNext() override {
276
0
    if (keys_iterator_ == nullptr) {
277
0
      if (dispatcher_->is_empty != nullptr) {
278
0
        return !dispatcher_->is_empty(dispatcher_, content_);
279
0
      }
280
0
      return dispatcher_->size(dispatcher_, content_) != 0;
281
0
    }
282
0
    return keys_iterator_->HasNext();
283
0
  }
284
285
  absl::Status Next(const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
286
                    google::protobuf::MessageFactory* absl_nonnull message_factory,
287
                    google::protobuf::Arena* absl_nonnull arena,
288
0
                    Value* absl_nonnull result) override {
289
0
    if (keys_iterator_ == nullptr) {
290
0
      if (dispatcher_->is_empty != nullptr
291
0
              ? dispatcher_->is_empty(dispatcher_, content_)
292
0
              : dispatcher_->size(dispatcher_, content_) == 0) {
293
0
        return absl::FailedPreconditionError(
294
0
            "ValueIterator::Next() called when "
295
0
            "ValueIterator::HasNext() returns false");
296
0
      }
297
0
      CEL_RETURN_IF_ERROR(ProjectKeys(descriptor_pool, message_factory, arena));
298
0
    }
299
0
    return keys_iterator_->Next(descriptor_pool, message_factory, arena,
300
0
                                result);
301
0
  }
302
303
  absl::StatusOr<bool> Next1(
304
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
305
      google::protobuf::MessageFactory* absl_nonnull message_factory,
306
      google::protobuf::Arena* absl_nonnull arena,
307
0
      Value* absl_nonnull key_or_value) override {
308
0
    ABSL_DCHECK(descriptor_pool != nullptr);
309
0
    ABSL_DCHECK(message_factory != nullptr);
310
0
    ABSL_DCHECK(arena != nullptr);
311
0
    ABSL_DCHECK(key_or_value != nullptr);
312
313
0
    if (keys_iterator_ == nullptr) {
314
0
      if (dispatcher_->is_empty != nullptr
315
0
              ? dispatcher_->is_empty(dispatcher_, content_)
316
0
              : dispatcher_->size(dispatcher_, content_) == 0) {
317
0
        return false;
318
0
      }
319
0
      CEL_RETURN_IF_ERROR(ProjectKeys(descriptor_pool, message_factory, arena));
320
0
    }
321
322
0
    return keys_iterator_->Next1(descriptor_pool, message_factory, arena,
323
0
                                 key_or_value);
324
0
  }
325
326
  absl::StatusOr<bool> Next2(
327
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
328
      google::protobuf::MessageFactory* absl_nonnull message_factory,
329
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull key,
330
0
      Value* absl_nullable value) override {
331
0
    ABSL_DCHECK(descriptor_pool != nullptr);
332
0
    ABSL_DCHECK(message_factory != nullptr);
333
0
    ABSL_DCHECK(arena != nullptr);
334
0
    ABSL_DCHECK(key != nullptr);
335
0
    ABSL_DCHECK(value != nullptr);
336
337
0
    if (keys_iterator_ == nullptr) {
338
0
      if (dispatcher_->is_empty != nullptr
339
0
              ? dispatcher_->is_empty(dispatcher_, content_)
340
0
              : dispatcher_->size(dispatcher_, content_) == 0) {
341
0
        return false;
342
0
      }
343
0
      CEL_RETURN_IF_ERROR(ProjectKeys(descriptor_pool, message_factory, arena));
344
0
    }
345
346
0
    CEL_ASSIGN_OR_RETURN(
347
0
        bool ok,
348
0
        keys_iterator_->Next1(descriptor_pool, message_factory, arena, key));
349
0
    if (!ok) {
350
0
      return false;
351
0
    }
352
0
    if (value != nullptr) {
353
0
      CEL_ASSIGN_OR_RETURN(
354
0
          ok, dispatcher_->find(dispatcher_, content_, *key, descriptor_pool,
355
0
                                message_factory, arena, value));
356
0
      if (!ok) {
357
0
        return absl::DataLossError(
358
0
            "map iterator returned key that was not present in the map");
359
0
      }
360
0
    }
361
0
    return true;
362
0
  }
363
364
 private:
365
  absl::Status ProjectKeys(
366
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
367
      google::protobuf::MessageFactory* absl_nonnull message_factory,
368
0
      google::protobuf::Arena* absl_nonnull arena) {
369
0
    ABSL_DCHECK(keys_iterator_ == nullptr);
370
371
0
    CEL_RETURN_IF_ERROR(dispatcher_->list_keys(dispatcher_, content_,
372
0
                                               descriptor_pool, message_factory,
373
0
                                               arena, &keys_));
374
0
    CEL_ASSIGN_OR_RETURN(keys_iterator_, keys_.NewIterator());
375
0
    ABSL_CHECK(keys_iterator_->HasNext());  // Crash OK
376
0
    return absl::OkStatus();
377
0
  }
378
379
  const CustomMapValueDispatcher* absl_nonnull const dispatcher_;
380
  const CustomMapValueContent content_;
381
  ListValue keys_;
382
  absl_nullable ValueIteratorPtr keys_iterator_;
383
};
384
385
}  // namespace
386
387
absl::Status CustomMapValueInterface::SerializeTo(
388
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
389
    google::protobuf::MessageFactory* absl_nonnull message_factory,
390
0
    google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const {
391
0
  ABSL_DCHECK(descriptor_pool != nullptr);
392
0
  ABSL_DCHECK(message_factory != nullptr);
393
0
  ABSL_DCHECK(output != nullptr);
394
395
0
  StructReflection reflection;
396
0
  CEL_RETURN_IF_ERROR(reflection.Initialize(descriptor_pool));
397
0
  const google::protobuf::Message* prototype =
398
0
      message_factory->GetPrototype(reflection.GetDescriptor());
399
0
  if (prototype == nullptr) {
400
0
    return absl::UnknownError(
401
0
        absl::StrCat("failed to get message prototype: ",
402
0
                     reflection.GetDescriptor()->full_name()));
403
0
  }
404
0
  google::protobuf::Arena arena;
405
0
  google::protobuf::Message* message = prototype->New(&arena);
406
0
  CEL_RETURN_IF_ERROR(
407
0
      ConvertToJsonObject(descriptor_pool, message_factory, message));
408
0
  if (!message->SerializePartialToZeroCopyStream(output)) {
409
0
    return absl::UnknownError(
410
0
        "failed to serialize message: google.protobuf.Struct");
411
0
  }
412
0
  return absl::OkStatus();
413
0
}
414
415
absl::Status CustomMapValueInterface::ForEach(
416
    ForEachCallback callback,
417
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
418
    google::protobuf::MessageFactory* absl_nonnull message_factory,
419
0
    google::protobuf::Arena* absl_nonnull arena) const {
420
0
  CEL_ASSIGN_OR_RETURN(auto iterator, NewIterator());
421
0
  while (iterator->HasNext()) {
422
0
    Value key;
423
0
    Value value;
424
0
    CEL_RETURN_IF_ERROR(
425
0
        iterator->Next(descriptor_pool, message_factory, arena, &key));
426
0
    CEL_ASSIGN_OR_RETURN(
427
0
        bool found, Find(key, descriptor_pool, message_factory, arena, &value));
428
0
    if (!found) {
429
0
      value = ErrorValue::From(NoSuchKeyError(key), arena);
430
0
    }
431
0
    CEL_ASSIGN_OR_RETURN(auto ok, callback(key, value));
432
0
    if (!ok) {
433
0
      break;
434
0
    }
435
0
  }
436
0
  return absl::OkStatus();
437
0
}
438
439
absl::StatusOr<absl_nonnull ValueIteratorPtr>
440
0
CustomMapValueInterface::NewIterator() const {
441
0
  return std::make_unique<CustomMapValueInterfaceIterator>(this);
442
0
}
443
444
absl::Status CustomMapValueInterface::Equal(
445
    const MapValue& other,
446
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
447
    google::protobuf::MessageFactory* absl_nonnull message_factory,
448
5.75k
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
449
5.75k
  return MapValueEqual(*this, other, descriptor_pool, message_factory, arena,
450
5.75k
                       result);
451
5.75k
}
452
453
401k
CustomMapValue::CustomMapValue() {
454
401k
  content_ = CustomMapValueContent::From(CustomMapValueInterface::Content{
455
401k
      .interface = &EmptyMapValue::Get(), .arena = nullptr});
456
401k
}
457
458
22
NativeTypeId CustomMapValue::GetTypeId() const {
459
22
  if (dispatcher_ == nullptr) {
460
22
    CustomMapValueInterface::Content content =
461
22
        content_.To<CustomMapValueInterface::Content>();
462
22
    ABSL_DCHECK(content.interface != nullptr);
463
22
    return content.interface->GetNativeTypeId();
464
22
  }
465
0
  return dispatcher_->get_type_id(dispatcher_, content_);
466
22
}
467
468
2
absl::string_view CustomMapValue::GetTypeName() const { return "map"; }
469
470
0
std::string CustomMapValue::DebugString() const {
471
0
  if (dispatcher_ == nullptr) {
472
0
    CustomMapValueInterface::Content content =
473
0
        content_.To<CustomMapValueInterface::Content>();
474
0
    ABSL_DCHECK(content.interface != nullptr);
475
0
    return content.interface->DebugString();
476
0
  }
477
0
  if (dispatcher_->debug_string != nullptr) {
478
0
    return dispatcher_->debug_string(dispatcher_, content_);
479
0
  }
480
0
  return "map";
481
0
}
482
483
absl::Status CustomMapValue::SerializeTo(
484
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
485
    google::protobuf::MessageFactory* absl_nonnull message_factory,
486
0
    google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const {
487
0
  if (dispatcher_ == nullptr) {
488
0
    CustomMapValueInterface::Content content =
489
0
        content_.To<CustomMapValueInterface::Content>();
490
0
    ABSL_DCHECK(content.interface != nullptr);
491
0
    return content.interface->SerializeTo(descriptor_pool, message_factory,
492
0
                                          output);
493
0
  }
494
0
  if (dispatcher_->serialize_to != nullptr) {
495
0
    return dispatcher_->serialize_to(dispatcher_, content_, descriptor_pool,
496
0
                                     message_factory, output);
497
0
  }
498
0
  return absl::UnimplementedError(
499
0
      absl::StrCat(GetTypeName(), " is unserializable"));
500
0
}
501
502
absl::Status CustomMapValue::ConvertToJson(
503
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
504
    google::protobuf::MessageFactory* absl_nonnull message_factory,
505
27.6k
    google::protobuf::Message* absl_nonnull json) const {
506
27.6k
  ABSL_DCHECK(descriptor_pool != nullptr);
507
27.6k
  ABSL_DCHECK(message_factory != nullptr);
508
27.6k
  ABSL_DCHECK(json != nullptr);
509
27.6k
  ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(),
510
27.6k
                 google::protobuf::Descriptor::WELLKNOWNTYPE_VALUE);
511
512
27.6k
  ValueReflection value_reflection;
513
27.6k
  CEL_RETURN_IF_ERROR(value_reflection.Initialize(json->GetDescriptor()));
514
27.6k
  google::protobuf::Message* json_object = value_reflection.MutableStructValue(json);
515
516
27.6k
  return ConvertToJsonObject(descriptor_pool, message_factory, json_object);
517
27.6k
}
518
519
absl::Status CustomMapValue::ConvertToJsonObject(
520
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
521
    google::protobuf::MessageFactory* absl_nonnull message_factory,
522
27.6k
    google::protobuf::Message* absl_nonnull json) const {
523
27.6k
  ABSL_DCHECK(descriptor_pool != nullptr);
524
27.6k
  ABSL_DCHECK(message_factory != nullptr);
525
27.6k
  ABSL_DCHECK(json != nullptr);
526
27.6k
  ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(),
527
27.6k
                 google::protobuf::Descriptor::WELLKNOWNTYPE_STRUCT);
528
529
27.6k
  if (dispatcher_ == nullptr) {
530
27.6k
    CustomMapValueInterface::Content content =
531
27.6k
        content_.To<CustomMapValueInterface::Content>();
532
27.6k
    ABSL_DCHECK(content.interface != nullptr);
533
27.6k
    return content.interface->ConvertToJsonObject(descriptor_pool,
534
27.6k
                                                  message_factory, json);
535
27.6k
  }
536
0
  if (dispatcher_->convert_to_json_object != nullptr) {
537
0
    return dispatcher_->convert_to_json_object(
538
0
        dispatcher_, content_, descriptor_pool, message_factory, json);
539
0
  }
540
0
  return absl::UnimplementedError(
541
0
      absl::StrCat(GetTypeName(), " is not convertable to JSON"));
542
0
}
543
544
absl::Status CustomMapValue::Equal(
545
    const Value& other,
546
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
547
    google::protobuf::MessageFactory* absl_nonnull message_factory,
548
11.3k
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
549
11.3k
  ABSL_DCHECK(descriptor_pool != nullptr);
550
11.3k
  ABSL_DCHECK(message_factory != nullptr);
551
11.3k
  ABSL_DCHECK(arena != nullptr);
552
11.3k
  ABSL_DCHECK(result != nullptr);
553
554
11.3k
  if (auto other_map_value = other.AsMap(); other_map_value) {
555
5.75k
    if (dispatcher_ == nullptr) {
556
5.75k
      CustomMapValueInterface::Content content =
557
5.75k
          content_.To<CustomMapValueInterface::Content>();
558
5.75k
      ABSL_DCHECK(content.interface != nullptr);
559
5.75k
      return content.interface->Equal(*other_map_value, descriptor_pool,
560
5.75k
                                      message_factory, arena, result);
561
5.75k
    }
562
0
    if (dispatcher_->equal != nullptr) {
563
0
      return dispatcher_->equal(dispatcher_, content_, *other_map_value,
564
0
                                descriptor_pool, message_factory, arena,
565
0
                                result);
566
0
    }
567
0
    return common_internal::MapValueEqual(*this, *other_map_value,
568
0
                                          descriptor_pool, message_factory,
569
0
                                          arena, result);
570
0
  }
571
5.59k
  *result = FalseValue();
572
5.59k
  return absl::OkStatus();
573
11.3k
}
574
575
0
bool CustomMapValue::IsZeroValue() const {
576
0
  if (dispatcher_ == nullptr) {
577
0
    CustomMapValueInterface::Content content =
578
0
        content_.To<CustomMapValueInterface::Content>();
579
0
    ABSL_DCHECK(content.interface != nullptr);
580
0
    return content.interface->IsZeroValue();
581
0
  }
582
0
  return dispatcher_->is_zero_value(dispatcher_, content_);
583
0
}
584
585
0
CustomMapValue CustomMapValue::Clone(google::protobuf::Arena* absl_nonnull arena) const {
586
0
  ABSL_DCHECK(arena != nullptr);
587
588
0
  if (dispatcher_ == nullptr) {
589
0
    CustomMapValueInterface::Content content =
590
0
        content_.To<CustomMapValueInterface::Content>();
591
0
    ABSL_DCHECK(content.interface != nullptr);
592
0
    return content.interface->Clone(arena);
593
0
  }
594
0
  return dispatcher_->clone(dispatcher_, content_, arena);
595
0
}
596
597
0
bool CustomMapValue::IsEmpty() const {
598
0
  if (dispatcher_ == nullptr) {
599
0
    CustomMapValueInterface::Content content =
600
0
        content_.To<CustomMapValueInterface::Content>();
601
0
    ABSL_DCHECK(content.interface != nullptr);
602
0
    return content.interface->IsEmpty();
603
0
  }
604
0
  if (dispatcher_->is_empty != nullptr) {
605
0
    return dispatcher_->is_empty(dispatcher_, content_);
606
0
  }
607
0
  return dispatcher_->size(dispatcher_, content_) == 0;
608
0
}
609
610
26.6k
size_t CustomMapValue::Size() const {
611
26.6k
  if (dispatcher_ == nullptr) {
612
26.6k
    CustomMapValueInterface::Content content =
613
26.6k
        content_.To<CustomMapValueInterface::Content>();
614
26.6k
    ABSL_DCHECK(content.interface != nullptr);
615
26.6k
    return content.interface->Size();
616
26.6k
  }
617
0
  return dispatcher_->size(dispatcher_, content_);
618
26.6k
}
619
620
absl::Status CustomMapValue::Get(
621
    const Value& key,
622
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
623
    google::protobuf::MessageFactory* absl_nonnull message_factory,
624
47.7k
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
625
47.7k
  ABSL_DCHECK(descriptor_pool != nullptr);
626
47.7k
  ABSL_DCHECK(message_factory != nullptr);
627
47.7k
  ABSL_DCHECK(arena != nullptr);
628
47.7k
  ABSL_DCHECK(result != nullptr);
629
630
95.4k
  CEL_ASSIGN_OR_RETURN(
631
95.4k
      bool ok, Find(key, descriptor_pool, message_factory, arena, result));
632
95.4k
  if (ABSL_PREDICT_FALSE(!ok)) {
633
46.0k
    switch (result->kind()) {
634
0
      case ValueKind::kError:
635
0
        ABSL_FALLTHROUGH_INTENDED;
636
0
      case ValueKind::kUnknown:
637
0
        break;
638
46.0k
      default:
639
46.0k
        *result = ErrorValue::From(NoSuchKeyError(key), arena);
640
46.0k
        break;
641
46.0k
    }
642
46.0k
  }
643
47.7k
  return absl::OkStatus();
644
95.4k
}
645
646
absl::StatusOr<bool> CustomMapValue::Find(
647
    const Value& key,
648
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
649
    google::protobuf::MessageFactory* absl_nonnull message_factory,
650
597k
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
651
597k
  ABSL_DCHECK(descriptor_pool != nullptr);
652
597k
  ABSL_DCHECK(message_factory != nullptr);
653
597k
  ABSL_DCHECK(arena != nullptr);
654
597k
  ABSL_DCHECK(result != nullptr);
655
656
597k
  switch (key.kind()) {
657
0
    case ValueKind::kError:
658
0
      ABSL_FALLTHROUGH_INTENDED;
659
0
    case ValueKind::kUnknown:
660
0
      *result = key;
661
0
      return false;
662
495
    case ValueKind::kBool:
663
495
      ABSL_FALLTHROUGH_INTENDED;
664
295k
    case ValueKind::kInt:
665
295k
      ABSL_FALLTHROUGH_INTENDED;
666
548k
    case ValueKind::kUint:
667
548k
      ABSL_FALLTHROUGH_INTENDED;
668
597k
    case ValueKind::kString:
669
597k
      break;
670
0
    default:
671
0
      *result = ErrorValue::From(InvalidMapKeyTypeError(key.kind()), arena);
672
0
      return false;
673
597k
  }
674
675
597k
  if (dispatcher_ == nullptr) {
676
597k
    CustomMapValueInterface::Content content =
677
597k
        content_.To<CustomMapValueInterface::Content>();
678
597k
    ABSL_DCHECK(content.interface != nullptr);
679
597k
    auto status_or_found = content.interface->Find(
680
597k
        key, descriptor_pool, message_factory, arena, result);
681
597k
    if (!status_or_found.ok()) {
682
0
      *result = ErrorValue::From(std::move(status_or_found).status(), arena);
683
0
      return false;
684
0
    }
685
597k
    if (!*status_or_found) {
686
552k
      *result = NullValue();
687
552k
      return false;
688
552k
    }
689
44.9k
    return true;
690
597k
  }
691
0
  auto status_or_found =
692
0
      dispatcher_->find(dispatcher_, content_, key, descriptor_pool,
693
0
                        message_factory, arena, result);
694
0
  if (!status_or_found.ok()) {
695
0
    *result = ErrorValue::From(std::move(status_or_found).status(), arena);
696
0
    return false;
697
0
  }
698
0
  if (!*status_or_found) {
699
0
    *result = NullValue();
700
0
    return false;
701
0
  }
702
0
  return true;
703
0
}
704
705
absl::Status CustomMapValue::Has(
706
    const Value& key,
707
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
708
    google::protobuf::MessageFactory* absl_nonnull message_factory,
709
6.32k
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
710
6.32k
  ABSL_DCHECK(descriptor_pool != nullptr);
711
6.32k
  ABSL_DCHECK(message_factory != nullptr);
712
6.32k
  ABSL_DCHECK(arena != nullptr);
713
6.32k
  ABSL_DCHECK(result != nullptr);
714
715
6.32k
  switch (key.kind()) {
716
0
    case ValueKind::kError:
717
0
      ABSL_FALLTHROUGH_INTENDED;
718
0
    case ValueKind::kUnknown:
719
0
      *result = key;
720
0
      return absl::OkStatus();
721
334
    case ValueKind::kBool:
722
334
      ABSL_FALLTHROUGH_INTENDED;
723
2.29k
    case ValueKind::kInt:
724
2.29k
      ABSL_FALLTHROUGH_INTENDED;
725
4.22k
    case ValueKind::kUint:
726
4.22k
      ABSL_FALLTHROUGH_INTENDED;
727
5.84k
    case ValueKind::kString:
728
5.84k
      break;
729
485
    default:
730
485
      *result = ErrorValue::From(InvalidMapKeyTypeError(key.kind()), arena);
731
485
      return absl::OkStatus();
732
6.32k
  }
733
5.84k
  if (dispatcher_ == nullptr) {
734
5.84k
    CustomMapValueInterface::Content content =
735
5.84k
        content_.To<CustomMapValueInterface::Content>();
736
5.84k
    ABSL_DCHECK(content.interface != nullptr);
737
5.84k
    auto status_or_has =
738
5.84k
        content.interface->Has(key, descriptor_pool, message_factory, arena);
739
5.84k
    if (!status_or_has.ok()) {
740
0
      *result = ErrorValue::From(std::move(status_or_has).status(), arena);
741
0
      return absl::OkStatus();
742
0
    }
743
5.84k
    *result = BoolValue(*status_or_has);
744
5.84k
    return absl::OkStatus();
745
5.84k
  }
746
0
  auto status_or_has = dispatcher_->has(
747
0
      dispatcher_, content_, key, descriptor_pool, message_factory, arena);
748
0
  if (!status_or_has.ok()) {
749
0
    *result = ErrorValue::From(std::move(status_or_has).status(), arena);
750
0
    return absl::OkStatus();
751
0
  }
752
0
  *result = BoolValue(*status_or_has);
753
0
  return absl::OkStatus();
754
0
}
755
756
absl::Status CustomMapValue::ListKeys(
757
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
758
    google::protobuf::MessageFactory* absl_nonnull message_factory,
759
0
    google::protobuf::Arena* absl_nonnull arena, ListValue* absl_nonnull result) const {
760
0
  ABSL_DCHECK(descriptor_pool != nullptr);
761
0
  ABSL_DCHECK(message_factory != nullptr);
762
0
  ABSL_DCHECK(arena != nullptr);
763
0
  ABSL_DCHECK(result != nullptr);
764
765
0
  if (dispatcher_ == nullptr) {
766
0
    CustomMapValueInterface::Content content =
767
0
        content_.To<CustomMapValueInterface::Content>();
768
0
    ABSL_DCHECK(content.interface != nullptr);
769
0
    return content.interface->ListKeys(descriptor_pool, message_factory, arena,
770
0
                                       result);
771
0
  }
772
0
  return dispatcher_->list_keys(dispatcher_, content_, descriptor_pool,
773
0
                                message_factory, arena, result);
774
0
}
775
776
absl::Status CustomMapValue::ForEach(
777
    ForEachCallback callback,
778
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
779
    google::protobuf::MessageFactory* absl_nonnull message_factory,
780
0
    google::protobuf::Arena* absl_nonnull arena) const {
781
0
  ABSL_DCHECK(descriptor_pool != nullptr);
782
0
  ABSL_DCHECK(message_factory != nullptr);
783
0
  ABSL_DCHECK(arena != nullptr);
784
785
0
  if (dispatcher_ == nullptr) {
786
0
    CustomMapValueInterface::Content content =
787
0
        content_.To<CustomMapValueInterface::Content>();
788
0
    ABSL_DCHECK(content.interface != nullptr);
789
0
    return content.interface->ForEach(callback, descriptor_pool,
790
0
                                      message_factory, arena);
791
0
  }
792
0
  if (dispatcher_->for_each != nullptr) {
793
0
    return dispatcher_->for_each(dispatcher_, content_, callback,
794
0
                                 descriptor_pool, message_factory, arena);
795
0
  }
796
0
  absl_nonnull ValueIteratorPtr iterator;
797
0
  if (dispatcher_->new_iterator != nullptr) {
798
0
    CEL_ASSIGN_OR_RETURN(iterator,
799
0
                         dispatcher_->new_iterator(dispatcher_, content_));
800
0
  } else {
801
0
    iterator = std::make_unique<CustomMapValueDispatcherIterator>(dispatcher_,
802
0
                                                                  content_);
803
0
  }
804
0
  while (iterator->HasNext()) {
805
0
    Value key;
806
0
    Value value;
807
0
    CEL_RETURN_IF_ERROR(
808
0
        iterator->Next(descriptor_pool, message_factory, arena, &key));
809
0
    CEL_ASSIGN_OR_RETURN(
810
0
        bool found,
811
0
        dispatcher_->find(dispatcher_, content_, key, descriptor_pool,
812
0
                          message_factory, arena, &value));
813
0
    if (!found) {
814
0
      value = ErrorValue::From(NoSuchKeyError(key), arena);
815
0
    }
816
0
    CEL_ASSIGN_OR_RETURN(auto ok, callback(key, value));
817
0
    if (!ok) {
818
0
      break;
819
0
    }
820
0
  }
821
0
  return absl::OkStatus();
822
0
}
823
824
absl::StatusOr<absl_nonnull ValueIteratorPtr> CustomMapValue::NewIterator()
825
7.17k
    const {
826
7.17k
  if (dispatcher_ == nullptr) {
827
7.17k
    CustomMapValueInterface::Content content =
828
7.17k
        content_.To<CustomMapValueInterface::Content>();
829
7.17k
    ABSL_DCHECK(content.interface != nullptr);
830
7.17k
    return content.interface->NewIterator();
831
7.17k
  }
832
0
  if (dispatcher_->new_iterator != nullptr) {
833
0
    return dispatcher_->new_iterator(dispatcher_, content_);
834
0
  }
835
0
  return std::make_unique<CustomMapValueDispatcherIterator>(dispatcher_,
836
0
                                                            content_);
837
0
}
838
839
}  // namespace cel