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