/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 |