Coverage Report

Created: 2026-10-09 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/eval/public/cel_value.cc
Line
Count
Source
1
#include "eval/public/cel_value.h"
2
3
#include <cstdint>
4
#include <string>
5
#include <utility>
6
#include <vector>
7
8
#include "absl/base/attributes.h"
9
#include "absl/base/no_destructor.h"
10
#include "absl/status/status.h"
11
#include "absl/strings/match.h"
12
#include "absl/strings/str_cat.h"
13
#include "absl/strings/str_format.h"
14
#include "absl/strings/str_join.h"
15
#include "absl/strings/string_view.h"
16
#include "absl/types/optional.h"
17
#include "eval/internal/errors.h"
18
#include "eval/public/structs/legacy_type_info_apis.h"
19
#include "google/protobuf/arena.h"
20
21
namespace google::api::expr::runtime {
22
23
namespace {
24
25
using ::google::protobuf::Arena;
26
namespace interop = ::cel::interop_internal;
27
28
constexpr absl::string_view kNullTypeName = "null_type";
29
constexpr absl::string_view kBoolTypeName = "bool";
30
constexpr absl::string_view kInt64TypeName = "int";
31
constexpr absl::string_view kUInt64TypeName = "uint";
32
constexpr absl::string_view kDoubleTypeName = "double";
33
constexpr absl::string_view kStringTypeName = "string";
34
constexpr absl::string_view kBytesTypeName = "bytes";
35
constexpr absl::string_view kDurationTypeName = "google.protobuf.Duration";
36
constexpr absl::string_view kTimestampTypeName = "google.protobuf.Timestamp";
37
// Leading "." to prevent potential namespace clash.
38
constexpr absl::string_view kListTypeName = "list";
39
constexpr absl::string_view kMapTypeName = "map";
40
constexpr absl::string_view kCelTypeTypeName = "type";
41
42
struct DebugStringVisitor {
43
  google::protobuf::Arena* const arena;
44
45
0
  std::string operator()(bool arg) { return absl::StrFormat("%d", arg); }
46
0
  std::string operator()(int64_t arg) { return absl::StrFormat("%lld", arg); }
47
0
  std::string operator()(uint64_t arg) { return absl::StrFormat("%llu", arg); }
48
0
  std::string operator()(double arg) { return absl::StrFormat("%f", arg); }
49
0
  std::string operator()(CelValue::NullType) { return "null"; }
50
51
0
  std::string operator()(CelValue::StringHolder arg) {
52
0
    return absl::StrFormat("%s", arg.value());
53
0
  }
54
55
0
  std::string operator()(CelValue::BytesHolder arg) {
56
0
    return absl::StrFormat("%s", arg.value());
57
0
  }
58
59
0
  std::string operator()(const MessageWrapper& arg) {
60
0
    return arg.message_ptr() == nullptr
61
0
               ? "NULL"
62
0
               : arg.legacy_type_info()->DebugString(arg);
63
0
  }
64
65
0
  std::string operator()(absl::Duration arg) {
66
0
    return absl::FormatDuration(arg);
67
0
  }
68
69
0
  std::string operator()(absl::Time arg) {
70
0
    return absl::FormatTime(arg, absl::UTCTimeZone());
71
0
  }
72
73
0
  std::string operator()(const CelList* arg) {
74
0
    std::vector<std::string> elements;
75
0
    elements.reserve(arg->size());
76
0
    for (int i = 0; i < arg->size(); i++) {
77
0
      elements.push_back(arg->Get(arena, i).DebugString());
78
0
    }
79
0
    return absl::StrCat("[", absl::StrJoin(elements, ", "), "]");
80
0
  }
81
82
0
  std::string operator()(const CelMap* arg) {
83
0
    auto keys_or_error = arg->ListKeys(arena);
84
0
    if (!keys_or_error.status().ok()) {
85
0
      return "invalid list keys";
86
0
    }
87
0
    const CelList* keys = std::move(keys_or_error.value());
88
0
    std::vector<std::string> elements;
89
0
    elements.reserve(keys->size());
90
0
    for (int i = 0; i < keys->size(); i++) {
91
0
      const auto& key = (*keys).Get(arena, i);
92
0
      const auto& optional_value = arg->Get(arena, key);
93
0
      elements.push_back(absl::StrCat("<", key.DebugString(), ">: <",
94
0
                                      optional_value.has_value()
95
0
                                          ? optional_value->DebugString()
96
0
                                          : "nullopt",
97
0
                                      ">"));
98
0
    }
99
0
    return absl::StrCat("{", absl::StrJoin(elements, ", "), "}");
100
0
  }
101
102
0
  std::string operator()(const UnknownSet* arg) {
103
0
    return "?";  // Not implemented.
104
0
  }
105
106
0
  std::string operator()(CelValue::CelTypeHolder arg) {
107
0
    return absl::StrCat(arg.value());
108
0
  }
109
110
0
  std::string operator()(const CelError* arg) { return arg->ToString(); }
111
};
112
113
}  // namespace
114
115
ABSL_CONST_INIT const absl::string_view kPayloadUrlMissingAttributePath =
116
    cel::runtime_internal::kPayloadUrlMissingAttributePath;
117
118
0
CelValue CelValue::CreateDuration(absl::Duration value) {
119
0
  if (value >= cel::runtime_internal::kDurationHigh ||
120
0
      value <= cel::runtime_internal::kDurationLow) {
121
0
    return CelValue(cel::runtime_internal::DurationOverflowError());
122
0
  }
123
0
  return CreateUncheckedDuration(value);
124
0
}
125
126
// TODO(issues/136): These don't match the CEL runtime typenames. They should
127
// be updated where possible for consistency.
128
0
std::string CelValue::TypeName(Type value_type) {
129
0
  switch (value_type) {
130
0
    case Type::kNullType:
131
0
      return "null_type";
132
0
    case Type::kBool:
133
0
      return "bool";
134
0
    case Type::kInt64:
135
0
      return "int64";
136
0
    case Type::kUint64:
137
0
      return "uint64";
138
0
    case Type::kDouble:
139
0
      return "double";
140
0
    case Type::kString:
141
0
      return "string";
142
0
    case Type::kBytes:
143
0
      return "bytes";
144
0
    case Type::kMessage:
145
0
      return "Message";
146
0
    case Type::kDuration:
147
0
      return "Duration";
148
0
    case Type::kTimestamp:
149
0
      return "Timestamp";
150
0
    case Type::kList:
151
0
      return "CelList";
152
0
    case Type::kMap:
153
0
      return "CelMap";
154
0
    case Type::kCelType:
155
0
      return "CelType";
156
0
    case Type::kUnknownSet:
157
0
      return "UnknownSet";
158
0
    case Type::kError:
159
0
      return "CelError";
160
0
    case Type::kAny:
161
0
      return "Any type";
162
0
    default:
163
0
      return "unknown";
164
0
  }
165
0
}
166
167
0
absl::Status CelValue::CheckMapKeyType(const CelValue& key) {
168
0
  switch (key.type()) {
169
0
    case CelValue::Type::kString:
170
0
    case CelValue::Type::kInt64:
171
0
    case CelValue::Type::kUint64:
172
0
    case CelValue::Type::kBool:
173
0
      return absl::OkStatus();
174
0
    default:
175
0
      return absl::InvalidArgumentError(absl::StrCat(
176
0
          "Invalid map key type: '", CelValue::TypeName(key.type()), "'"));
177
0
  }
178
0
}
179
180
0
CelValue CelValue::ObtainCelType() const {
181
0
  switch (type()) {
182
0
    case Type::kNullType:
183
0
      return CreateCelType(CelTypeHolder(kNullTypeName));
184
0
    case Type::kBool:
185
0
      return CreateCelType(CelTypeHolder(kBoolTypeName));
186
0
    case Type::kInt64:
187
0
      return CreateCelType(CelTypeHolder(kInt64TypeName));
188
0
    case Type::kUint64:
189
0
      return CreateCelType(CelTypeHolder(kUInt64TypeName));
190
0
    case Type::kDouble:
191
0
      return CreateCelType(CelTypeHolder(kDoubleTypeName));
192
0
    case Type::kString:
193
0
      return CreateCelType(CelTypeHolder(kStringTypeName));
194
0
    case Type::kBytes:
195
0
      return CreateCelType(CelTypeHolder(kBytesTypeName));
196
0
    case Type::kMessage: {
197
0
      MessageWrapper wrapper;
198
0
      CelValue::GetValue(&wrapper);
199
0
      if (wrapper.message_ptr() == nullptr) {
200
0
        return CreateCelType(CelTypeHolder(kNullTypeName));
201
0
      }
202
      // Descritptor::full_name() returns const reference, so using pointer
203
      // should be safe.
204
0
      return CreateCelType(
205
0
          CelTypeHolder(wrapper.legacy_type_info()->GetTypename(wrapper)));
206
0
    }
207
0
    case Type::kDuration:
208
0
      return CreateCelType(CelTypeHolder(kDurationTypeName));
209
0
    case Type::kTimestamp:
210
0
      return CreateCelType(CelTypeHolder(kTimestampTypeName));
211
0
    case Type::kList:
212
0
      return CreateCelType(CelTypeHolder(kListTypeName));
213
0
    case Type::kMap:
214
0
      return CreateCelType(CelTypeHolder(kMapTypeName));
215
0
    case Type::kCelType:
216
0
      return CreateCelType(CelTypeHolder(kCelTypeTypeName));
217
0
    case Type::kUnknownSet:
218
0
      return *this;
219
0
    case Type::kError:
220
0
      return *this;
221
0
    default: {
222
0
      static const CelError* invalid_type_error =
223
0
          new CelError(absl::InvalidArgumentError("Unsupported CelValue type"));
224
0
      return CreateError(invalid_type_error);
225
0
    }
226
0
  }
227
0
}
228
229
// Returns debug string describing a value
230
0
const std::string CelValue::DebugString() const {
231
0
  google::protobuf::Arena arena;
232
0
  return absl::StrCat(CelValue::TypeName(type()), ": ",
233
0
                      InternalVisit<std::string>(DebugStringVisitor{&arena}));
234
0
}
235
236
namespace {
237
238
class EmptyCelList final : public CelList {
239
 public:
240
0
  static const EmptyCelList* Get() {
241
0
    static const absl::NoDestructor<EmptyCelList> instance;
242
0
    return &*instance;
243
0
  }
244
245
0
  CelValue operator[](int index) const override {
246
0
    static const CelError* invalid_argument =
247
0
        new CelError(absl::InvalidArgumentError("index out of bounds"));
248
0
    return CelValue::CreateError(invalid_argument);
249
0
  }
250
251
0
  int size() const override { return 0; }
252
253
0
  bool empty() const override { return true; }
254
};
255
256
class EmptyCelMap final : public CelMap {
257
 public:
258
0
  static const EmptyCelMap* Get() {
259
0
    static const absl::NoDestructor<EmptyCelMap> instance;
260
0
    return &*instance;
261
0
  }
262
263
0
  absl::optional<CelValue> operator[](CelValue key) const override {
264
0
    return std::nullopt;
265
0
  }
266
267
0
  absl::StatusOr<bool> Has(const CelValue& key) const override {
268
0
    CEL_RETURN_IF_ERROR(CelValue::CheckMapKeyType(key));
269
0
    return false;
270
0
  }
271
272
0
  int size() const override { return 0; }
273
274
0
  bool empty() const override { return true; }
275
276
0
  absl::StatusOr<const CelList*> ListKeys() const override {
277
0
    return EmptyCelList::Get();
278
0
  }
279
};
280
281
}  // namespace
282
283
0
CelValue CelValue::CreateList() { return CreateList(EmptyCelList::Get()); }
284
285
0
CelValue CelValue::CreateMap() { return CreateMap(EmptyCelMap::Get()); }
286
287
CelValue CreateErrorValue(Arena* arena, absl::string_view message,
288
0
                          absl::StatusCode error_code) {
289
0
  CelError* error = Arena::Create<CelError>(arena, error_code, message);
290
0
  return CelValue::CreateError(error);
291
0
}
292
293
0
CelValue CreateErrorValue(Arena* arena, const absl::Status& status) {
294
0
  CelError* error = Arena::Create<CelError>(arena, status);
295
0
  return CelValue::CreateError(error);
296
0
}
297
298
CelValue CreateNoMatchingOverloadError(google::protobuf::Arena* arena,
299
0
                                       absl::string_view fn) {
300
0
  return CelValue::CreateError(
301
0
      interop::CreateNoMatchingOverloadError(arena, fn));
302
0
}
303
304
0
bool CheckNoMatchingOverloadError(CelValue value) {
305
0
  return value.IsError() &&
306
0
         value.ErrorOrDie()->code() == absl::StatusCode::kUnknown &&
307
0
         absl::StrContains(value.ErrorOrDie()->message(),
308
0
                           cel::runtime_internal::kErrNoMatchingOverload);
309
0
}
310
311
0
CelValue CreateNoSuchFieldError(google::protobuf::Arena* arena, absl::string_view field) {
312
0
  return CelValue::CreateError(interop::CreateNoSuchFieldError(arena, field));
313
0
}
314
315
0
CelValue CreateNoSuchKeyError(google::protobuf::Arena* arena, absl::string_view key) {
316
0
  return CelValue::CreateError(interop::CreateNoSuchKeyError(arena, key));
317
0
}
318
319
0
bool CheckNoSuchKeyError(CelValue value) {
320
0
  return value.IsError() &&
321
0
         absl::StartsWith(value.ErrorOrDie()->message(),
322
0
                          cel::runtime_internal::kErrNoSuchKey);
323
0
}
324
325
CelValue CreateMissingAttributeError(google::protobuf::Arena* arena,
326
0
                                     absl::string_view missing_attribute_path) {
327
0
  return CelValue::CreateError(
328
0
      interop::CreateMissingAttributeError(arena, missing_attribute_path));
329
0
}
330
331
0
bool IsMissingAttributeError(const CelValue& value) {
332
0
  const CelError* error;
333
0
  if (!value.GetValue(&error)) return false;
334
0
  if (error && error->code() == absl::StatusCode::kInvalidArgument) {
335
0
    auto path = error->GetPayload(
336
0
        cel::runtime_internal::kPayloadUrlMissingAttributePath);
337
0
    return path.has_value();
338
0
  }
339
0
  return false;
340
0
}
341
342
CelValue CreateUnknownFunctionResultError(google::protobuf::Arena* arena,
343
0
                                          absl::string_view help_message) {
344
0
  return CelValue::CreateError(
345
0
      interop::CreateUnknownFunctionResultError(arena, help_message));
346
0
}
347
348
0
bool IsUnknownFunctionResult(const CelValue& value) {
349
0
  const CelError* error;
350
0
  if (!value.GetValue(&error)) return false;
351
352
0
  if (error == nullptr || error->code() != absl::StatusCode::kUnavailable) {
353
0
    return false;
354
0
  }
355
0
  auto payload = error->GetPayload(
356
0
      cel::runtime_internal::kPayloadUrlUnknownFunctionResult);
357
0
  return payload.has_value() && payload.value() == "true";
358
0
}
359
360
}  // namespace google::api::expr::runtime