Coverage Report

Created: 2026-05-27 07:00

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_20260107::Duration>(absl::lts_20260107::Duration, absl::lts_20260107::Duration)
Unexecuted instantiation: equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Inequal<absl::lts_20260107::Time>(absl::lts_20260107::Time, absl::lts_20260107::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
532
absl::optional<bool> Equal(Type lhs, Type rhs) {
103
532
  return lhs == rhs;
104
532
}
equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Equal<bool>(bool, bool)
Line
Count
Source
102
9
absl::optional<bool> Equal(Type lhs, Type rhs) {
103
9
  return lhs == rhs;
104
9
}
equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Equal<long>(long, long)
Line
Count
Source
102
309
absl::optional<bool> Equal(Type lhs, Type rhs) {
103
309
  return lhs == rhs;
104
309
}
equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Equal<unsigned long>(unsigned long, unsigned long)
Line
Count
Source
102
180
absl::optional<bool> Equal(Type lhs, Type rhs) {
103
180
  return lhs == rhs;
104
180
}
equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Equal<double>(double, double)
Line
Count
Source
102
34
absl::optional<bool> Equal(Type lhs, Type rhs) {
103
34
  return lhs == rhs;
104
34
}
Unexecuted instantiation: equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Equal<absl::lts_20260107::Duration>(absl::lts_20260107::Duration, absl::lts_20260107::Duration)
Unexecuted instantiation: equality_functions.cc:std::__1::optional<bool> cel::(anonymous namespace)::Equal<absl::lts_20260107::Time>(absl::lts_20260107::Time, absl::lts_20260107::Time)
105
106
template <>
107
113
absl::optional<bool> Equal(const StringValue& lhs, const StringValue& rhs) {
108
113
  return lhs.Equals(rhs);
109
113
}
110
111
template <>
112
18
absl::optional<bool> Equal(const BytesValue& lhs, const BytesValue& rhs) {
113
18
  return lhs.Equals(rhs);
114
18
}
115
116
template <>
117
0
absl::optional<bool> Equal(const NullValue&, const NullValue&) {
118
0
  return true;
119
0
}
120
121
template <>
122
2
absl::optional<bool> Equal(const TypeValue& lhs, const TypeValue& rhs) {
123
2
  return lhs.name() == rhs.name();
124
2
}
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
84
    google::protobuf::Arena* absl_nonnull arena) {
134
84
  if (&lhs == &rhs) {
135
0
    return true;
136
0
  }
137
168
  CEL_ASSIGN_OR_RETURN(auto lhs_size, lhs.Size());
138
168
  CEL_ASSIGN_OR_RETURN(auto rhs_size, rhs.Size());
139
84
  if (lhs_size != rhs_size) {
140
14
    return false;
141
14
  }
142
143
74
  for (int i = 0; i < lhs_size; ++i) {
144
20
    CEL_ASSIGN_OR_RETURN(auto lhs_i,
145
20
                         lhs.Get(i, descriptor_pool, message_factory, arena));
146
20
    CEL_ASSIGN_OR_RETURN(auto rhs_i,
147
20
                         rhs.Get(i, descriptor_pool, message_factory, arena));
148
20
    CEL_ASSIGN_OR_RETURN(absl::optional<bool> eq,
149
20
                         EqualsProvider()(lhs_i, rhs_i, descriptor_pool,
150
20
                                          message_factory, arena));
151
20
    if (!eq.has_value() || !*eq) {
152
16
      return eq;
153
16
    }
154
20
  }
155
54
  return true;
156
70
}
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::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_20260107::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
84
    google::protobuf::Arena* absl_nonnull arena) {
134
84
  if (&lhs == &rhs) {
135
0
    return true;
136
0
  }
137
168
  CEL_ASSIGN_OR_RETURN(auto lhs_size, lhs.Size());
138
168
  CEL_ASSIGN_OR_RETURN(auto rhs_size, rhs.Size());
139
84
  if (lhs_size != rhs_size) {
140
14
    return false;
141
14
  }
142
143
74
  for (int i = 0; i < lhs_size; ++i) {
144
20
    CEL_ASSIGN_OR_RETURN(auto lhs_i,
145
20
                         lhs.Get(i, descriptor_pool, message_factory, arena));
146
20
    CEL_ASSIGN_OR_RETURN(auto rhs_i,
147
20
                         rhs.Get(i, descriptor_pool, message_factory, arena));
148
20
    CEL_ASSIGN_OR_RETURN(absl::optional<bool> eq,
149
20
                         EqualsProvider()(lhs_i, rhs_i, descriptor_pool,
150
20
                                          message_factory, arena));
151
20
    if (!eq.has_value() || !*eq) {
152
16
      return eq;
153
16
    }
154
20
  }
155
54
  return true;
156
70
}
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 TypeConversionError(result.GetTypeName(), "bool").NativeValue();
173
0
}
174
175
6.13k
absl::optional<Number> NumberFromValue(const Value& value) {
176
6.13k
  if (value.Is<IntValue>()) {
177
2.22k
    return Number::FromInt64(value.GetInt().NativeValue());
178
3.90k
  } else if (value.Is<UintValue>()) {
179
1.42k
    return Number::FromUint64(value.GetUint().NativeValue());
180
2.48k
  } else if (value.Is<DoubleValue>()) {
181
1.04k
    return Number::FromDouble(value.GetDouble().NativeValue());
182
1.04k
  }
183
184
1.44k
  return absl::nullopt;
185
6.13k
}
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
30
    google::protobuf::Arena* absl_nonnull arena) {
192
30
  absl::optional<Number> number = NumberFromValue(key);
193
194
30
  if (!number.has_value()) {
195
1
    return absl::nullopt;
196
1
  }
197
198
29
  if (!key.IsInt() && number->LosslessConvertibleToInt()) {
199
5
    absl::optional<Value> entry;
200
5
    CEL_ASSIGN_OR_RETURN(entry,
201
5
                         rhs.Find(IntValue(number->AsInt()), descriptor_pool,
202
5
                                  message_factory, arena));
203
5
    if (entry) {
204
0
      return entry;
205
0
    }
206
5
  }
207
208
29
  if (!key.IsUint() && number->LosslessConvertibleToUint()) {
209
19
    absl::optional<Value> entry;
210
19
    CEL_ASSIGN_OR_RETURN(entry,
211
19
                         rhs.Find(UintValue(number->AsUint()), descriptor_pool,
212
19
                                  message_factory, arena));
213
19
    if (entry) {
214
0
      return entry;
215
0
    }
216
19
  }
217
218
29
  return absl::nullopt;
219
29
}
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
50
    google::protobuf::Arena* absl_nonnull arena) {
229
50
  if (&lhs == &rhs) {
230
0
    return true;
231
0
  }
232
50
  if (lhs.Size() != rhs.Size()) {
233
5
    return false;
234
5
  }
235
236
90
  CEL_ASSIGN_OR_RETURN(auto iter, lhs.NewIterator());
237
238
90
  while (iter->HasNext()) {
239
44
    CEL_ASSIGN_OR_RETURN(auto lhs_key,
240
44
                         iter->Next(descriptor_pool, message_factory, arena));
241
242
44
    absl::optional<Value> entry;
243
44
    CEL_ASSIGN_OR_RETURN(
244
44
        entry, rhs.Find(lhs_key, descriptor_pool, message_factory, arena));
245
246
44
    if (!entry && EqualsProvider::kIsHeterogeneous) {
247
30
      CEL_ASSIGN_OR_RETURN(
248
30
          entry, CheckAlternativeNumericType(lhs_key, rhs, descriptor_pool,
249
30
                                             message_factory, arena));
250
30
    }
251
44
    if (!entry) {
252
30
      return false;
253
30
    }
254
255
28
    CEL_ASSIGN_OR_RETURN(auto lhs_value, lhs.Get(lhs_key, descriptor_pool,
256
28
                                                 message_factory, arena));
257
28
    CEL_ASSIGN_OR_RETURN(absl::optional<bool> eq,
258
14
                         EqualsProvider()(lhs_value, *entry, descriptor_pool,
259
14
                                          message_factory, arena));
260
261
14
    if (!eq.has_value() || !*eq) {
262
9
      return eq;
263
9
    }
264
14
  }
265
266
6
  return true;
267
90
}
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::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_20260107::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
50
    google::protobuf::Arena* absl_nonnull arena) {
229
50
  if (&lhs == &rhs) {
230
0
    return true;
231
0
  }
232
50
  if (lhs.Size() != rhs.Size()) {
233
5
    return false;
234
5
  }
235
236
90
  CEL_ASSIGN_OR_RETURN(auto iter, lhs.NewIterator());
237
238
90
  while (iter->HasNext()) {
239
44
    CEL_ASSIGN_OR_RETURN(auto lhs_key,
240
44
                         iter->Next(descriptor_pool, message_factory, arena));
241
242
44
    absl::optional<Value> entry;
243
44
    CEL_ASSIGN_OR_RETURN(
244
44
        entry, rhs.Find(lhs_key, descriptor_pool, message_factory, arena));
245
246
44
    if (!entry && EqualsProvider::kIsHeterogeneous) {
247
30
      CEL_ASSIGN_OR_RETURN(
248
30
          entry, CheckAlternativeNumericType(lhs_key, rhs, descriptor_pool,
249
30
                                             message_factory, arena));
250
30
    }
251
44
    if (!entry) {
252
30
      return false;
253
30
    }
254
255
28
    CEL_ASSIGN_OR_RETURN(auto lhs_value, lhs.Get(lhs_key, descriptor_pool,
256
28
                                                 message_factory, arena));
257
28
    CEL_ASSIGN_OR_RETURN(absl::optional<bool> eq,
258
14
                         EqualsProvider()(lhs_value, *entry, descriptor_pool,
259
14
                                          message_factory, arena));
260
261
14
    if (!eq.has_value() || !*eq) {
262
9
      return eq;
263
9
    }
264
14
  }
265
266
6
  return true;
267
90
}
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(
288
0
        cel::runtime_internal::CreateNoMatchingOverloadError(name));
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_20260107::Duration, std::__1::optional<bool> (*)(absl::lts_20260107::Duration, absl::lts_20260107::Duration)>(std::__1::optional<bool> (*)(absl::lts_20260107::Duration, absl::lts_20260107::Duration), std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(absl::lts_20260107::Duration, absl::lts_20260107::Duration, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(absl::lts_20260107::Duration, absl::lts_20260107::Duration, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*) const
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::WrapComparison<absl::lts_20260107::Time, std::__1::optional<bool> (*)(absl::lts_20260107::Time, absl::lts_20260107::Time)>(std::__1::optional<bool> (*)(absl::lts_20260107::Time, absl::lts_20260107::Time), std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(absl::lts_20260107::Time, absl::lts_20260107::Time, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)#1}::operator()(absl::lts_20260107::Time, absl::lts_20260107::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_20260107::Duration, absl::lts_20260107::Duration, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)> cel::(anonymous namespace)::WrapComparison<absl::lts_20260107::Duration, std::__1::optional<bool> (*)(absl::lts_20260107::Duration, absl::lts_20260107::Duration)>(std::__1::optional<bool> (*)(absl::lts_20260107::Duration, absl::lts_20260107::Duration), std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Unexecuted instantiation: equality_functions.cc:std::__1::function<cel::Value (absl::lts_20260107::Time, absl::lts_20260107::Time, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)> cel::(anonymous namespace)::WrapComparison<absl::lts_20260107::Time, std::__1::optional<bool> (*)(absl::lts_20260107::Time, absl::lts_20260107::Time)>(std::__1::optional<bool> (*)(absl::lts_20260107::Time, absl::lts_20260107::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_20260107::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<bool>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<long>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<unsigned long>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<double>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<cel::StringValue const&>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<cel::BytesValue const&>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<absl::lts_20260107::Duration>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<absl::lts_20260107::Time>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::Status cel::(anonymous namespace)::RegisterEqualityFunctionsForType<cel::NullValue const&>(cel::FunctionRegistry&)
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::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(
321
0
          cel::runtime_internal::CreateNoMatchingOverloadError(kEqual));
322
0
    }
323
0
    return BoolValue(*result);
324
0
  };
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::ComplexEquality<cel::ListValue const&, absl::lts_20260107::FunctionRef<absl::lts_20260107::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260107::FunctionRef<absl::lts_20260107::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_20260107::FunctionRef<absl::lts_20260107::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260107::FunctionRef<absl::lts_20260107::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_20260107::FunctionRef<absl::lts_20260107::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260107::FunctionRef<absl::lts_20260107::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_20260107::FunctionRef<absl::lts_20260107::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260107::FunctionRef<absl::lts_20260107::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(
338
0
          cel::runtime_internal::CreateNoMatchingOverloadError(kInequal));
339
0
    }
340
0
    return BoolValue(!*result);
341
0
  };
Unexecuted instantiation: equality_functions.cc:cel::(anonymous namespace)::ComplexInequality<cel::ListValue const&, absl::lts_20260107::FunctionRef<absl::lts_20260107::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260107::FunctionRef<absl::lts_20260107::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_20260107::FunctionRef<absl::lts_20260107::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260107::FunctionRef<absl::lts_20260107::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
342
0
}
Unexecuted instantiation: equality_functions.cc:auto cel::(anonymous namespace)::ComplexInequality<cel::ListValue const&, absl::lts_20260107::FunctionRef<absl::lts_20260107::StatusOr<std::__1::optional<bool> > (cel::ListValue const&, cel::ListValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260107::FunctionRef<absl::lts_20260107::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_20260107::FunctionRef<absl::lts_20260107::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&>(absl::lts_20260107::FunctionRef<absl::lts_20260107::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>&)
343
344
template <class Type>
345
absl::Status RegisterComplexEqualityFunctionsForType(
346
    absl::FunctionRef<absl::StatusOr<absl::optional<bool>>(
347
        Type, Type, const google::protobuf::DescriptorPool* absl_nonnull,
348
        google::protobuf::MessageFactory* absl_nonnull, google::protobuf::Arena* absl_nonnull)>
349
        op,
350
0
    cel::FunctionRegistry& registry) {
351
0
  using FunctionAdapter = cel::RegisterHelper<
352
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, Type, Type>>;
353
  // Inequality
354
0
  CEL_RETURN_IF_ERROR(FunctionAdapter::RegisterGlobalOverload(
355
0
      kInequal, ComplexInequality<Type>(op), registry));
356
357
  // Equality
358
0
  CEL_RETURN_IF_ERROR(FunctionAdapter::RegisterGlobalOverload(
359
0
      kEqual, ComplexEquality<Type>(op), registry));
360
361
0
  return absl::OkStatus();
362
0
}
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::Status cel::(anonymous namespace)::RegisterComplexEqualityFunctionsForType<cel::ListValue const&>(absl::lts_20260107::FunctionRef<absl::lts_20260107::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_20260107::Status cel::(anonymous namespace)::RegisterComplexEqualityFunctionsForType<cel::MapValue const&>(absl::lts_20260107::FunctionRef<absl::lts_20260107::StatusOr<std::__1::optional<bool> > (cel::MapValue const&, cel::MapValue const&, google::protobuf::DescriptorPool const*, google::protobuf::MessageFactory*, google::protobuf::Arena*)>, cel::FunctionRegistry&)
363
364
absl::Status RegisterHomogenousEqualityFunctions(
365
0
    cel::FunctionRegistry& registry) {
366
0
  CEL_RETURN_IF_ERROR(RegisterEqualityFunctionsForType<bool>(registry));
367
368
0
  CEL_RETURN_IF_ERROR(RegisterEqualityFunctionsForType<int64_t>(registry));
369
370
0
  CEL_RETURN_IF_ERROR(RegisterEqualityFunctionsForType<uint64_t>(registry));
371
372
0
  CEL_RETURN_IF_ERROR(RegisterEqualityFunctionsForType<double>(registry));
373
374
0
  CEL_RETURN_IF_ERROR(
375
0
      RegisterEqualityFunctionsForType<const cel::StringValue&>(registry));
376
377
0
  CEL_RETURN_IF_ERROR(
378
0
      RegisterEqualityFunctionsForType<const cel::BytesValue&>(registry));
379
380
0
  CEL_RETURN_IF_ERROR(
381
0
      RegisterEqualityFunctionsForType<absl::Duration>(registry));
382
383
0
  CEL_RETURN_IF_ERROR(RegisterEqualityFunctionsForType<absl::Time>(registry));
384
385
0
  CEL_RETURN_IF_ERROR(
386
0
      RegisterEqualityFunctionsForType<const cel::NullValue&>(registry));
387
388
0
  CEL_RETURN_IF_ERROR(
389
0
      RegisterEqualityFunctionsForType<const cel::TypeValue&>(registry));
390
391
0
  CEL_RETURN_IF_ERROR(
392
0
      RegisterComplexEqualityFunctionsForType<const cel::ListValue&>(
393
0
          &ListEqual<HomogenousEqualProvider>, registry));
394
395
0
  CEL_RETURN_IF_ERROR(
396
0
      RegisterComplexEqualityFunctionsForType<const cel::MapValue&>(
397
0
          &MapEqual<HomogenousEqualProvider>, registry));
398
399
0
  return absl::OkStatus();
400
0
}
401
402
0
absl::Status RegisterNullMessageEqualityFunctions(FunctionRegistry& registry) {
403
  // equals
404
0
  CEL_RETURN_IF_ERROR(
405
0
      (cel::RegisterHelper<
406
0
          BinaryFunctionAdapter<bool, const StructValue&, const NullValue&>>::
407
0
           RegisterGlobalOverload(
408
0
               kEqual,
409
0
               [](const StructValue&, const NullValue&) { return false; },
410
0
               registry)));
411
412
0
  CEL_RETURN_IF_ERROR(
413
0
      (cel::RegisterHelper<
414
0
          BinaryFunctionAdapter<bool, const NullValue&, const StructValue&>>::
415
0
           RegisterGlobalOverload(
416
0
               kEqual,
417
0
               [](const NullValue&, const StructValue&) { return false; },
418
0
               registry)));
419
420
  // inequals
421
0
  CEL_RETURN_IF_ERROR(
422
0
      (cel::RegisterHelper<
423
0
          BinaryFunctionAdapter<bool, const StructValue&, const NullValue&>>::
424
0
           RegisterGlobalOverload(
425
0
               kInequal,
426
0
               [](const StructValue&, const NullValue&) { return true; },
427
0
               registry)));
428
429
0
  return cel::RegisterHelper<
430
0
      BinaryFunctionAdapter<bool, const NullValue&, const StructValue&>>::
431
0
      RegisterGlobalOverload(
432
0
          kInequal, [](const NullValue&, const StructValue&) { return true; },
433
0
          registry);
434
0
}
435
436
template <typename EqualsProvider>
437
absl::StatusOr<absl::optional<bool>> HomogenousValueEqual(
438
    const Value& v1, const Value& v2,
439
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
440
    google::protobuf::MessageFactory* absl_nonnull message_factory,
441
799
    google::protobuf::Arena* absl_nonnull arena) {
442
799
  if (v1.kind() != v2.kind()) {
443
0
    return absl::nullopt;
444
0
  }
445
446
799
  static_assert(std::is_lvalue_reference_v<decltype(v1.GetString())>,
447
799
                "unexpected value copy");
448
449
799
  switch (v1->kind()) {
450
9
    case ValueKind::kBool:
451
9
      return Equal<bool>(v1.GetBool().NativeValue(),
452
9
                         v2.GetBool().NativeValue());
453
0
    case ValueKind::kNull:
454
0
      return Equal<const NullValue&>(v1.GetNull(), v2.GetNull());
455
309
    case ValueKind::kInt:
456
309
      return Equal<int64_t>(v1.GetInt().NativeValue(),
457
309
                            v2.GetInt().NativeValue());
458
180
    case ValueKind::kUint:
459
180
      return Equal<uint64_t>(v1.GetUint().NativeValue(),
460
180
                             v2.GetUint().NativeValue());
461
34
    case ValueKind::kDouble:
462
34
      return Equal<double>(v1.GetDouble().NativeValue(),
463
34
                           v2.GetDouble().NativeValue());
464
0
    case ValueKind::kDuration:
465
0
      return Equal<absl::Duration>(v1.GetDuration().NativeValue(),
466
0
                                   v2.GetDuration().NativeValue());
467
0
    case ValueKind::kTimestamp:
468
0
      return Equal<absl::Time>(v1.GetTimestamp().NativeValue(),
469
0
                               v2.GetTimestamp().NativeValue());
470
2
    case ValueKind::kCelType:
471
2
      return Equal<const TypeValue&>(v1.GetType(), v2.GetType());
472
113
    case ValueKind::kString:
473
113
      return Equal<const StringValue&>(v1.GetString(), v2.GetString());
474
18
    case ValueKind::kBytes:
475
18
      return Equal<const cel::BytesValue&>(v1.GetBytes(), v2.GetBytes());
476
84
    case ValueKind::kList:
477
84
      return ListEqual<EqualsProvider>(v1.GetList(), v2.GetList(),
478
84
                                       descriptor_pool, message_factory, arena);
479
50
    case ValueKind::kMap:
480
50
      return MapEqual<EqualsProvider>(v1.GetMap(), v2.GetMap(), descriptor_pool,
481
50
                                      message_factory, arena);
482
0
    case ValueKind::kOpaque:
483
0
      return OpaqueEqual(v1.GetOpaque(), v2.GetOpaque(), descriptor_pool,
484
0
                         message_factory, arena);
485
0
    default:
486
0
      return absl::nullopt;
487
799
  }
488
799
}
Unexecuted instantiation: equality_functions.cc:absl::lts_20260107::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_20260107::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
441
799
    google::protobuf::Arena* absl_nonnull arena) {
442
799
  if (v1.kind() != v2.kind()) {
443
0
    return absl::nullopt;
444
0
  }
445
446
799
  static_assert(std::is_lvalue_reference_v<decltype(v1.GetString())>,
447
799
                "unexpected value copy");
448
449
799
  switch (v1->kind()) {
450
9
    case ValueKind::kBool:
451
9
      return Equal<bool>(v1.GetBool().NativeValue(),
452
9
                         v2.GetBool().NativeValue());
453
0
    case ValueKind::kNull:
454
0
      return Equal<const NullValue&>(v1.GetNull(), v2.GetNull());
455
309
    case ValueKind::kInt:
456
309
      return Equal<int64_t>(v1.GetInt().NativeValue(),
457
309
                            v2.GetInt().NativeValue());
458
180
    case ValueKind::kUint:
459
180
      return Equal<uint64_t>(v1.GetUint().NativeValue(),
460
180
                             v2.GetUint().NativeValue());
461
34
    case ValueKind::kDouble:
462
34
      return Equal<double>(v1.GetDouble().NativeValue(),
463
34
                           v2.GetDouble().NativeValue());
464
0
    case ValueKind::kDuration:
465
0
      return Equal<absl::Duration>(v1.GetDuration().NativeValue(),
466
0
                                   v2.GetDuration().NativeValue());
467
0
    case ValueKind::kTimestamp:
468
0
      return Equal<absl::Time>(v1.GetTimestamp().NativeValue(),
469
0
                               v2.GetTimestamp().NativeValue());
470
2
    case ValueKind::kCelType:
471
2
      return Equal<const TypeValue&>(v1.GetType(), v2.GetType());
472
113
    case ValueKind::kString:
473
113
      return Equal<const StringValue&>(v1.GetString(), v2.GetString());
474
18
    case ValueKind::kBytes:
475
18
      return Equal<const cel::BytesValue&>(v1.GetBytes(), v2.GetBytes());
476
84
    case ValueKind::kList:
477
84
      return ListEqual<EqualsProvider>(v1.GetList(), v2.GetList(),
478
84
                                       descriptor_pool, message_factory, arena);
479
50
    case ValueKind::kMap:
480
50
      return MapEqual<EqualsProvider>(v1.GetMap(), v2.GetMap(), descriptor_pool,
481
50
                                      message_factory, arena);
482
0
    case ValueKind::kOpaque:
483
0
      return OpaqueEqual(v1.GetOpaque(), v2.GetOpaque(), descriptor_pool,
484
0
                         message_factory, arena);
485
0
    default:
486
0
      return absl::nullopt;
487
799
  }
488
799
}
489
490
absl::StatusOr<Value> EqualOverloadImpl(
491
    const Value& lhs, const Value& rhs,
492
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
493
    google::protobuf::MessageFactory* absl_nonnull message_factory,
494
0
    google::protobuf::Arena* absl_nonnull arena) {
495
0
  CEL_ASSIGN_OR_RETURN(absl::optional<bool> result,
496
0
                       runtime_internal::ValueEqualImpl(
497
0
                           lhs, rhs, descriptor_pool, message_factory, arena));
498
0
  if (result.has_value()) {
499
0
    return BoolValue(*result);
500
0
  }
501
0
  return ErrorValue(
502
0
      cel::runtime_internal::CreateNoMatchingOverloadError(kEqual));
503
0
}
504
505
absl::StatusOr<Value> InequalOverloadImpl(
506
    const Value& lhs, const Value& rhs,
507
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
508
    google::protobuf::MessageFactory* absl_nonnull message_factory,
509
0
    google::protobuf::Arena* absl_nonnull arena) {
510
0
  CEL_ASSIGN_OR_RETURN(absl::optional<bool> result,
511
0
                       runtime_internal::ValueEqualImpl(
512
0
                           lhs, rhs, descriptor_pool, message_factory, arena));
513
0
  if (result.has_value()) {
514
0
    return BoolValue(!*result);
515
0
  }
516
0
  return ErrorValue(
517
0
      cel::runtime_internal::CreateNoMatchingOverloadError(kInequal));
518
0
}
519
520
absl::Status RegisterHeterogeneousEqualityFunctions(
521
0
    cel::FunctionRegistry& registry) {
522
0
  using Adapter = cel::RegisterHelper<
523
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, const Value&, const Value&>>;
524
0
  CEL_RETURN_IF_ERROR(
525
0
      Adapter::RegisterGlobalOverload(kEqual, &EqualOverloadImpl, registry));
526
527
0
  CEL_RETURN_IF_ERROR(Adapter::RegisterGlobalOverload(
528
0
      kInequal, &InequalOverloadImpl, registry));
529
530
0
  return absl::OkStatus();
531
0
}
532
533
absl::StatusOr<absl::optional<bool>> HomogenousEqualProvider::operator()(
534
    const Value& lhs, const Value& rhs,
535
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
536
    google::protobuf::MessageFactory* absl_nonnull message_factory,
537
0
    google::protobuf::Arena* absl_nonnull arena) const {
538
0
  return HomogenousValueEqual<HomogenousEqualProvider>(
539
0
      lhs, rhs, descriptor_pool, message_factory, arena);
540
0
}
541
542
absl::StatusOr<absl::optional<bool>> HeterogeneousEqualProvider::operator()(
543
    const Value& lhs, const Value& rhs,
544
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
545
    google::protobuf::MessageFactory* absl_nonnull message_factory,
546
34
    google::protobuf::Arena* absl_nonnull arena) const {
547
34
  return runtime_internal::ValueEqualImpl(lhs, rhs, descriptor_pool,
548
34
                                          message_factory, arena);
549
34
}
550
551
}  // namespace
552
553
namespace runtime_internal {
554
555
absl::StatusOr<absl::optional<bool>> ValueEqualImpl(
556
    const Value& v1, const Value& v2,
557
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
558
    google::protobuf::MessageFactory* absl_nonnull message_factory,
559
3.85k
    google::protobuf::Arena* absl_nonnull arena) {
560
3.85k
  if (v1.kind() == v2.kind()) {
561
799
    if (v1.IsStruct() && v2.IsStruct()) {
562
0
      CEL_ASSIGN_OR_RETURN(
563
0
          Value result,
564
0
          v1.GetStruct().Equal(v2, descriptor_pool, message_factory, arena));
565
0
      if (result.IsBool()) {
566
0
        return result.GetBool().NativeValue();
567
0
      }
568
0
      return false;
569
0
    }
570
799
    return HomogenousValueEqual<HeterogeneousEqualProvider>(
571
799
        v1, v2, descriptor_pool, message_factory, arena);
572
799
  }
573
574
3.05k
  absl::optional<Number> lhs = NumberFromValue(v1);
575
3.05k
  absl::optional<Number> rhs = NumberFromValue(v2);
576
577
3.05k
  if (rhs.has_value() && lhs.has_value()) {
578
1.76k
    return *lhs == *rhs;
579
1.76k
  }
580
581
  // TODO(uncreated-issue/6): It's currently possible for the interpreter to create a
582
  // map containing an Error. Return no matching overload to propagate an error
583
  // instead of a false result.
584
1.29k
  if (v1.IsError() || v1.IsUnknown() || v2.IsError() || v2.IsUnknown()) {
585
0
    return absl::nullopt;
586
0
  }
587
588
1.29k
  return false;
589
1.29k
}
590
591
}  // namespace runtime_internal
592
593
absl::Status RegisterEqualityFunctions(FunctionRegistry& registry,
594
14.5k
                                       const RuntimeOptions& options) {
595
14.5k
  if (options.enable_heterogeneous_equality) {
596
14.5k
    if (options.enable_fast_builtins) {
597
      // If enabled, the evaluator provides an implementation that works
598
      // directly on the value stack.
599
14.5k
      return absl::OkStatus();
600
14.5k
    }
601
    // Heterogeneous equality uses one generic overload that delegates to the
602
    // right equality implementation at runtime.
603
14.5k
    CEL_RETURN_IF_ERROR(RegisterHeterogeneousEqualityFunctions(registry));
604
0
  } else {
605
0
    CEL_RETURN_IF_ERROR(RegisterHomogenousEqualityFunctions(registry));
606
607
0
    CEL_RETURN_IF_ERROR(RegisterNullMessageEqualityFunctions(registry));
608
0
  }
609
0
  return absl::OkStatus();
610
14.5k
}
611
612
}  // namespace cel