Coverage Report

Created: 2026-10-09 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/runtime/standard/equality_functions.cc
Line
Count
Source
1
// Copyright 2022 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 "runtime/standard/equality_functions.h"
16
17
#include <cstdint>
18
#include <functional>
19
#include <optional>
20
#include <type_traits>
21
#include <utility>
22
23
#include "absl/base/nullability.h"
24
#include "absl/functional/function_ref.h"
25
#include "absl/status/status.h"
26
#include "absl/status/statusor.h"
27
#include "absl/strings/string_view.h"
28
#include "absl/time/time.h"
29
#include "absl/types/optional.h"
30
#include "base/builtins.h"
31
#include "base/function_adapter.h"
32
#include "common/value.h"
33
#include "common/value_kind.h"
34
#include "internal/number.h"
35
#include "internal/status_macros.h"
36
#include "runtime/function_registry.h"
37
#include "runtime/internal/errors.h"
38
#include "runtime/register_function_helper.h"
39
#include "runtime/runtime_options.h"
40
#include "google/protobuf/arena.h"
41
#include "google/protobuf/descriptor.h"
42
#include "google/protobuf/message.h"
43
44
namespace cel {
45
namespace {
46
47
using ::cel::builtin::kEqual;
48
using ::cel::builtin::kInequal;
49
using ::cel::internal::Number;
50
51
// Declaration for the functors for generic equality operator.
52
// Equal only defined for same-typed values.
53
// Nullopt is returned if equality is not defined.
54
struct HomogenousEqualProvider {
55
  static constexpr bool kIsHeterogeneous = false;
56
  absl::StatusOr<absl::optional<bool>> operator()(
57
      const Value& lhs, const Value& rhs,
58
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
59
      google::protobuf::MessageFactory* absl_nonnull message_factory,
60
      google::protobuf::Arena* absl_nonnull arena) const;
61
};
62
63
// Equal defined between compatible types.
64
// Nullopt is returned if equality is not defined.
65
struct HeterogeneousEqualProvider {
66
  static constexpr bool kIsHeterogeneous = true;
67
68
  absl::StatusOr<absl::optional<bool>> operator()(
69
      const Value& lhs, const Value& rhs,
70
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
71
      google::protobuf::MessageFactory* absl_nonnull message_factory,
72
      google::protobuf::Arena* absl_nonnull arena) const;
73
};
74
75
// Comparison template functions
76
template <class Type>
77
0
absl::optional<bool> Inequal(Type lhs, Type rhs) {
78
0
  return lhs != rhs;
79
0
}
Unexecuted instantiation: equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Inequal<bool>(bool, bool)
Unexecuted instantiation: equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Inequal<long>(long, long)
Unexecuted instantiation: equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Inequal<unsigned long>(unsigned long, unsigned long)
Unexecuted instantiation: equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Inequal<double>(double, double)
Unexecuted instantiation: equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Inequal<absl::lts_20260526::Duration>(absl::lts_20260526::Duration, absl::lts_20260526::Duration)
Unexecuted instantiation: equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Inequal<absl::lts_20260526::Time>(absl::lts_20260526::Time, absl::lts_20260526::Time)
80
81
template <>
82
0
absl::optional<bool> Inequal(const StringValue& lhs, const StringValue& rhs) {
83
0
  return !lhs.Equals(rhs);
84
0
}
85
86
template <>
87
0
absl::optional<bool> Inequal(const BytesValue& lhs, const BytesValue& rhs) {
88
0
  return !lhs.Equals(rhs);
89
0
}
90
91
template <>
92
0
absl::optional<bool> Inequal(const NullValue&, const NullValue&) {
93
0
  return false;
94
0
}
95
96
template <>
97
0
absl::optional<bool> Inequal(const TypeValue& lhs, const TypeValue& rhs) {
98
0
  return lhs.name() != rhs.name();
99
0
}
100
101
template <class Type>
102
15.0k
absl::optional<bool> Equal(Type lhs, Type rhs) {
103
15.0k
  return lhs == rhs;
104
15.0k
}
equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Equal<bool>(bool, bool)
Line
Count
Source
102
408
absl::optional<bool> Equal(Type lhs, Type rhs) {
103
408
  return lhs == rhs;
104
408
}
equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Equal<long>(long, long)
Line
Count
Source
102
4.89k
absl::optional<bool> Equal(Type lhs, Type rhs) {
103
4.89k
  return lhs == rhs;
104
4.89k
}
equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Equal<unsigned long>(unsigned long, unsigned long)
Line
Count
Source
102
8.25k
absl::optional<bool> Equal(Type lhs, Type rhs) {
103
8.25k
  return lhs == rhs;
104
8.25k
}
equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Equal<double>(double, double)
Line
Count
Source
102
777
absl::optional<bool> Equal(Type lhs, Type rhs) {
103
777
  return lhs == rhs;
104
777
}
equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Equal<absl::lts_20260526::Duration>(absl::lts_20260526::Duration, absl::lts_20260526::Duration)
Line
Count
Source
102
145
absl::optional<bool> Equal(Type lhs, Type rhs) {
103
145
  return lhs == rhs;
104
145
}
equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Equal<absl::lts_20260526::Time>(absl::lts_20260526::Time, absl::lts_20260526::Time)
Line
Count
Source
102
529
absl::optional<bool> Equal(Type lhs, Type rhs) {
103
529
  return lhs == rhs;
104
529
}
105
106
template <>
107
327
absl::optional<bool> Equal(const StringValue& lhs, const StringValue& rhs) {
108
327
  return lhs.Equals(rhs);
109
327
}
110
111
template <>
112
720
absl::optional<bool> Equal(const BytesValue& lhs, const BytesValue& rhs) {
113
720
  return lhs.Equals(rhs);
114
720
}
115
116
template <>
117
0
absl::optional<bool> Equal(const NullValue&, const NullValue&) {
118
0
  return true;
119
0
}
120
121
template <>
122
1.74k
absl::optional<bool> Equal(const TypeValue& lhs, const TypeValue& rhs) {
123
1.74k
  return lhs.name() == rhs.name();
124
1.74k
}
125
126
// Equality for lists. Template parameter provides either heterogeneous or
127
// homogenous equality for comparing members.
128
template <typename EqualsProvider>
129
absl::StatusOr<absl::optional<bool>> ListEqual(
130
    const ListValue& lhs, const ListValue& rhs,
131
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
132
    google::protobuf::MessageFactory* absl_nonnull message_factory,
133
2.67k
    google::protobuf::Arena* absl_nonnull arena) {
134
2.67k
  if (&lhs == &rhs) {
135
0
    return true;
136
0
  }
137
5.35k
  CEL_ASSIGN_OR_RETURN(auto lhs_size, lhs.Size());
138
5.35k
  CEL_ASSIGN_OR_RETURN(auto rhs_size, rhs.Size());
139
2.67k
  if (lhs_size != rhs_size) {
140
540
    return false;
141
540
  }
142
143
2.23k
  for (int i = 0; i < lhs_size; ++i) {
144
1.82k
    CEL_ASSIGN_OR_RETURN(auto lhs_i,
145
1.82k
                         lhs.Get(i, descriptor_pool, message_factory, arena));
146
1.82k
    CEL_ASSIGN_OR_RETURN(auto rhs_i,
147
1.82k
                         rhs.Get(i, descriptor_pool, message_factory, arena));
148
1.82k
    CEL_ASSIGN_OR_RETURN(absl::optional<bool> eq,
149
1.82k
                         EqualsProvider()(lhs_i, rhs_i, descriptor_pool,
150
1.82k
                                          message_factory, arena));
151
1.82k
    if (!eq.has_value() || !*eq) {
152
1.72k
      return eq;
153
1.72k
    }
154
1.82k
  }
155
414
  return true;
156
2.13k
}
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::StatusOr<std::__1::optional<bool> > cel::(anonymous namespace)::ListEqual<cel::(anonymous namespace)::HomogenousEqualProvider>(cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)
equality_functions.cc:absl::lts_20260526::StatusOr<std::__1::optional<bool> > cel::(anonymous namespace)::ListEqual<cel::(anonymous namespace)::HeterogeneousEqualProvider>(cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)
Line
Count
Source
133
2.67k
    google::protobuf::Arena* absl_nonnull arena) {
134
2.67k
  if (&lhs == &rhs) {
135
0
    return true;
136
0
  }
137
5.35k
  CEL_ASSIGN_OR_RETURN(auto lhs_size, lhs.Size());
138
5.35k
  CEL_ASSIGN_OR_RETURN(auto rhs_size, rhs.Size());
139
2.67k
  if (lhs_size != rhs_size) {
140
540
    return false;
141
540
  }
142
143
2.23k
  for (int i = 0; i < lhs_size; ++i) {
144
1.82k
    CEL_ASSIGN_OR_RETURN(auto lhs_i,
145
1.82k
                         lhs.Get(i, descriptor_pool, message_factory, arena));
146
1.82k
    CEL_ASSIGN_OR_RETURN(auto rhs_i,
147
1.82k
                         rhs.Get(i, descriptor_pool, message_factory, arena));
148
1.82k
    CEL_ASSIGN_OR_RETURN(absl::optional<bool> eq,
149
1.82k
                         EqualsProvider()(lhs_i, rhs_i, descriptor_pool,
150
1.82k
                                          message_factory, arena));
151
1.82k
    if (!eq.has_value() || !*eq) {
152
1.72k
      return eq;
153
1.72k
    }
154
1.82k
  }
155
414
  return true;
156
2.13k
}
157
158
// Opaque types only support heterogeneous equality, and by extension that means
159
// optionals. Heterogeneous equality being enabled is enforced by
160
// `EnableOptionalTypes`.
161
absl::StatusOr<absl::optional<bool>> OpaqueEqual(
162
    const OpaqueValue& lhs, const OpaqueValue& rhs,
163
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
164
    google::protobuf::MessageFactory* absl_nonnull message_factory,
165
0
    google::protobuf::Arena* absl_nonnull arena) {
166
0
  Value result;
167
0
  CEL_RETURN_IF_ERROR(
168
0
      lhs.Equal(rhs, descriptor_pool, message_factory, arena, &result));
169
0
  if (auto bool_value = result.AsBool(); bool_value) {
170
0
    return bool_value->NativeValue();
171
0
  }
172
0
  return common_internal::MakeTypeConversionError(result.GetTypeName(), "bool");
173
0
}
174
175
133k
absl::optional<Number> NumberFromValue(const Value& value) {
176
133k
  if (value.Is<IntValue>()) {
177
51.0k
    return Number::FromInt64(value.GetInt().NativeValue());
178
82.7k
  } else if (value.Is<UintValue>()) {
179
44.9k
    return Number::FromUint64(value.GetUint().NativeValue());
180
44.9k
  } else if (value.Is<DoubleValue>()) {
181
18.7k
    return Number::FromDouble(value.GetDouble().NativeValue());
182
18.7k
  }
183
184
19.1k
  return std::nullopt;
185
133k
}
186
187
absl::StatusOr<absl::optional<Value>> CheckAlternativeNumericType(
188
    const Value& key, const MapValue& rhs,
189
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
190
    google::protobuf::MessageFactory* absl_nonnull message_factory,
191
5.00k
    google::protobuf::Arena* absl_nonnull arena) {
192
5.00k
  absl::optional<Number> number = NumberFromValue(key);
193
194
5.00k
  if (!number.has_value()) {
195
2.51k
    return std::nullopt;
196
2.51k
  }
197
198
2.48k
  if (!key.IsInt() && number->LosslessConvertibleToInt()) {
199
708
    absl::optional<Value> entry;
200
708
    CEL_ASSIGN_OR_RETURN(entry,
201
708
                         rhs.Find(IntValue(number->AsInt()), descriptor_pool,
202
708
                                  message_factory, arena));
203
708
    if (entry) {
204
324
      return entry;
205
324
    }
206
708
  }
207
208
2.16k
  if (!key.IsUint() && number->LosslessConvertibleToUint()) {
209
1.23k
    absl::optional<Value> entry;
210
1.23k
    CEL_ASSIGN_OR_RETURN(entry,
211
1.23k
                         rhs.Find(UintValue(number->AsUint()), descriptor_pool,
212
1.23k
                                  message_factory, arena));
213
1.23k
    if (entry) {
214
97
      return entry;
215
97
    }
216
1.23k
  }
217
218
2.06k
  return std::nullopt;
219
2.16k
}
220
221
// Equality for maps. Template parameter provides either heterogeneous or
222
// homogenous equality for comparing values.
223
template <typename EqualsProvider>
224
absl::StatusOr<absl::optional<bool>> MapEqual(
225
    const MapValue& lhs, const MapValue& rhs,
226
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
227
    google::protobuf::MessageFactory* absl_nonnull message_factory,
228
10.0k
    google::protobuf::Arena* absl_nonnull arena) {
229
10.0k
  if (&lhs == &rhs) {
230
0
    return true;
231
0
  }
232
10.0k
  if (lhs.Size() != rhs.Size()) {
233
3.42k
    return false;
234
3.42k
  }
235
236
13.2k
  CEL_ASSIGN_OR_RETURN(auto iter, lhs.NewIterator());
237
238
13.2k
  while (iter->HasNext()) {
239
6.30k
    CEL_ASSIGN_OR_RETURN(auto lhs_key,
240
6.30k
                         iter->Next(descriptor_pool, message_factory, arena));
241
242
6.30k
    absl::optional<Value> entry;
243
6.30k
    CEL_ASSIGN_OR_RETURN(
244
6.30k
        entry, rhs.Find(lhs_key, descriptor_pool, message_factory, arena));
245
246
6.30k
    if (!entry && EqualsProvider::kIsHeterogeneous) {
247
5.00k
      CEL_ASSIGN_OR_RETURN(
248
5.00k
          entry, CheckAlternativeNumericType(lhs_key, rhs, descriptor_pool,
249
5.00k
                                             message_factory, arena));
250
5.00k
    }
251
6.30k
    if (!entry) {
252
4.58k
      return false;
253
4.58k
    }
254
255
3.42k
    CEL_ASSIGN_OR_RETURN(auto lhs_value, lhs.Get(lhs_key, descriptor_pool,
256
3.42k
                                                 message_factory, arena));
257
3.42k
    CEL_ASSIGN_OR_RETURN(absl::optional<bool> eq,
258
1.71k
                         EqualsProvider()(lhs_value, *entry, descriptor_pool,
259
1.71k
                                          message_factory, arena));
260
261
1.71k
    if (!eq.has_value() || !*eq) {
262
687
      return eq;
263
687
    }
264
1.71k
  }
265
266
1.37k
  return true;
267
13.2k
}
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::StatusOr<std::__1::optional<bool> > cel::(anonymous namespace)::MapEqual<cel::(anonymous namespace)::HomogenousEqualProvider>(cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)
equality_functions.cc:absl::lts_20260526::StatusOr<std::__1::optional<bool> > cel::(anonymous namespace)::MapEqual<cel::(anonymous namespace)::HeterogeneousEqualProvider>(cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)
Line
Count
Source
228
10.0k
    google::protobuf::Arena* absl_nonnull arena) {
229
10.0k
  if (&lhs == &rhs) {
230
0
    return true;
231
0
  }
232
10.0k
  if (lhs.Size() != rhs.Size()) {
233
3.42k
    return false;
234
3.42k
  }
235
236
13.2k
  CEL_ASSIGN_OR_RETURN(auto iter, lhs.NewIterator());
237
238
13.2k
  while (iter->HasNext()) {
239
6.30k
    CEL_ASSIGN_OR_RETURN(auto lhs_key,
240
6.30k
                         iter->Next(descriptor_pool, message_factory, arena));
241
242
6.30k
    absl::optional<Value> entry;
243
6.30k
    CEL_ASSIGN_OR_RETURN(
244
6.30k
        entry, rhs.Find(lhs_key, descriptor_pool, message_factory, arena));
245
246
6.30k
    if (!entry && EqualsProvider::kIsHeterogeneous) {
247
5.00k
      CEL_ASSIGN_OR_RETURN(
248
5.00k
          entry, CheckAlternativeNumericType(lhs_key, rhs, descriptor_pool,
249
5.00k
                                             message_factory, arena));
250
5.00k
    }
251
6.30k
    if (!entry) {
252
4.58k
      return false;
253
4.58k
    }
254
255
3.42k
    CEL_ASSIGN_OR_RETURN(auto lhs_value, lhs.Get(lhs_key, descriptor_pool,
256
3.42k
                                                 message_factory, arena));
257
3.42k
    CEL_ASSIGN_OR_RETURN(absl::optional<bool> eq,
258
1.71k
                         EqualsProvider()(lhs_value, *entry, descriptor_pool,
259
1.71k
                                          message_factory, arena));
260
261
1.71k
    if (!eq.has_value() || !*eq) {
262
687
      return eq;
263
687
    }
264
1.71k
  }
265
266
1.37k
  return true;
267
13.2k
}
268
269
// Helper for wrapping ==/!= implementations.
270
// Name should point to a static constexpr string so the lambda capture is safe.
271
template <typename Type, typename Op>
272
std::function<Value(Type, Type, const google::protobuf::DescriptorPool* absl_nonnull,
273
                    google::protobuf::MessageFactory* absl_nonnull,
274
                    google::protobuf::Arena* absl_nonnull)>
275
0
WrapComparison(Op op, absl::string_view name) {
276
0
  return [op = std::move(op), name](
277
0
             Type lhs, Type rhs,
278
0
             const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
279
0
             google::protobuf::MessageFactory* absl_nonnull message_factory,
280
0
             google::protobuf::Arena* absl_nonnull arena) -> Value {
281
0
    absl::optional<bool> result = op(lhs, rhs);
282
283
0
    if (result.has_value()) {
284
0
      return BoolValue(*result);
285
0
    }
286
287
0
    return ErrorValue::From(
288
0
        cel::runtime_internal::CreateNoMatchingOverloadError(name), arena);
289
0
  };
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::WrapComparison<bool, std::__1::optional<bool> (*)(bool, bool)>(std::__1::optional<bool> (*)(bool, bool), std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(bool, bool, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(bool, bool, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::WrapComparison<long, std::__1::optional<bool> (*)(long, long)>(std::__1::optional<bool> (*)(long, long), std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(long, long, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(long, long, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::WrapComparison<unsigned long, std::__1::optional<bool> (*)(unsigned long, unsigned long)>(std::__1::optional<bool> (*)(unsigned long, unsigned long), std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(unsigned long, unsigned long, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(unsigned long, unsigned long, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::WrapComparison<double, std::__1::optional<bool> (*)(double, double)>(std::__1::optional<bool> (*)(double, double), std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(double, double, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(double, double, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::WrapComparison<cel::StringValue const&, std::__1::optional<bool> (*)(cel::StringValue const&, cel::StringValue const&)>(std::__1::optional<bool> (*)(cel::StringValue const&, cel::StringValue const&), std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(cel::StringValue const&, cel::StringValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(cel::StringValue const&, cel::StringValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::WrapComparison<cel::BytesValue const&, std::__1::optional<bool> (*)(cel::BytesValue const&, cel::BytesValue const&)>(std::__1::optional<bool> (*)(cel::BytesValue const&, cel::BytesValue const&), std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(cel::BytesValue const&, cel::BytesValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(cel::BytesValue const&, cel::BytesValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::WrapComparison<absl::lts_20260526::Duration, std::__1::optional<bool> (*)(absl::lts_20260526::Duration, absl::lts_20260526::Duration)>(std::__1::optional<bool> (*)(absl::lts_20260526::Duration, absl::lts_20260526::Duration), std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(absl::lts_20260526::Duration, absl::lts_20260526::Duration, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(absl::lts_20260526::Duration, absl::lts_20260526::Duration, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::WrapComparison<absl::lts_20260526::Time, std::__1::optional<bool> (*)(absl::lts_20260526::Time, absl::lts_20260526::Time)>(std::__1::optional<bool> (*)(absl::lts_20260526::Time, absl::lts_20260526::Time), std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(absl::lts_20260526::Time, absl::lts_20260526::Time, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(absl::lts_20260526::Time, absl::lts_20260526::Time, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::WrapComparison<cel::NullValue const&, std::__1::optional<bool> (*)(cel::NullValue const&, cel::NullValue const&)>(std::__1::optional<bool> (*)(cel::NullValue const&, cel::NullValue const&), std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(cel::NullValue const&, cel::NullValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(cel::NullValue const&, cel::NullValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::WrapComparison<cel::TypeValue const&, std::__1::optional<bool> (*)(cel::TypeValue const&, cel::TypeValue const&)>(std::__1::optional<bool> (*)(cel::TypeValue const&, cel::TypeValue const&), std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(cel::TypeValue const&, cel::TypeValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(cel::TypeValue const&, cel::TypeValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
290
0
}
Unexecuted instantiation: equality_functions.cc:std::__1::function<cel::Value (bool, bool, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)> cel::(anonymous namespace)::WrapComparison<bool, std::__1::optional<bool> (*)(bool, bool)>(std::__1::optional<bool> (*)(bool, bool), std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Unexecuted instantiation: equality_functions.cc:std::__1::function<cel::Value (long, long, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)> cel::(anonymous namespace)::WrapComparison<long, std::__1::optional<bool> (*)(long, long)>(std::__1::optional<bool> (*)(long, long), std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Unexecuted instantiation: equality_functions.cc:std::__1::function<cel::Value (unsigned long, unsigned long, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)> cel::(anonymous namespace)::WrapComparison<unsigned long, std::__1::optional<bool> (*)(unsigned long, unsigned long)>(std::__1::optional<bool> (*)(unsigned long, unsigned long), std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Unexecuted instantiation: equality_functions.cc:std::__1::function<cel::Value (double, double, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)> cel::(anonymous namespace)::WrapComparison<double, std::__1::optional<bool> (*)(double, double)>(std::__1::optional<bool> (*)(double, double), std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Unexecuted instantiation: equality_functions.cc:std::__1::function<cel::Value (cel::StringValue const&, cel::StringValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)> cel::(anonymous namespace)::WrapComparison<cel::StringValue const&, std::__1::optional<bool> (*)(cel::StringValue const&, cel::StringValue const&)>(std::__1::optional<bool> (*)(cel::StringValue const&, cel::StringValue const&), std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Unexecuted instantiation: equality_functions.cc:std::__1::function<cel::Value (cel::BytesValue const&, cel::BytesValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)> cel::(anonymous namespace)::WrapComparison<cel::BytesValue const&, std::__1::optional<bool> (*)(cel::BytesValue const&, cel::BytesValue const&)>(std::__1::optional<bool> (*)(cel::BytesValue const&, cel::BytesValue const&), std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Unexecuted instantiation: equality_functions.cc:std::__1::function<cel::Value (absl::lts_20260526::Duration, absl::lts_20260526::Duration, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)> cel::(anonymous namespace)::WrapComparison<absl::lts_20260526::Duration, std::__1::optional<bool> (*)(absl::lts_20260526::Duration, absl::lts_20260526::Duration)>(std::__1::optional<bool> (*)(absl::lts_20260526::Duration, absl::lts_20260526::Duration), std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Unexecuted instantiation: equality_functions.cc:std::__1::function<cel::Value (absl::lts_20260526::Time, absl::lts_20260526::Time, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)> cel::(anonymous namespace)::WrapComparison<absl::lts_20260526::Time, std::__1::optional<bool> (*)(absl::lts_20260526::Time, absl::lts_20260526::Time)>(std::__1::optional<bool> (*)(absl::lts_20260526::Time, absl::lts_20260526::Time), std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Unexecuted instantiation: equality_functions.cc:std::__1::function<cel::Value (cel::NullValue const&, cel::NullValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)> cel::(anonymous namespace)::WrapComparison<cel::NullValue const&, std::__1::optional<bool> (*)(cel::NullValue const&, cel::NullValue const&)>(std::__1::optional<bool> (*)(cel::NullValue const&, cel::NullValue const&), std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Unexecuted instantiation: equality_functions.cc:std::__1::function<cel::Value (cel::TypeValue const&, cel::TypeValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)> cel::(anonymous namespace)::WrapComparison<cel::TypeValue const&, std::__1::optional<bool> (*)(cel::TypeValue const&, cel::TypeValue const&)>(std::__1::optional<bool> (*)(cel::TypeValue const&, cel::TypeValue const&), std::__1::basic_string_view<char, std::__1::char_traits<char> >)
291
292
// Helper method
293
//
294
// Registers all equality functions for template parameters type.
295
template <class Type>
296
0
absl::Status RegisterEqualityFunctionsForType(cel::FunctionRegistry& registry) {
297
0
  using FunctionAdapter =
298
0
      cel::RegisterHelper<BinaryFunctionAdapter<Value, Type, Type>>;
299
  // Inequality
300
0
  CEL_RETURN_IF_ERROR(FunctionAdapter::RegisterGlobalOverload(
301
0
      kInequal, WrapComparison<Type>(&Inequal<Type>, kInequal), registry));
302
303
  // Equality
304
0
  CEL_RETURN_IF_ERROR(FunctionAdapter::RegisterGlobalOverload(
305
0
      kEqual, WrapComparison<Type>(&Equal<Type>, kEqual), registry));
306
307
0
  return absl::OkStatus();
308
0
}
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<bool>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<long>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<unsigned long>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<double>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<cel::StringValue const&>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<cel::BytesValue const&>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<absl::lts_20260526::Duration>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<absl::lts_20260526::Time>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<cel::NullValue const&>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<cel::TypeValue const&>(cel::FunctionRegistry&)
309
310
template <typename Type, typename Op>
311
0
auto ComplexEquality(Op&& op) {
312
0
  return [op = std::forward<Op>(op)](
313
0
             const Type& t1, const Type& t2,
314
0
             const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
315
0
             google::protobuf::MessageFactory* absl_nonnull message_factory,
316
0
             google::protobuf::Arena* absl_nonnull arena) -> absl::StatusOr<Value> {
317
0
    CEL_ASSIGN_OR_RETURN(absl::optional<bool> result,
318
0
                         op(t1, t2, descriptor_pool, message_factory, arena));
319
0
    if (!result.has_value()) {
320
0
      return ErrorValue::From(
321
0
          cel::runtime_internal::CreateNoMatchingOverloadError(kEqual), arena);
322
0
    }
323
0
    return BoolValue(*result);
324
0
  };
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::ComplexEquality<cel::ListValue const&, absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&)::{lambda(cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::ComplexEquality<cel::MapValue const&, absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&)::{lambda(cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
325
0
}
Unexecuted instantiation: equality_functions.cc:auto cel::(anonymous namespace)::ComplexEquality<cel::ListValue const&, absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&)
Unexecuted instantiation: equality_functions.cc:auto cel::(anonymous namespace)::ComplexEquality<cel::MapValue const&, absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&)
326
327
template <typename Type, typename Op>
328
0
auto ComplexInequality(Op&& op) {
329
0
  return [op = std::forward<Op>(op)](
330
0
             Type t1, Type t2,
331
0
             const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
332
0
             google::protobuf::MessageFactory* absl_nonnull message_factory,
333
0
             google::protobuf::Arena* absl_nonnull arena) -> absl::StatusOr<Value> {
334
0
    CEL_ASSIGN_OR_RETURN(absl::optional<bool> result,
335
0
                         op(t1, t2, descriptor_pool, message_factory, arena));
336
0
    if (!result.has_value()) {
337
0
      return ErrorValue::From(
338
0
          cel::runtime_internal::CreateNoMatchingOverloadError(kInequal),
339
0
          arena);
340
0
    }
341
0
    return BoolValue(!*result);
342
0
  };
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::ComplexInequality<cel::ListValue const&, absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&)::{lambda(cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::ComplexInequality<cel::MapValue const&, absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&)::{lambda(cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
343
0
}
Unexecuted instantiation: equality_functions.cc:auto cel::(anonymous namespace)::ComplexInequality<cel::ListValue const&, absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&)
Unexecuted instantiation: equality_functions.cc:auto cel::(anonymous namespace)::ComplexInequality<cel::MapValue const&, absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&)
344
345
template <class Type>
346
absl::Status RegisterComplexEqualityFunctionsForType(
347
    absl::FunctionRef<absl::StatusOr<absl::optional<bool>>(
348
        Type, Type, const google::protobuf::DescriptorPool* absl_nonnull,
349
        google::protobuf::MessageFactory* absl_nonnull, google::protobuf::Arena* absl_nonnull)>
350
        op,
351
0
    cel::FunctionRegistry& registry) {
352
0
  using FunctionAdapter = cel::RegisterHelper<
353
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, Type, Type>>;
354
  // Inequality
355
0
  CEL_RETURN_IF_ERROR(FunctionAdapter::RegisterGlobalOverload(
356
0
      kInequal, ComplexInequality<Type>(op), registry));
357
358
  // Equality
359
0
  CEL_RETURN_IF_ERROR(FunctionAdapter::RegisterGlobalOverload(
360
0
      kEqual, ComplexEquality<Type>(op), registry));
361
362
0
  return absl::OkStatus();
363
0
}
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::Status cel::(anonymous namespace)::RegisterComplexEqualityFunctionsForType<cel::ListValue const&>(absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>, cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::Status cel::(anonymous namespace)::RegisterComplexEqualityFunctionsForType<cel::MapValue const&>(absl::lts_20260526::FunctionRef<absl::lts_20260526::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>, cel::FunctionRegistry&)
364
365
absl::Status RegisterHomogenousEqualityFunctions(
366
0
    cel::FunctionRegistry& registry) {
367
0
  CEL_RETURN_IF_ERROR(RegisterEqualityFunctionsForType<bool>(registry));
368
369
0
  CEL_RETURN_IF_ERROR(RegisterEqualityFunctionsForType<int64_t>(registry));
370
371
0
  CEL_RETURN_IF_ERROR(RegisterEqualityFunctionsForType<uint64_t>(registry));
372
373
0
  CEL_RETURN_IF_ERROR(RegisterEqualityFunctionsForType<double>(registry));
374
375
0
  CEL_RETURN_IF_ERROR(
376
0
      RegisterEqualityFunctionsForType<const cel::StringValue&>(registry));
377
378
0
  CEL_RETURN_IF_ERROR(
379
0
      RegisterEqualityFunctionsForType<const cel::BytesValue&>(registry));
380
381
0
  CEL_RETURN_IF_ERROR(
382
0
      RegisterEqualityFunctionsForType<absl::Duration>(registry));
383
384
0
  CEL_RETURN_IF_ERROR(RegisterEqualityFunctionsForType<absl::Time>(registry));
385
386
0
  CEL_RETURN_IF_ERROR(
387
0
      RegisterEqualityFunctionsForType<const cel::NullValue&>(registry));
388
389
0
  CEL_RETURN_IF_ERROR(
390
0
      RegisterEqualityFunctionsForType<const cel::TypeValue&>(registry));
391
392
0
  CEL_RETURN_IF_ERROR(
393
0
      RegisterComplexEqualityFunctionsForType<const cel::ListValue&>(
394
0
          &ListEqual<HomogenousEqualProvider>, registry));
395
396
0
  CEL_RETURN_IF_ERROR(
397
0
      RegisterComplexEqualityFunctionsForType<const cel::MapValue&>(
398
0
          &MapEqual<HomogenousEqualProvider>, registry));
399
400
0
  return absl::OkStatus();
401
0
}
402
403
0
absl::Status RegisterNullMessageEqualityFunctions(FunctionRegistry& registry) {
404
  // equals
405
0
  CEL_RETURN_IF_ERROR(
406
0
      (cel::RegisterHelper<
407
0
          BinaryFunctionAdapter<bool, const StructValue&, const NullValue&>>::
408
0
           RegisterGlobalOverload(
409
0
               kEqual,
410
0
               [](const StructValue&, const NullValue&) { return false; },
411
0
               registry)));
412
413
0
  CEL_RETURN_IF_ERROR(
414
0
      (cel::RegisterHelper<
415
0
          BinaryFunctionAdapter<bool, const NullValue&, const StructValue&>>::
416
0
           RegisterGlobalOverload(
417
0
               kEqual,
418
0
               [](const NullValue&, const StructValue&) { return false; },
419
0
               registry)));
420
421
  // inequals
422
0
  CEL_RETURN_IF_ERROR(
423
0
      (cel::RegisterHelper<
424
0
          BinaryFunctionAdapter<bool, const StructValue&, const NullValue&>>::
425
0
           RegisterGlobalOverload(
426
0
               kInequal,
427
0
               [](const StructValue&, const NullValue&) { return true; },
428
0
               registry)));
429
430
0
  return cel::RegisterHelper<
431
0
      BinaryFunctionAdapter<bool, const NullValue&, const StructValue&>>::
432
0
      RegisterGlobalOverload(
433
0
          kInequal, [](const NullValue&, const StructValue&) { return true; },
434
0
          registry);
435
0
}
436
437
template <typename EqualsProvider>
438
absl::StatusOr<absl::optional<bool>> HomogenousValueEqual(
439
    const Value& v1, const Value& v2,
440
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
441
    google::protobuf::MessageFactory* absl_nonnull message_factory,
442
30.5k
    google::protobuf::Arena* absl_nonnull arena) {
443
30.5k
  if (v1.kind() != v2.kind()) {
444
0
    return std::nullopt;
445
0
  }
446
447
30.5k
  static_assert(std::is_lvalue_reference_v<decltype(v1.GetString())>,
448
30.5k
                "unexpected value copy");
449
450
30.5k
  switch (v1->kind()) {
451
408
    case ValueKind::kBool:
452
408
      return Equal<bool>(v1.GetBool().NativeValue(),
453
408
                         v2.GetBool().NativeValue());
454
0
    case ValueKind::kNull:
455
0
      return Equal<const NullValue&>(v1.GetNull(), v2.GetNull());
456
4.89k
    case ValueKind::kInt:
457
4.89k
      return Equal<int64_t>(v1.GetInt().NativeValue(),
458
4.89k
                            v2.GetInt().NativeValue());
459
8.25k
    case ValueKind::kUint:
460
8.25k
      return Equal<uint64_t>(v1.GetUint().NativeValue(),
461
8.25k
                             v2.GetUint().NativeValue());
462
777
    case ValueKind::kDouble:
463
777
      return Equal<double>(v1.GetDouble().NativeValue(),
464
777
                           v2.GetDouble().NativeValue());
465
145
    case ValueKind::kDuration:
466
145
      return Equal<absl::Duration>(v1.GetDuration().NativeValue(),
467
145
                                   v2.GetDuration().NativeValue());
468
529
    case ValueKind::kTimestamp:
469
529
      return Equal<absl::Time>(v1.GetTimestamp().NativeValue(),
470
529
                               v2.GetTimestamp().NativeValue());
471
1.74k
    case ValueKind::kCelType:
472
1.74k
      return Equal<const TypeValue&>(v1.GetType(), v2.GetType());
473
327
    case ValueKind::kString:
474
327
      return Equal<const StringValue&>(v1.GetString(), v2.GetString());
475
720
    case ValueKind::kBytes:
476
720
      return Equal<const cel::BytesValue&>(v1.GetBytes(), v2.GetBytes());
477
2.67k
    case ValueKind::kList:
478
2.67k
      return ListEqual<EqualsProvider>(v1.GetList(), v2.GetList(),
479
2.67k
                                       descriptor_pool, message_factory, arena);
480
10.0k
    case ValueKind::kMap:
481
10.0k
      return MapEqual<EqualsProvider>(v1.GetMap(), v2.GetMap(), descriptor_pool,
482
10.0k
                                      message_factory, arena);
483
0
    case ValueKind::kOpaque:
484
0
      return OpaqueEqual(v1.GetOpaque(), v2.GetOpaque(), descriptor_pool,
485
0
                         message_factory, arena);
486
0
    default:
487
0
      return std::nullopt;
488
30.5k
  }
489
30.5k
}
Unexecuted instantiation: equality_functions.cc:absl::lts_20260526::StatusOr<std::__1::optional<bool> > cel::(anonymous namespace)::HomogenousValueEqual<cel::(anonymous namespace)::HomogenousEqualProvider>(cel::Value const&, cel::Value const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)
equality_functions.cc:absl::lts_20260526::StatusOr<std::__1::optional<bool> > cel::(anonymous namespace)::HomogenousValueEqual<cel::(anonymous namespace)::HeterogeneousEqualProvider>(cel::Value const&, cel::Value const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)
Line
Count
Source
442
30.5k
    google::protobuf::Arena* absl_nonnull arena) {
443
30.5k
  if (v1.kind() != v2.kind()) {
444
0
    return std::nullopt;
445
0
  }
446
447
30.5k
  static_assert(std::is_lvalue_reference_v<decltype(v1.GetString())>,
448
30.5k
                "unexpected value copy");
449
450
30.5k
  switch (v1->kind()) {
451
408
    case ValueKind::kBool:
452
408
      return Equal<bool>(v1.GetBool().NativeValue(),
453
408
                         v2.GetBool().NativeValue());
454
0
    case ValueKind::kNull:
455
0
      return Equal<const NullValue&>(v1.GetNull(), v2.GetNull());
456
4.89k
    case ValueKind::kInt:
457
4.89k
      return Equal<int64_t>(v1.GetInt().NativeValue(),
458
4.89k
                            v2.GetInt().NativeValue());
459
8.25k
    case ValueKind::kUint:
460
8.25k
      return Equal<uint64_t>(v1.GetUint().NativeValue(),
461
8.25k
                             v2.GetUint().NativeValue());
462
777
    case ValueKind::kDouble:
463
777
      return Equal<double>(v1.GetDouble().NativeValue(),
464
777
                           v2.GetDouble().NativeValue());
465
145
    case ValueKind::kDuration:
466
145
      return Equal<absl::Duration>(v1.GetDuration().NativeValue(),
467
145
                                   v2.GetDuration().NativeValue());
468
529
    case ValueKind::kTimestamp:
469
529
      return Equal<absl::Time>(v1.GetTimestamp().NativeValue(),
470
529
                               v2.GetTimestamp().NativeValue());
471
1.74k
    case ValueKind::kCelType:
472
1.74k
      return Equal<const TypeValue&>(v1.GetType(), v2.GetType());
473
327
    case ValueKind::kString:
474
327
      return Equal<const StringValue&>(v1.GetString(), v2.GetString());
475
720
    case ValueKind::kBytes:
476
720
      return Equal<const cel::BytesValue&>(v1.GetBytes(), v2.GetBytes());
477
2.67k
    case ValueKind::kList:
478
2.67k
      return ListEqual<EqualsProvider>(v1.GetList(), v2.GetList(),
479
2.67k
                                       descriptor_pool, message_factory, arena);
480
10.0k
    case ValueKind::kMap:
481
10.0k
      return MapEqual<EqualsProvider>(v1.GetMap(), v2.GetMap(), descriptor_pool,
482
10.0k
                                      message_factory, arena);
483
0
    case ValueKind::kOpaque:
484
0
      return OpaqueEqual(v1.GetOpaque(), v2.GetOpaque(), descriptor_pool,
485
0
                         message_factory, arena);
486
0
    default:
487
0
      return std::nullopt;
488
30.5k
  }
489
30.5k
}
490
491
absl::StatusOr<Value> EqualOverloadImpl(
492
    const Value& lhs, const Value& rhs,
493
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
494
    google::protobuf::MessageFactory* absl_nonnull message_factory,
495
0
    google::protobuf::Arena* absl_nonnull arena) {
496
0
  CEL_ASSIGN_OR_RETURN(absl::optional<bool> result,
497
0
                       runtime_internal::ValueEqualImpl(
498
0
                           lhs, rhs, descriptor_pool, message_factory, arena));
499
0
  if (result.has_value()) {
500
0
    return BoolValue(*result);
501
0
  }
502
0
  return ErrorValue::From(
503
0
      cel::runtime_internal::CreateNoMatchingOverloadError(kEqual), arena);
504
0
}
505
506
absl::StatusOr<Value> InequalOverloadImpl(
507
    const Value& lhs, const Value& rhs,
508
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
509
    google::protobuf::MessageFactory* absl_nonnull message_factory,
510
0
    google::protobuf::Arena* absl_nonnull arena) {
511
0
  CEL_ASSIGN_OR_RETURN(absl::optional<bool> result,
512
0
                       runtime_internal::ValueEqualImpl(
513
0
                           lhs, rhs, descriptor_pool, message_factory, arena));
514
0
  if (result.has_value()) {
515
0
    return BoolValue(!*result);
516
0
  }
517
0
  return ErrorValue::From(
518
0
      cel::runtime_internal::CreateNoMatchingOverloadError(kInequal), arena);
519
0
}
520
521
absl::Status RegisterHeterogeneousEqualityFunctions(
522
0
    cel::FunctionRegistry& registry) {
523
0
  using Adapter = cel::RegisterHelper<
524
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, const Value&, const Value&>>;
525
0
  CEL_RETURN_IF_ERROR(
526
0
      Adapter::RegisterGlobalOverload(kEqual, &EqualOverloadImpl, registry));
527
528
0
  CEL_RETURN_IF_ERROR(Adapter::RegisterGlobalOverload(
529
0
      kInequal, &InequalOverloadImpl, registry));
530
531
0
  return absl::OkStatus();
532
0
}
533
534
absl::StatusOr<absl::optional<bool>> HomogenousEqualProvider::operator()(
535
    const Value& lhs, const Value& rhs,
536
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
537
    google::protobuf::MessageFactory* absl_nonnull message_factory,
538
0
    google::protobuf::Arena* absl_nonnull arena) const {
539
0
  return HomogenousValueEqual<HomogenousEqualProvider>(
540
0
      lhs, rhs, descriptor_pool, message_factory, arena);
541
0
}
542
543
absl::StatusOr<absl::optional<bool>> HeterogeneousEqualProvider::operator()(
544
    const Value& lhs, const Value& rhs,
545
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
546
    google::protobuf::MessageFactory* absl_nonnull message_factory,
547
3.53k
    google::protobuf::Arena* absl_nonnull arena) const {
548
3.53k
  return runtime_internal::ValueEqualImpl(lhs, rhs, descriptor_pool,
549
3.53k
                                          message_factory, arena);
550
3.53k
}
551
552
}  // namespace
553
554
namespace runtime_internal {
555
556
absl::StatusOr<absl::optional<bool>> ValueEqualImpl(
557
    const Value& v1, const Value& v2,
558
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
559
    google::protobuf::MessageFactory* absl_nonnull message_factory,
560
94.9k
    google::protobuf::Arena* absl_nonnull arena) {
561
94.9k
  if (v1.kind() == v2.kind()) {
562
30.5k
    if (v1.IsStruct() && v2.IsStruct()) {
563
0
      CEL_ASSIGN_OR_RETURN(
564
0
          Value result,
565
0
          v1.GetStruct().Equal(v2, descriptor_pool, message_factory, arena));
566
0
      if (result.IsBool()) {
567
0
        return result.GetBool().NativeValue();
568
0
      }
569
0
      return false;
570
0
    }
571
30.5k
    return HomogenousValueEqual<HeterogeneousEqualProvider>(
572
30.5k
        v1, v2, descriptor_pool, message_factory, arena);
573
30.5k
  }
574
575
64.4k
  absl::optional<Number> lhs = NumberFromValue(v1);
576
64.4k
  absl::optional<Number> rhs = NumberFromValue(v2);
577
578
64.4k
  if (rhs.has_value() && lhs.has_value()) {
579
49.5k
    return *lhs == *rhs;
580
49.5k
  }
581
582
  // TODO(uncreated-issue/6): It's currently possible for the interpreter to create a
583
  // map containing an Error. Return no matching overload to propagate an error
584
  // instead of a false result.
585
14.9k
  if (v1.IsError() || v1.IsUnknown() || v2.IsError() || v2.IsUnknown()) {
586
0
    return std::nullopt;
587
0
  }
588
589
14.9k
  return false;
590
14.9k
}
591
592
}  // namespace runtime_internal
593
594
absl::Status RegisterEqualityFunctions(FunctionRegistry& registry,
595
22.7k
                                       const RuntimeOptions& options) {
596
22.7k
  if (options.enable_heterogeneous_equality) {
597
22.7k
    if (options.enable_fast_builtins) {
598
      // If enabled, the evaluator provides an implementation that works
599
      // directly on the value stack.
600
22.7k
      return absl::OkStatus();
601
22.7k
    }
602
    // Heterogeneous equality uses one generic overload that delegates to the
603
    // right equality implementation at runtime.
604
0
    CEL_RETURN_IF_ERROR(RegisterHeterogeneousEqualityFunctions(registry));
605
0
  } else {
606
0
    CEL_RETURN_IF_ERROR(RegisterHomogenousEqualityFunctions(registry));
607
608
0
    CEL_RETURN_IF_ERROR(RegisterNullMessageEqualityFunctions(registry));
609
0
  }
610
0
  return absl::OkStatus();
611
22.7k
}
612
613
}  // namespace cel