Coverage Report

Created: 2026-05-27 07:00

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