Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 38 additions & 21 deletions common/legacy_value.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,9 @@ using ::cel::interop_internal::TrivialTypeInfo;
using ::google::api::expr::runtime::CelList;
using ::google::api::expr::runtime::CelMap;
using ::google::api::expr::runtime::CelValue;
using ::google::api::expr::runtime::CreateCelValueFromField;
using ::google::api::expr::runtime::GetGenericProtoTypeInfoInstance;
using ::google::api::expr::runtime::LegacyTypeInfoApis;
using ::google::api::expr::runtime::MessageWrapper;
using ::google::api::expr::runtime::internal::GetGenericProtoAccessApisInstance;
using ::google::api::expr::runtime::internal::MaybeWrapValueToMessage;

absl::Status InvalidMapKeyTypeError(ValueKind kind) {
Expand Down Expand Up @@ -262,6 +260,11 @@ CelValue LegacyTrivialStructValue(google::protobuf::Arena* absl_nonnull arena,
}
if (auto parsed_message_value = value.AsParsedMessage();
parsed_message_value) {
if (interop_internal::IsUnsafeParsedMessageValue(*parsed_message_value)) {
return CelValue::CreateMessageWrapper(
AsMessageWrapper(cel::to_address(*parsed_message_value),
&GetGenericProtoTypeInfoInstance()));
}
auto maybe_cloned = parsed_message_value->Clone(arena);
return CelValue::CreateMessageWrapper(MessageWrapper(
cel::to_address(maybe_cloned), &GetGenericProtoTypeInfoInstance()));
Expand Down Expand Up @@ -923,17 +926,26 @@ absl::Status LegacyStructValue::GetFieldByName(
const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
google::protobuf::MessageFactory* absl_nonnull message_factory,
google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
auto message_wrapper = AsMessageWrapper(message_ptr_, legacy_type_info_);
if (ABSL_PREDICT_FALSE(legacy_type_info_ == TrivialTypeInfo::GetInstance())) {
*result = NoSuchFieldError(name);
return absl::OkStatus();
}
CEL_ASSIGN_OR_RETURN(auto cel_value,
GetGenericProtoAccessApisInstance().GetField(
name, message_wrapper, unboxing_options,
MemoryManagerRef::Pooling(arena)));
CEL_RETURN_IF_ERROR(ModernValue(arena, cel_value, *result));
return absl::OkStatus();

ParsedMessageValue parsed_message = UnsafeParsedMessageValue(message_ptr_);
const auto* descriptor = parsed_message.GetDescriptor();
const auto* field = descriptor->FindFieldByName(name);
if (field == nullptr) {
field = descriptor->file()->pool()->FindExtensionByPrintableName(descriptor,
name);
if (field == nullptr) {
*result = NoSuchFieldError(name);
return absl::OkStatus();
}
}

return interop_internal::WrapLegacyMessageField(
message_ptr_, field, unboxing_options, descriptor_pool, message_factory,
arena, result);
}

absl::Status LegacyStructValue::GetFieldByNumber(
Expand Down Expand Up @@ -985,7 +997,6 @@ absl::Status LegacyStructValue::Qualify(
if (ABSL_PREDICT_FALSE(qualifiers.empty())) {
return absl::InvalidArgumentError("invalid select qualifier path.");
}
auto message_wrapper = AsMessageWrapper(message_ptr_, legacy_type_info_);
if (ABSL_PREDICT_FALSE(legacy_type_info_ == TrivialTypeInfo::GetInstance())) {
absl::string_view field_name = absl::visit(
absl::Overload(
Expand All @@ -1000,12 +1011,13 @@ absl::Status LegacyStructValue::Qualify(
*count = -1;
return absl::OkStatus();
}
CEL_ASSIGN_OR_RETURN(auto legacy_result,
GetGenericProtoAccessApisInstance().Qualify(
qualifiers, message_wrapper, presence_test,
MemoryManager::Pooling(arena)));
CEL_RETURN_IF_ERROR(ModernValue(arena, legacy_result.value, *result));
*count = legacy_result.qualifier_count;

ParsedMessageValue parsed_message = UnsafeParsedMessageValue(message_ptr_);
CEL_RETURN_IF_ERROR(parsed_message.Qualify(qualifiers, presence_test,
descriptor_pool, message_factory,
arena, result, count));

interop_internal::WrapLegacyFieldAccessResult(arena, result);
return absl::OkStatus();
}

Expand Down Expand Up @@ -1311,12 +1323,17 @@ const google::protobuf::Message* absl_nullable GetLegacyMessage(const Value& val
absl::Status WrapLegacyMessageField(
const google::protobuf::Message* absl_nonnull message,
const google::protobuf::FieldDescriptor* absl_nonnull field_descriptor,
ProtoWrapperTypeOptions unboxing_option, google::protobuf::Arena* arena,
ProtoWrapperTypeOptions unboxing_option,
const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
google::protobuf::MessageFactory* absl_nonnull message_factory, google::protobuf::Arena* arena,
Value* absl_nonnull out) {
CEL_ASSIGN_OR_RETURN(CelValue result,
CreateCelValueFromField(message, field_descriptor,
unboxing_option, arena));
return ModernValue(arena, result, *out);
ParsedMessageValue parsed_message = UnsafeParsedMessageValue(message);
CEL_RETURN_IF_ERROR(parsed_message.GetField(field_descriptor, unboxing_option,
descriptor_pool, message_factory,
arena, out));
WrapLegacyFieldAccessResult(arena, out);

return absl::OkStatus();
}

} // namespace interop_internal
Expand Down
8 changes: 7 additions & 1 deletion common/legacy_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ class MessageFactory;

namespace cel::interop_internal {

inline bool IsUnsafeParsedMessageValue(const cel::ParsedMessageValue& value) {
return value.is_unsafe();
}

// Returns the underlying `google::protobuf::Message` of a `cel::Value` if it is a legacy
// message with the default type info, or `nullptr` otherwise.
const google::protobuf::Message* absl_nullable GetLegacyMessage(const Value& value);
Expand All @@ -82,7 +86,9 @@ void WrapLegacyFieldAccessResult(google::protobuf::Arena* absl_nonnull arena,
absl::Status WrapLegacyMessageField(
const google::protobuf::Message* absl_nonnull message,
const google::protobuf::FieldDescriptor* absl_nonnull field_descriptor,
ProtoWrapperTypeOptions unboxing_option, google::protobuf::Arena* arena,
ProtoWrapperTypeOptions unboxing_option,
const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
google::protobuf::MessageFactory* absl_nonnull message_factory, google::protobuf::Arena* arena,
Value* absl_nonnull out);

absl::StatusOr<Value> FromLegacyValue(
Expand Down
23 changes: 13 additions & 10 deletions common/values/legacy_map_value.cc
Original file line number Diff line number Diff line change
Expand Up @@ -401,21 +401,24 @@ class LegacyParsedJsonMapValue final
if (arena == nullptr) {
arena = arena_;
}
if (auto status =
google::api::expr::runtime::CelValue::CheckMapKeyType(key);
!status.ok()) {
status.IgnoreError();
return std::nullopt;
}
Value modern_key;
if (ABSL_PREDICT_FALSE(!ModernValue(arena, key, modern_key).ok())) {
return std::nullopt;
}
Value modern_val;
auto status_or_found = value_.Find(
modern_key, google::protobuf::DescriptorPool::generated_pool(),
google::protobuf::MessageFactory::generated_factory(), arena, &modern_val);
if (!status_or_found.ok() || !*status_or_found) {
// Call custom map FindDirectly. MapValue normally handles coercing error
// results to value types, so emulate that here.
//
// We know that the descriptor pool and message factory aren't needed here,
// so fine to use generated.
auto found =
Find(modern_key, google::protobuf::DescriptorPool::generated_pool(),
google::protobuf::MessageFactory::generated_factory(), arena, &modern_val);
if (!found.ok()) {
return google::api::expr::runtime::CreateErrorValue(arena,
found.status());
}
if (!(*found) && !modern_val.IsError()) {
return std::nullopt;
}
return UnsafeLegacyValue(modern_val, /*stable=*/false, arena);
Expand Down
6 changes: 6 additions & 0 deletions common/values/parsed_message_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@

namespace cel {

namespace interop_internal {
bool IsUnsafeParsedMessageValue(const ParsedMessageValue& value);
}

class MessageValue;
class StructValue;
class Value;
Expand Down Expand Up @@ -189,6 +193,8 @@ class ParsedMessageValue final
friend class common_internal::StructValueMixin<ParsedMessageValue>;
friend ParsedMessageValue UnsafeParsedMessageValue(
const google::protobuf::Message* absl_nonnull value);
friend bool interop_internal::IsUnsafeParsedMessageValue(
const ParsedMessageValue& value);

explicit ParsedMessageValue(
const google::protobuf::Message* absl_nonnull value ABSL_ATTRIBUTE_LIFETIME_BOUND)
Expand Down
73 changes: 43 additions & 30 deletions eval/eval/select_step.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,22 @@ absl::Status WrappedStructGet(
ProtoWrapperTypeOptions unboxing_option,
const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
google::protobuf::MessageFactory* absl_nonnull message_factory,
google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) {
if (const google::protobuf::Message* message =
cel::interop_internal::GetLegacyMessage(target);
message != nullptr) {
CelValue::MessageWrapper message_wrapper(
message, &GetGenericProtoTypeInfoInstance());
CEL_ASSIGN_OR_RETURN(CelValue cel_value,
internal::GetGenericProtoAccessApisInstance().GetField(
field, message_wrapper, unboxing_option,
cel::MemoryManagerRef::Pooling(arena)));
return cel::ModernValue(arena, cel_value, *result);
google::protobuf::Arena* absl_nonnull arena,
bool enable_use_new_field_select_implementation,
Value* absl_nonnull result) {
if (!enable_use_new_field_select_implementation) {
if (const google::protobuf::Message* message =
cel::interop_internal::GetLegacyMessage(target);
message != nullptr) {
CelValue::MessageWrapper message_wrapper(
message, &GetGenericProtoTypeInfoInstance());
CEL_ASSIGN_OR_RETURN(
CelValue cel_value,
internal::GetGenericProtoAccessApisInstance().GetField(
field, message_wrapper, unboxing_option,
cel::MemoryManagerRef::Pooling(arena)));
return cel::ModernValue(arena, cel_value, *result);
}
}
return target.GetStruct().GetFieldByName(
field, unboxing_option, descriptor_pool, message_factory, arena, result);
Expand Down Expand Up @@ -132,7 +137,9 @@ absl::Status PerformGet(const Value& target, absl::string_view field,
ProtoWrapperTypeOptions unboxing_option,
const google::protobuf::DescriptorPool* descriptor_pool,
google::protobuf::MessageFactory* message_factory,
google::protobuf::Arena* arena, Value& result) {
google::protobuf::Arena* arena,
bool enable_use_new_field_select_implementation,
Value& result) {
switch (target.kind()) {
case ValueKind::kMap: {
auto status = target.GetMap().Get(field_value, descriptor_pool,
Expand All @@ -143,9 +150,9 @@ absl::Status PerformGet(const Value& target, absl::string_view field,
return absl::OkStatus();
}
case ValueKind::kStruct: {
auto status =
WrappedStructGet(target, field, unboxing_option, descriptor_pool,
message_factory, arena, &result);
auto status = WrappedStructGet(
target, field, unboxing_option, descriptor_pool, message_factory,
arena, enable_use_new_field_select_implementation, &result);
if (!status.ok()) {
result = ErrorValue(std::move(status));
}
Expand All @@ -161,7 +168,9 @@ absl::Status PerformOptionalGet(const Value& target, absl::string_view field,
ProtoWrapperTypeOptions unboxing_option,
const google::protobuf::DescriptorPool* descriptor_pool,
google::protobuf::MessageFactory* message_factory,
google::protobuf::Arena* arena, Value& result) {
google::protobuf::Arena* arena,
bool enable_use_new_field_select_implementation,
Value& result) {
switch (target.kind()) {
case ValueKind::kMap: {
CEL_ASSIGN_OR_RETURN(
Expand All @@ -182,9 +191,9 @@ absl::Status PerformOptionalGet(const Value& target, absl::string_view field,
result = OptionalValue::None();
return absl::OkStatus();
}
CEL_RETURN_IF_ERROR(WrappedStructGet(target, field, unboxing_option,
descriptor_pool, message_factory,
arena, &result));
CEL_RETURN_IF_ERROR(WrappedStructGet(
target, field, unboxing_option, descriptor_pool, message_factory,
arena, enable_use_new_field_select_implementation, &result));

ABSL_DCHECK(!result.IsUnknown());
result = OptionalValue::Of(std::move(result), arena);
Expand Down Expand Up @@ -247,7 +256,7 @@ absl::Status SelectStep::Evaluate(ExecutionFrame* frame) const {
optional_arg = arg.GetOptional();
}

if (!(optional_arg || arg->Is<MapValue>() || arg->Is<StructValue>())) {
if (!(optional_arg || arg.IsMap() || arg.IsStruct())) {
frame->value_stack().PopAndPush(cel::ErrorValue(InvalidSelectTargetError()),
std::move(result_trail));
return absl::OkStatus();
Expand Down Expand Up @@ -290,7 +299,8 @@ absl::Status SelectStep::Evaluate(ExecutionFrame* frame) const {
optional_arg->Value(&value);
auto status = PerformOptionalGet(
value, field_, field_value_, unboxing_option_, frame->descriptor_pool(),
frame->message_factory(), frame->arena(), result);
frame->message_factory(), frame->arena(),
frame->options().enable_use_new_field_select_implementation, result);
if (!status.ok()) {
result = ErrorValue(std::move(status));
}
Expand All @@ -300,7 +310,8 @@ absl::Status SelectStep::Evaluate(ExecutionFrame* frame) const {

CEL_RETURN_IF_ERROR(PerformGet(
arg, field_, field_value_, unboxing_option_, frame->descriptor_pool(),
frame->message_factory(), frame->arena(), result));
frame->message_factory(), frame->arena(),
frame->options().enable_use_new_field_select_implementation, result));
frame->value_stack().PopAndPush(std::move(result), std::move(result_trail));
return absl::OkStatus();
}
Expand Down Expand Up @@ -380,19 +391,20 @@ class DirectSelectStep : public DirectExpressionStep {
}
Value value;
optional_arg->Value(&value);
auto status =
PerformOptionalGet(value, field_, field_value_, unboxing_option_,
frame.descriptor_pool(), frame.message_factory(),
frame.arena(), result);
auto status = PerformOptionalGet(
value, field_, field_value_, unboxing_option_,
frame.descriptor_pool(), frame.message_factory(), frame.arena(),
frame.options().enable_use_new_field_select_implementation, result);
if (!status.ok()) {
result = ErrorValue(std::move(status));
}
return absl::OkStatus();
}

return PerformGet(result, field_, field_value_, unboxing_option_,
frame.descriptor_pool(), frame.message_factory(),
frame.arena(), result);
return PerformGet(
result, field_, field_value_, unboxing_option_, frame.descriptor_pool(),
frame.message_factory(), frame.arena(),
frame.options().enable_use_new_field_select_implementation, result);
}

private:
Expand Down Expand Up @@ -495,7 +507,8 @@ absl::Status ProtoSelectStep::EvaluateLegacyMessageGetField(
return absl::OkStatus();
}
return cel::interop_internal::WrapLegacyMessageField(
legacy_message, field_descriptor_, unboxing_option_, frame->arena(),
legacy_message, field_descriptor_, unboxing_option_,
frame->descriptor_pool(), frame->message_factory(), frame->arena(),
&frame->value_stack().Peek());
}

Expand Down
2 changes: 2 additions & 0 deletions eval/internal/cel_value_equal_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ const std::vector<CelValue>& ValueExamples1() {
result->push_back(CelValue::CreateMap(&CelMapExample1()));
result->push_back(CelValue::CreateCelTypeView("type"));

ABSL_CHECK_EQ(arena.SpaceUsed(), 0) << "Arena should not be used.";

return result.release();
}();
return *examples;
Expand Down
1 change: 1 addition & 0 deletions eval/public/cel_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ cel::RuntimeOptions ConvertToRuntimeOptions(const InterpreterOptions& options) {
options.enable_fast_builtins,
options.enable_precision_preserving_double_format,
options.enable_typed_field_access,
options.enable_use_new_field_select_implementation,
};
}

Expand Down
10 changes: 10 additions & 0 deletions eval/public/cel_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,16 @@ struct InterpreterOptions {
// path for field access when the type is known at plan time, instead of using
// the generic field access implementation.
bool enable_typed_field_access = false;

// Temporary flag to gate using a new field selection implementation for
// protos.
//
// For the cel::Runtime APIs, this is a no-op.
//
// For google::api::expr::runtime::CelExpression, this will enable updated
// implementations for field access on protobuf messages, aligned with the
// cel::Value implementation.
bool enable_use_new_field_select_implementation = false;
};
// LINT.ThenChange(//depot/google3/runtime/runtime_options.h)

Expand Down
9 changes: 8 additions & 1 deletion eval/public/structs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,17 @@ cc_library(
deps = [
":cel_proto_wrap_util",
":proto_message_type_adapter",
":trivial_legacy_type_info_internal",
"//common:value",
"//eval/public:cel_value",
"//eval/public:message_wrapper",
"//internal:proto_time_encoding",
"@com_google_absl//absl/types:optional",
"@com_google_absl//absl/base:no_destructor",
"@com_google_absl//absl/base:nullability",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_protobuf//:duration_cc_proto",
"@com_google_protobuf//:protobuf",
"@com_google_protobuf//:timestamp_cc_proto",
Expand Down
Loading
Loading