|
26 | 26 | #include "absl/strings/str_cat.h" |
27 | 27 | #include "absl/strings/string_view.h" |
28 | 28 | #include "common/casting.h" |
29 | | -#include "common/memory.h" |
| 29 | +#include "common/native_type.h" |
30 | 30 | #include "common/value.h" |
31 | 31 | #include "common/values/list_value_builder.h" |
32 | 32 | #include "common/values/values.h" |
@@ -90,8 +90,8 @@ class EmptyListValue final : public common_internal::CompatListValue { |
90 | 90 | return absl::OkStatus(); |
91 | 91 | } |
92 | 92 |
|
93 | | - CustomListValue Clone(absl::Nonnull<google::protobuf::Arena*>) const override { |
94 | | - return CustomListValue(); |
| 93 | + CustomListValue Clone(absl::Nonnull<google::protobuf::Arena*> arena) const override { |
| 94 | + return CustomListValue(&EmptyListValue::Get(), arena); |
95 | 95 | } |
96 | 96 |
|
97 | 97 | int size() const override { return 0; } |
@@ -159,6 +159,40 @@ class CustomListValueInterfaceIterator final : public ValueIterator { |
159 | 159 | size_t index_ = 0; |
160 | 160 | }; |
161 | 161 |
|
| 162 | +namespace { |
| 163 | + |
| 164 | +class CustomListValueDispatcherIterator final : public ValueIterator { |
| 165 | + public: |
| 166 | + explicit CustomListValueDispatcherIterator( |
| 167 | + absl::Nonnull<const CustomListValueDispatcher*> dispatcher, |
| 168 | + CustomListValueContent content, size_t size) |
| 169 | + : dispatcher_(dispatcher), content_(content), size_(size) {} |
| 170 | + |
| 171 | + bool HasNext() override { return index_ < size_; } |
| 172 | + |
| 173 | + absl::Status Next( |
| 174 | + absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool, |
| 175 | + absl::Nonnull<google::protobuf::MessageFactory*> message_factory, |
| 176 | + absl::Nonnull<google::protobuf::Arena*> arena, |
| 177 | + absl::Nonnull<Value*> result) override { |
| 178 | + if (ABSL_PREDICT_FALSE(index_ >= size_)) { |
| 179 | + return absl::FailedPreconditionError( |
| 180 | + "ValueIterator::Next() called when " |
| 181 | + "ValueIterator::HasNext() returns false"); |
| 182 | + } |
| 183 | + return dispatcher_->get(dispatcher_, content_, index_++, descriptor_pool, |
| 184 | + message_factory, arena, result); |
| 185 | + } |
| 186 | + |
| 187 | + private: |
| 188 | + absl::Nonnull<const CustomListValueDispatcher*> const dispatcher_; |
| 189 | + const CustomListValueContent content_; |
| 190 | + const size_t size_; |
| 191 | + size_t index_ = 0; |
| 192 | +}; |
| 193 | + |
| 194 | +} // namespace |
| 195 | + |
162 | 196 | absl::Status CustomListValueInterface::SerializeTo( |
163 | 197 | absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool, |
164 | 198 | absl::Nonnull<google::protobuf::MessageFactory*> message_factory, |
@@ -257,21 +291,269 @@ absl::Status CustomListValueInterface::Contains( |
257 | 291 | return absl::OkStatus(); |
258 | 292 | } |
259 | 293 |
|
260 | | -CustomListValue::CustomListValue() |
261 | | - : CustomListValue(Owned(Owner::None(), &EmptyListValue::Get())) {} |
| 294 | +CustomListValue::CustomListValue() { |
| 295 | + content_ = CustomListValueContent::From(CustomListValueInterface::Content{ |
| 296 | + .interface = &EmptyListValue::Get(), .arena = nullptr}); |
| 297 | +} |
| 298 | + |
| 299 | +NativeTypeId CustomListValue::GetTypeId() const { |
| 300 | + if (dispatcher_ == nullptr) { |
| 301 | + CustomListValueInterface::Content content = |
| 302 | + content_.To<CustomListValueInterface::Content>(); |
| 303 | + ABSL_DCHECK(content.interface != nullptr); |
| 304 | + return NativeTypeId::Of(*content.interface); |
| 305 | + } |
| 306 | + return dispatcher_->get_type_id(dispatcher_, content_); |
| 307 | +} |
| 308 | + |
| 309 | +absl::string_view CustomListValue::GetTypeName() const { return "list"; } |
| 310 | + |
| 311 | +std::string CustomListValue::DebugString() const { |
| 312 | + if (dispatcher_ == nullptr) { |
| 313 | + CustomListValueInterface::Content content = |
| 314 | + content_.To<CustomListValueInterface::Content>(); |
| 315 | + ABSL_DCHECK(content.interface != nullptr); |
| 316 | + return content.interface->DebugString(); |
| 317 | + } |
| 318 | + if (dispatcher_->debug_string != nullptr) { |
| 319 | + return dispatcher_->debug_string(dispatcher_, content_); |
| 320 | + } |
| 321 | + return "list"; |
| 322 | +} |
| 323 | + |
| 324 | +absl::Status CustomListValue::SerializeTo( |
| 325 | + absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool, |
| 326 | + absl::Nonnull<google::protobuf::MessageFactory*> message_factory, |
| 327 | + absl::Nonnull<absl::Cord*> value) const { |
| 328 | + if (dispatcher_ == nullptr) { |
| 329 | + CustomListValueInterface::Content content = |
| 330 | + content_.To<CustomListValueInterface::Content>(); |
| 331 | + ABSL_DCHECK(content.interface != nullptr); |
| 332 | + return content.interface->SerializeTo(descriptor_pool, message_factory, |
| 333 | + value); |
| 334 | + } |
| 335 | + if (dispatcher_->serialize_to != nullptr) { |
| 336 | + return dispatcher_->serialize_to(dispatcher_, content_, descriptor_pool, |
| 337 | + message_factory, value); |
| 338 | + } |
| 339 | + return absl::UnimplementedError( |
| 340 | + absl::StrCat(GetTypeName(), " is unserializable")); |
| 341 | +} |
| 342 | + |
| 343 | +absl::Status CustomListValue::ConvertToJson( |
| 344 | + absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool, |
| 345 | + absl::Nonnull<google::protobuf::MessageFactory*> message_factory, |
| 346 | + absl::Nonnull<google::protobuf::Message*> json) const { |
| 347 | + ABSL_DCHECK(descriptor_pool != nullptr); |
| 348 | + ABSL_DCHECK(message_factory != nullptr); |
| 349 | + ABSL_DCHECK(json != nullptr); |
| 350 | + ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(), |
| 351 | + google::protobuf::Descriptor::WELLKNOWNTYPE_VALUE); |
| 352 | + |
| 353 | + ValueReflection value_reflection; |
| 354 | + CEL_RETURN_IF_ERROR(value_reflection.Initialize(json->GetDescriptor())); |
| 355 | + google::protobuf::Message* json_array = value_reflection.MutableListValue(json); |
| 356 | + |
| 357 | + return ConvertToJsonArray(descriptor_pool, message_factory, json_array); |
| 358 | +} |
| 359 | + |
| 360 | +absl::Status CustomListValue::ConvertToJsonArray( |
| 361 | + absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool, |
| 362 | + absl::Nonnull<google::protobuf::MessageFactory*> message_factory, |
| 363 | + absl::Nonnull<google::protobuf::Message*> json) const { |
| 364 | + ABSL_DCHECK(descriptor_pool != nullptr); |
| 365 | + ABSL_DCHECK(message_factory != nullptr); |
| 366 | + ABSL_DCHECK(json != nullptr); |
| 367 | + ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(), |
| 368 | + google::protobuf::Descriptor::WELLKNOWNTYPE_LISTVALUE); |
| 369 | + |
| 370 | + if (dispatcher_ == nullptr) { |
| 371 | + CustomListValueInterface::Content content = |
| 372 | + content_.To<CustomListValueInterface::Content>(); |
| 373 | + ABSL_DCHECK(content.interface != nullptr); |
| 374 | + return content.interface->ConvertToJsonArray(descriptor_pool, |
| 375 | + message_factory, json); |
| 376 | + } |
| 377 | + if (dispatcher_->convert_to_json_array != nullptr) { |
| 378 | + return dispatcher_->convert_to_json_array( |
| 379 | + dispatcher_, content_, descriptor_pool, message_factory, json); |
| 380 | + } |
| 381 | + return absl::UnimplementedError( |
| 382 | + absl::StrCat(GetTypeName(), " is not convertable to JSON")); |
| 383 | +} |
| 384 | + |
| 385 | +absl::Status CustomListValue::Equal( |
| 386 | + const Value& other, |
| 387 | + absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool, |
| 388 | + absl::Nonnull<google::protobuf::MessageFactory*> message_factory, |
| 389 | + absl::Nonnull<google::protobuf::Arena*> arena, absl::Nonnull<Value*> result) const { |
| 390 | + ABSL_DCHECK(descriptor_pool != nullptr); |
| 391 | + ABSL_DCHECK(message_factory != nullptr); |
| 392 | + ABSL_DCHECK(arena != nullptr); |
| 393 | + ABSL_DCHECK(result != nullptr); |
| 394 | + |
| 395 | + if (dispatcher_ == nullptr) { |
| 396 | + CustomListValueInterface::Content content = |
| 397 | + content_.To<CustomListValueInterface::Content>(); |
| 398 | + ABSL_DCHECK(content.interface != nullptr); |
| 399 | + return content.interface->Equal(other, descriptor_pool, message_factory, |
| 400 | + arena, result); |
| 401 | + } |
| 402 | + if (auto other_list_value = other.AsList(); other_list_value) { |
| 403 | + if (dispatcher_->equal != nullptr) { |
| 404 | + return dispatcher_->equal(dispatcher_, content_, *other_list_value, |
| 405 | + descriptor_pool, message_factory, arena, |
| 406 | + result); |
| 407 | + } |
| 408 | + return common_internal::ListValueEqual(*this, *other_list_value, |
| 409 | + descriptor_pool, message_factory, |
| 410 | + arena, result); |
| 411 | + } |
| 412 | + *result = FalseValue(); |
| 413 | + return absl::OkStatus(); |
| 414 | +} |
| 415 | + |
| 416 | +bool CustomListValue::IsZeroValue() const { |
| 417 | + if (dispatcher_ == nullptr) { |
| 418 | + CustomListValueInterface::Content content = |
| 419 | + content_.To<CustomListValueInterface::Content>(); |
| 420 | + ABSL_DCHECK(content.interface != nullptr); |
| 421 | + return content.interface->IsZeroValue(); |
| 422 | + } |
| 423 | + return dispatcher_->is_zero_value(dispatcher_, content_); |
| 424 | +} |
262 | 425 |
|
263 | 426 | CustomListValue CustomListValue::Clone( |
264 | 427 | absl::Nonnull<google::protobuf::Arena*> arena) const { |
265 | 428 | ABSL_DCHECK(arena != nullptr); |
266 | | - ABSL_DCHECK(*this); |
267 | 429 |
|
268 | | - if (ABSL_PREDICT_FALSE(!interface_)) { |
269 | | - return CustomListValue(); |
| 430 | + if (dispatcher_ == nullptr) { |
| 431 | + CustomListValueInterface::Content content = |
| 432 | + content_.To<CustomListValueInterface::Content>(); |
| 433 | + ABSL_DCHECK(content.interface != nullptr); |
| 434 | + if (content.arena != arena) { |
| 435 | + return content.interface->Clone(arena); |
| 436 | + } |
| 437 | + return *this; |
270 | 438 | } |
271 | | - if (interface_.arena() != arena) { |
272 | | - return interface_->Clone(arena); |
| 439 | + return dispatcher_->clone(dispatcher_, content_, arena); |
| 440 | +} |
| 441 | + |
| 442 | +bool CustomListValue::IsEmpty() const { |
| 443 | + if (dispatcher_ == nullptr) { |
| 444 | + CustomListValueInterface::Content content = |
| 445 | + content_.To<CustomListValueInterface::Content>(); |
| 446 | + ABSL_DCHECK(content.interface != nullptr); |
| 447 | + return content.interface->IsEmpty(); |
| 448 | + } |
| 449 | + if (dispatcher_->is_empty != nullptr) { |
| 450 | + return dispatcher_->is_empty(dispatcher_, content_); |
| 451 | + } |
| 452 | + return dispatcher_->size(dispatcher_, content_) == 0; |
| 453 | +} |
| 454 | + |
| 455 | +size_t CustomListValue::Size() const { |
| 456 | + if (dispatcher_ == nullptr) { |
| 457 | + CustomListValueInterface::Content content = |
| 458 | + content_.To<CustomListValueInterface::Content>(); |
| 459 | + ABSL_DCHECK(content.interface != nullptr); |
| 460 | + return content.interface->Size(); |
273 | 461 | } |
274 | | - return *this; |
| 462 | + return dispatcher_->size(dispatcher_, content_); |
| 463 | +} |
| 464 | + |
| 465 | +absl::Status CustomListValue::Get( |
| 466 | + size_t index, absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool, |
| 467 | + absl::Nonnull<google::protobuf::MessageFactory*> message_factory, |
| 468 | + absl::Nonnull<google::protobuf::Arena*> arena, absl::Nonnull<Value*> result) const { |
| 469 | + if (dispatcher_ == nullptr) { |
| 470 | + CustomListValueInterface::Content content = |
| 471 | + content_.To<CustomListValueInterface::Content>(); |
| 472 | + ABSL_DCHECK(content.interface != nullptr); |
| 473 | + return content.interface->Get(index, descriptor_pool, message_factory, |
| 474 | + arena, result); |
| 475 | + } |
| 476 | + return dispatcher_->get(dispatcher_, content_, index, descriptor_pool, |
| 477 | + message_factory, arena, result); |
| 478 | +} |
| 479 | + |
| 480 | +absl::Status CustomListValue::ForEach( |
| 481 | + ForEachWithIndexCallback callback, |
| 482 | + absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool, |
| 483 | + absl::Nonnull<google::protobuf::MessageFactory*> message_factory, |
| 484 | + absl::Nonnull<google::protobuf::Arena*> arena) const { |
| 485 | + if (dispatcher_ == nullptr) { |
| 486 | + CustomListValueInterface::Content content = |
| 487 | + content_.To<CustomListValueInterface::Content>(); |
| 488 | + ABSL_DCHECK(content.interface != nullptr); |
| 489 | + return content.interface->ForEach(callback, descriptor_pool, |
| 490 | + message_factory, arena); |
| 491 | + } |
| 492 | + if (dispatcher_->for_each != nullptr) { |
| 493 | + return dispatcher_->for_each(dispatcher_, content_, callback, |
| 494 | + descriptor_pool, message_factory, arena); |
| 495 | + } |
| 496 | + const size_t size = dispatcher_->size(dispatcher_, content_); |
| 497 | + for (size_t index = 0; index < size; ++index) { |
| 498 | + Value element; |
| 499 | + CEL_RETURN_IF_ERROR(dispatcher_->get(dispatcher_, content_, index, |
| 500 | + descriptor_pool, message_factory, |
| 501 | + arena, &element)); |
| 502 | + CEL_ASSIGN_OR_RETURN(auto ok, callback(index, element)); |
| 503 | + if (!ok) { |
| 504 | + break; |
| 505 | + } |
| 506 | + } |
| 507 | + return absl::OkStatus(); |
| 508 | +} |
| 509 | + |
| 510 | +absl::StatusOr<absl::Nonnull<ValueIteratorPtr>> CustomListValue::NewIterator() |
| 511 | + const { |
| 512 | + if (dispatcher_ == nullptr) { |
| 513 | + CustomListValueInterface::Content content = |
| 514 | + content_.To<CustomListValueInterface::Content>(); |
| 515 | + ABSL_DCHECK(content.interface != nullptr); |
| 516 | + return content.interface->NewIterator(); |
| 517 | + } |
| 518 | + if (dispatcher_->new_iterator != nullptr) { |
| 519 | + return dispatcher_->new_iterator(dispatcher_, content_); |
| 520 | + } |
| 521 | + return std::make_unique<CustomListValueDispatcherIterator>( |
| 522 | + dispatcher_, content_, dispatcher_->size(dispatcher_, content_)); |
| 523 | +} |
| 524 | + |
| 525 | +absl::Status CustomListValue::Contains( |
| 526 | + const Value& other, |
| 527 | + absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool, |
| 528 | + absl::Nonnull<google::protobuf::MessageFactory*> message_factory, |
| 529 | + absl::Nonnull<google::protobuf::Arena*> arena, absl::Nonnull<Value*> result) const { |
| 530 | + if (dispatcher_ == nullptr) { |
| 531 | + CustomListValueInterface::Content content = |
| 532 | + content_.To<CustomListValueInterface::Content>(); |
| 533 | + ABSL_DCHECK(content.interface != nullptr); |
| 534 | + return content.interface->Contains(other, descriptor_pool, message_factory, |
| 535 | + arena, result); |
| 536 | + } |
| 537 | + if (dispatcher_->contains != nullptr) { |
| 538 | + return dispatcher_->contains(dispatcher_, content_, other, descriptor_pool, |
| 539 | + message_factory, arena, result); |
| 540 | + } |
| 541 | + Value outcome = BoolValue(false); |
| 542 | + Value equal; |
| 543 | + CEL_RETURN_IF_ERROR(ForEach( |
| 544 | + [&](size_t index, const Value& element) -> absl::StatusOr<bool> { |
| 545 | + CEL_RETURN_IF_ERROR(element.Equal(other, descriptor_pool, |
| 546 | + message_factory, arena, &equal)); |
| 547 | + if (auto bool_result = As<BoolValue>(equal); |
| 548 | + bool_result.has_value() && bool_result->NativeValue()) { |
| 549 | + outcome = BoolValue(true); |
| 550 | + return false; |
| 551 | + } |
| 552 | + return true; |
| 553 | + }, |
| 554 | + descriptor_pool, message_factory, arena)); |
| 555 | + *result = outcome; |
| 556 | + return absl::OkStatus(); |
275 | 557 | } |
276 | 558 |
|
277 | 559 | } // namespace cel |
0 commit comments