Skip to content

Commit 9b93a20

Browse files
jnthntatumcopybara-github
authored andcommitted
Migrate repeated/map field accesses to use modern implementation.
PiperOrigin-RevId: 966689473
1 parent 1dcff09 commit 9b93a20

14 files changed

Lines changed: 1261 additions & 94 deletions

common/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,8 @@ cc_test(
865865
":value_kind",
866866
":value_testing",
867867
"//base:attributes",
868+
"//eval/public:cel_value",
869+
"//eval/public/structs:proto_message_type_adapter",
868870
"//internal:parse_text_proto",
869871
"//internal:status_macros",
870872
"//internal:testing",

common/legacy_value.cc

Lines changed: 102 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,15 @@
4343
#include "common/unknown.h"
4444
#include "common/value.h"
4545
#include "common/value_kind.h"
46+
#include "common/values/legacy_list_value.h"
47+
#include "common/values/legacy_map_value.h"
4648
#include "common/values/list_value_builder.h"
4749
#include "common/values/map_value_builder.h"
4850
#include "common/values/values.h"
4951
#include "eval/internal/cel_value_equal.h"
5052
#include "eval/public/cel_value.h"
51-
#include "eval/public/containers/field_backed_list_impl.h"
52-
#include "eval/public/containers/field_backed_map_impl.h"
5353
#include "eval/public/message_wrapper.h"
5454
#include "eval/public/structs/cel_proto_wrap_util.h"
55-
#include "eval/public/structs/legacy_type_adapter.h"
5655
#include "eval/public/structs/legacy_type_info_apis.h"
5756
#include "eval/public/structs/proto_message_type_adapter.h"
5857
#include "eval/public/structs/trivial_legacy_type_info_internal.h"
@@ -77,12 +76,9 @@ using ::google::api::expr::runtime::CelList;
7776
using ::google::api::expr::runtime::CelMap;
7877
using ::google::api::expr::runtime::CelValue;
7978
using ::google::api::expr::runtime::CreateCelValueFromField;
80-
using ::google::api::expr::runtime::FieldBackedListImpl;
81-
using ::google::api::expr::runtime::FieldBackedMapImpl;
8279
using ::google::api::expr::runtime::GetGenericProtoTypeInfoInstance;
8380
using ::google::api::expr::runtime::LegacyTypeInfoApis;
8481
using ::google::api::expr::runtime::MessageWrapper;
85-
using ::google::api::expr::runtime::internal::GetGenericProtoAccessApisInstance;
8682
using ::google::api::expr::runtime::internal::MaybeWrapValueToMessage;
8783

8884
absl::Status InvalidMapKeyTypeError(ValueKind kind) {
@@ -284,19 +280,17 @@ CelValue LegacyTrivialListValue(google::protobuf::Arena* absl_nonnull arena,
284280
}
285281
if (auto parsed_repeated_field_value = value.AsParsedRepeatedField();
286282
parsed_repeated_field_value) {
287-
auto maybe_cloned = parsed_repeated_field_value->Clone(arena);
288-
return CelValue::CreateList(google::protobuf::Arena::Create<FieldBackedListImpl>(
289-
arena, &maybe_cloned.message(), maybe_cloned.field(), arena));
283+
auto wrapped = common_internal::WrapLegacyParsedRepeatedField(
284+
*parsed_repeated_field_value, arena);
285+
return CelValue::CreateList(
286+
common_internal::AsLegacyListValue(wrapped)->cel_list());
290287
}
291288
if (auto parsed_json_list_value = value.AsParsedJsonList();
292289
parsed_json_list_value) {
293-
auto maybe_cloned = parsed_json_list_value->Clone(arena);
294-
return CelValue::CreateList(google::protobuf::Arena::Create<FieldBackedListImpl>(
295-
arena, cel::to_address(maybe_cloned),
296-
well_known_types::GetListValueReflectionOrDie(
297-
maybe_cloned->GetDescriptor())
298-
.GetValuesDescriptor(),
299-
arena));
290+
auto wrapped = common_internal::WrapLegacyParsedJsonList(
291+
*parsed_json_list_value, arena);
292+
return CelValue::CreateList(
293+
common_internal::AsLegacyListValue(wrapped)->cel_list());
300294
}
301295
if (auto custom_list_value = value.AsCustomList(); custom_list_value) {
302296
auto status_or_compat_list = common_internal::MakeCompatListValue(
@@ -322,19 +316,17 @@ CelValue LegacyTrivialMapValue(google::protobuf::Arena* absl_nonnull arena,
322316
}
323317
if (auto parsed_map_field_value = value.AsParsedMapField();
324318
parsed_map_field_value) {
325-
auto maybe_cloned = parsed_map_field_value->Clone(arena);
326-
return CelValue::CreateMap(google::protobuf::Arena::Create<FieldBackedMapImpl>(
327-
arena, &maybe_cloned.message(), maybe_cloned.field(), arena));
319+
auto wrapped = common_internal::WrapLegacyParsedMapField(
320+
*parsed_map_field_value, arena);
321+
return CelValue::CreateMap(
322+
common_internal::AsLegacyMapValue(wrapped)->cel_map());
328323
}
329324
if (auto parsed_json_map_value = value.AsParsedJsonMap();
330325
parsed_json_map_value) {
331-
auto maybe_cloned = parsed_json_map_value->Clone(arena);
332-
return CelValue::CreateMap(google::protobuf::Arena::Create<FieldBackedMapImpl>(
333-
arena, cel::to_address(maybe_cloned),
334-
well_known_types::GetStructReflectionOrDie(
335-
maybe_cloned->GetDescriptor())
336-
.GetFieldsDescriptor(),
337-
arena));
326+
auto wrapped =
327+
common_internal::WrapLegacyParsedJsonMap(*parsed_json_map_value, arena);
328+
return CelValue::CreateMap(
329+
common_internal::AsLegacyMapValue(wrapped)->cel_map());
338330
}
339331
if (auto custom_map_value = value.AsCustomMap(); custom_map_value) {
340332
auto status_or_compat_map = common_internal::MakeCompatMapValue(
@@ -352,6 +344,25 @@ CelValue LegacyTrivialMapValue(google::protobuf::Arena* absl_nonnull arena,
352344
value.GetRuntimeType().DebugString()))));
353345
}
354346

347+
LegacyStructValue ParsedMessageToLegacyStructValue(
348+
const ParsedMessageValue& parsed_message) {
349+
return LegacyStructValue(cel::to_address(parsed_message),
350+
&GetGenericProtoTypeInfoInstance());
351+
}
352+
353+
LegacyStructValue MakeLegacyStructValue(
354+
const google::protobuf::Message* absl_nonnull message,
355+
const LegacyTypeInfoApis* legacy_type_info) {
356+
// Guard against edge cases where a custom implementation of Message
357+
// misbehaves.
358+
// Modern value handles this with DCHECKs on value creation, legacy value
359+
// would allow it and just report an ErrorValue on accesses.
360+
if (message->GetReflection() == nullptr || legacy_type_info == nullptr) {
361+
legacy_type_info = TrivialTypeInfo::GetInstance();
362+
}
363+
return LegacyStructValue(message, legacy_type_info);
364+
}
365+
355366
} // namespace
356367

357368
google::api::expr::runtime::CelValue UnsafeLegacyValue(
@@ -394,10 +405,6 @@ google::api::expr::runtime::CelValue UnsafeLegacyValue(
394405
}
395406
}
396407

397-
} // namespace common_internal
398-
399-
namespace common_internal {
400-
401408
std::string LegacyListValue::DebugString() const {
402409
return CelValue::CreateList(impl_).DebugString();
403410
}
@@ -837,10 +844,8 @@ absl::Status LegacyStructValue::SerializeTo(
837844
ABSL_DCHECK(message_factory != nullptr);
838845
ABSL_DCHECK(output != nullptr);
839846

840-
auto message_wrapper = AsMessageWrapper(message_ptr_, legacy_type_info_);
841847
if (ABSL_PREDICT_TRUE(
842-
message_wrapper.message_ptr()->SerializePartialToZeroCopyStream(
843-
output))) {
848+
message_ptr_->SerializePartialToZeroCopyStream(output))) {
844849
return absl::OkStatus();
845850
}
846851
return absl::UnknownError("failed to serialize protocol buffer message");
@@ -918,16 +923,38 @@ absl::Status LegacyStructValue::GetFieldByName(
918923
const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
919924
google::protobuf::MessageFactory* absl_nonnull message_factory,
920925
google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
921-
auto message_wrapper = AsMessageWrapper(message_ptr_, legacy_type_info_);
922926
if (ABSL_PREDICT_FALSE(legacy_type_info_ == TrivialTypeInfo::GetInstance())) {
923927
*result = NoSuchFieldError(name);
924928
return absl::OkStatus();
925929
}
926-
CEL_ASSIGN_OR_RETURN(auto cel_value,
927-
GetGenericProtoAccessApisInstance().GetField(
928-
name, message_wrapper, unboxing_options,
929-
MemoryManagerRef::Pooling(arena)));
930-
CEL_RETURN_IF_ERROR(ModernValue(arena, cel_value, *result));
930+
931+
ParsedMessageValue parsed_message = UnsafeParsedMessageValue(message_ptr_);
932+
const auto* descriptor = parsed_message.GetDescriptor();
933+
const auto* field = descriptor->FindFieldByName(name);
934+
if (field == nullptr) {
935+
field = descriptor->file()->pool()->FindExtensionByPrintableName(descriptor,
936+
name);
937+
if (field == nullptr) {
938+
*result = NoSuchFieldError(name);
939+
return absl::OkStatus();
940+
}
941+
}
942+
943+
if (field->is_map()) {
944+
*result = WrapLegacyParsedMapField(
945+
UnsafeParsedMapFieldValue(message_ptr_, field), arena);
946+
return absl::OkStatus();
947+
}
948+
if (field->is_repeated()) {
949+
*result = WrapLegacyParsedRepeatedField(
950+
UnsafeParsedRepeatedFieldValue(message_ptr_, field), arena);
951+
return absl::OkStatus();
952+
}
953+
954+
CEL_RETURN_IF_ERROR(parsed_message.GetField(field, unboxing_options,
955+
descriptor_pool, message_factory,
956+
arena, result));
957+
interop_internal::WrapLegacyFieldAccessResult(arena, result);
931958
return absl::OkStatus();
932959
}
933960

@@ -980,7 +1007,6 @@ absl::Status LegacyStructValue::Qualify(
9801007
if (ABSL_PREDICT_FALSE(qualifiers.empty())) {
9811008
return absl::InvalidArgumentError("invalid select qualifier path.");
9821009
}
983-
auto message_wrapper = AsMessageWrapper(message_ptr_, legacy_type_info_);
9841010
if (ABSL_PREDICT_FALSE(legacy_type_info_ == TrivialTypeInfo::GetInstance())) {
9851011
absl::string_view field_name = absl::visit(
9861012
absl::Overload(
@@ -995,12 +1021,13 @@ absl::Status LegacyStructValue::Qualify(
9951021
*count = -1;
9961022
return absl::OkStatus();
9971023
}
998-
CEL_ASSIGN_OR_RETURN(auto legacy_result,
999-
GetGenericProtoAccessApisInstance().Qualify(
1000-
qualifiers, message_wrapper, presence_test,
1001-
MemoryManager::Pooling(arena)));
1002-
CEL_RETURN_IF_ERROR(ModernValue(arena, legacy_result.value, *result));
1003-
*count = legacy_result.qualifier_count;
1024+
1025+
ParsedMessageValue parsed_message = UnsafeParsedMessageValue(message_ptr_);
1026+
CEL_RETURN_IF_ERROR(parsed_message.Qualify(qualifiers, presence_test,
1027+
descriptor_pool, message_factory,
1028+
arena, result, count));
1029+
1030+
interop_internal::WrapLegacyFieldAccessResult(arena, result);
10041031
return absl::OkStatus();
10051032
}
10061033

@@ -1035,7 +1062,7 @@ absl::Status ModernValue(google::protobuf::Arena* arena,
10351062
return absl::OkStatus();
10361063
case CelValue::Type::kMessage: {
10371064
auto message_wrapper = legacy_value.MessageWrapperOrDie();
1038-
result = common_internal::LegacyStructValue(
1065+
result = common_internal::MakeLegacyStructValue(
10391066
google::protobuf::DownCastMessage<google::protobuf::Message>(
10401067
message_wrapper.message_ptr()),
10411068
message_wrapper.legacy_type_info());
@@ -1153,7 +1180,7 @@ absl::StatusOr<Value> FromLegacyValue(google::protobuf::Arena* arena,
11531180
legacy_value.BytesOrDie().value());
11541181
case CelValue::Type::kMessage: {
11551182
auto message_wrapper = legacy_value.MessageWrapperOrDie();
1156-
return common_internal::LegacyStructValue(
1183+
return common_internal::MakeLegacyStructValue(
11571184
google::protobuf::DownCastMessage<google::protobuf::Message>(
11581185
message_wrapper.message_ptr()),
11591186
message_wrapper.legacy_type_info());
@@ -1262,6 +1289,33 @@ google::api::expr::runtime::CelValue ModernValueToLegacyValueOrDie(
12621289
return std::move(*status_or_value);
12631290
}
12641291

1292+
void WrapLegacyFieldAccessResult(google::protobuf::Arena* absl_nonnull arena,
1293+
Value* absl_nonnull result) {
1294+
if (result->IsParsedMessage()) {
1295+
*result = common_internal::ParsedMessageToLegacyStructValue(
1296+
result->GetParsedMessage());
1297+
} else if (result->IsParsedRepeatedField()) {
1298+
*result =
1299+
WrapLegacyParsedRepeatedField(result->GetParsedRepeatedField(), arena);
1300+
} else if (result->IsParsedJsonList()) {
1301+
*result = WrapLegacyParsedJsonList(result->GetParsedJsonList(), arena);
1302+
} else if (result->IsParsedMapField()) {
1303+
*result = WrapLegacyParsedMapField(result->GetParsedMapField(), arena);
1304+
} else if (result->IsParsedJsonMap()) {
1305+
*result = WrapLegacyParsedJsonMap(result->GetParsedJsonMap(), arena);
1306+
} else if (result->IsList()) {
1307+
auto is_empty = result->GetList().IsEmpty();
1308+
if (is_empty.ok() && *is_empty) {
1309+
*result = CustomListValue(common_internal::EmptyCompatListValue(), arena);
1310+
}
1311+
} else if (result->IsMap()) {
1312+
auto is_empty = result->GetMap().IsEmpty();
1313+
if (is_empty.ok() && *is_empty) {
1314+
*result = CustomMapValue(common_internal::EmptyCompatMapValue(), arena);
1315+
}
1316+
}
1317+
}
1318+
12651319
TypeValue CreateTypeValueFromView(google::protobuf::Arena* arena,
12661320
absl::string_view input) {
12671321
return TypeValue(common_internal::LegacyRuntimeType(input));

common/legacy_value.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ namespace cel::interop_internal {
6565
// message with the default type info, or `nullptr` otherwise.
6666
const google::protobuf::Message* absl_nullable GetLegacyMessage(const Value& value);
6767

68+
// Helper for wrapping a field accesses for the legacy runtime.
69+
//
70+
// Adapts the output to avoid further allocations when converting to a legacy
71+
// value when possible.
72+
void WrapLegacyFieldAccessResult(google::protobuf::Arena* absl_nonnull arena,
73+
Value* absl_nonnull result);
74+
6875
// Access a field on a legacy message value, writing the result to `out`.
6976
// Prefers wrapping legacy values instead of using the modern value
7077
// representation.

common/value.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1512,6 +1512,13 @@ Value WrapFieldImpl(
15121512
ABSL_DCHECK(!IsWellKnownMessageType(message->GetDescriptor()));
15131513

15141514
const auto* reflection = message->GetReflection();
1515+
if (ABSL_PREDICT_FALSE(reflection == nullptr)) {
1516+
// This only happens for special implementations of Message that
1517+
// should not normally be used with CEL.
1518+
return ErrorValue(absl::InvalidArgumentError(
1519+
absl::StrCat("failed to get reflection for message type: ",
1520+
message->GetDescriptor()->full_name())));
1521+
}
15151522
if (field->is_map()) {
15161523
if (reflection->FieldSize(*message, field) == 0) {
15171524
return MapValue();
@@ -1653,6 +1660,13 @@ Value WrapRepeatedFieldImpl(
16531660
ABSL_DCHECK(arena != nullptr);
16541661

16551662
const auto* reflection = message->GetReflection();
1663+
if (ABSL_PREDICT_FALSE(reflection == nullptr)) {
1664+
// This only happens for special implementations of Message that
1665+
// should not normally be used with CEL.
1666+
return ErrorValue(absl::InvalidArgumentError(
1667+
absl::StrCat("failed to get reflection for message type: ",
1668+
message->GetDescriptor()->full_name())));
1669+
}
16561670
const int size = reflection->FieldSize(*message, field);
16571671
if (ABSL_PREDICT_FALSE(index < 0 || index >= size)) {
16581672
return ErrorValue(absl::InvalidArgumentError(

common/values/custom_map_value.cc

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -678,13 +678,22 @@ absl::StatusOr<bool> CustomMapValue::Find(
678678
CustomMapValueInterface::Content content =
679679
content_.To<CustomMapValueInterface::Content>();
680680
ABSL_DCHECK(content.interface != nullptr);
681-
CEL_ASSIGN_OR_RETURN(
682-
ok, content.interface->Find(key, descriptor_pool, message_factory,
683-
arena, result));
681+
auto status_or_found = content.interface->Find(
682+
key, descriptor_pool, message_factory, arena, result);
683+
if (!status_or_found.ok()) {
684+
*result = ErrorValue(std::move(status_or_found).status());
685+
return false;
686+
}
687+
ok = *status_or_found;
684688
} else {
685-
CEL_ASSIGN_OR_RETURN(
686-
ok, dispatcher_->find(dispatcher_, content_, key, descriptor_pool,
687-
message_factory, arena, result));
689+
auto status_or_found =
690+
dispatcher_->find(dispatcher_, content_, key, descriptor_pool,
691+
message_factory, arena, result);
692+
if (!status_or_found.ok()) {
693+
*result = ErrorValue(std::move(status_or_found).status());
694+
return false;
695+
}
696+
ok = *status_or_found;
688697
}
689698
if (ok) {
690699
return true;
@@ -726,12 +735,21 @@ absl::Status CustomMapValue::Has(
726735
CustomMapValueInterface::Content content =
727736
content_.To<CustomMapValueInterface::Content>();
728737
ABSL_DCHECK(content.interface != nullptr);
729-
CEL_ASSIGN_OR_RETURN(has, content.interface->Has(key, descriptor_pool,
730-
message_factory, arena));
738+
auto status_or_has =
739+
content.interface->Has(key, descriptor_pool, message_factory, arena);
740+
if (!status_or_has.ok()) {
741+
*result = ErrorValue(std::move(status_or_has).status());
742+
return absl::OkStatus();
743+
}
744+
has = *status_or_has;
731745
} else {
732-
CEL_ASSIGN_OR_RETURN(
733-
has, dispatcher_->has(dispatcher_, content_, key, descriptor_pool,
734-
message_factory, arena));
746+
auto status_or_has = dispatcher_->has(
747+
dispatcher_, content_, key, descriptor_pool, message_factory, arena);
748+
if (!status_or_has.ok()) {
749+
*result = ErrorValue(std::move(status_or_has).status());
750+
return absl::OkStatus();
751+
}
752+
has = *status_or_has;
735753
}
736754
*result = BoolValue(has);
737755
return absl::OkStatus();

common/values/custom_map_value.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ class CustomMapValueInterfaceKeysIterator;
5454
class CustomMapValue;
5555
using CustomMapValueContent = CustomValueContent;
5656

57+
// Dispatch table for `CustomMapValue`.
58+
//
59+
// See the documentation for `CustomMapValueInterface` for more details on
60+
// composite functions.
61+
//
62+
// See documentation for `UnsafeCustomMapValue` on how to use this class.
5763
struct CustomMapValueDispatcher {
5864
using GetTypeId =
5965
NativeTypeId (*)(const CustomMapValueDispatcher* absl_nonnull dispatcher,
@@ -253,6 +259,9 @@ class CustomMapValueInterface {
253259
google::protobuf::MessageFactory* absl_nonnull message_factory,
254260
google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const = 0;
255261

262+
// Whether the map has the given key.
263+
//
264+
// A non-ok status is coerced to an ErrorValue (e.g. wrong key type).
256265
virtual absl::StatusOr<bool> Has(
257266
const Value& key,
258267
const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,

0 commit comments

Comments
 (0)