From 371e043d309f1b74cfa7521f1d27221dd84bb3a4 Mon Sep 17 00:00:00 2001 From: Stephen Roberts Date: Thu, 15 Jan 2026 05:03:15 -0800 Subject: [PATCH] please run presubmits PiperOrigin-RevId: 856612493 --- .../main/java/dev/cel/common/ast/BUILD.bazel | 1 + .../dev/cel/common/ast/CelExprFactory.java | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/common/src/main/java/dev/cel/common/ast/BUILD.bazel b/common/src/main/java/dev/cel/common/ast/BUILD.bazel index 3fc709a07..001459d06 100644 --- a/common/src/main/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/ast/BUILD.bazel @@ -125,6 +125,7 @@ java_library( "//common/annotations", "//common/values:cel_byte_string", "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", ], ) diff --git a/common/src/main/java/dev/cel/common/ast/CelExprFactory.java b/common/src/main/java/dev/cel/common/ast/CelExprFactory.java index b69dab05c..8eee2f7ec 100644 --- a/common/src/main/java/dev/cel/common/ast/CelExprFactory.java +++ b/common/src/main/java/dev/cel/common/ast/CelExprFactory.java @@ -16,11 +16,17 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Strings.isNullOrEmpty; +import static com.google.common.collect.ImmutableList.toImmutableList; import com.google.common.primitives.UnsignedLong; +import com.google.protobuf.ByteString; +import com.google.protobuf.Descriptors.EnumValueDescriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Message; import dev.cel.common.annotations.Internal; import dev.cel.common.values.CelByteString; import java.util.Arrays; +import java.util.List; /** Factory for generating expression nodes. */ @Internal @@ -138,6 +144,68 @@ public final CelExpr.CelStruct.Entry newMessageField(String field, CelExpr value .build(); } + /** Creates a new message {@link CelExpr} from a protobuf {@link Message}. */ + public final CelExpr newMessageValue(Message message) { + return newMessage( + message.getDescriptorForType().getFullName(), + message.getAllFields().entrySet().stream() + .map(entry -> newMessageFieldValue(entry.getKey(), entry.getValue())) + .collect(toImmutableList())); + } + + private CelExpr.CelStruct.Entry newMessageFieldValue(FieldDescriptor field, Object value) { + CelExpr fieldValue; + if (field.isMapField()) { + fieldValue = newMapFieldValue(field, value); + } else if (field.isRepeated()) { + fieldValue = newRepeatedFieldValue(field, value); + } else { + fieldValue = newSingularFieldValue(field, value); + } + return newMessageField(field.getName(), fieldValue); + } + + private CelExpr newMapFieldValue(FieldDescriptor field, Object value) { + @SuppressWarnings("unchecked") + List list = (List) value; // Safe cast per protobuf spec. + FieldDescriptor keyField = field.getMessageType().findFieldByNumber(1); + FieldDescriptor valueField = field.getMessageType().findFieldByNumber(2); + return newMap( + list.stream() + .map( + entryMsg -> + newMapEntry( + /* key= */ newSingularFieldValue(keyField, entryMsg.getField(keyField)), + /* value= */ newSingularFieldValue( + valueField, entryMsg.getField(valueField)))) + .collect(toImmutableList())); + } + + private CelExpr newRepeatedFieldValue(FieldDescriptor field, Object value) { + @SuppressWarnings("unchecked") + List list = (List) value; // Safe cast per protobuf spec. + return newList( + list.stream().map(v -> newSingularFieldValue(field, v)).collect(toImmutableList())); + } + + private CelExpr newSingularFieldValue(FieldDescriptor field, Object value) { + return switch (field.getType()) { + case DOUBLE -> newDoubleLiteral((Double) value); + case FLOAT -> newDoubleLiteral(((Float) value).doubleValue()); + case INT64, SFIXED64, SINT64 -> newIntLiteral((Long) value); + case UINT64, FIXED64 -> newUintLiteral((Long) value); + case INT32, SFIXED32, SINT32 -> newIntLiteral(((Integer) value).longValue()); + case UINT32, FIXED32 -> newUintLiteral(((Integer) value).longValue()); + case BOOL -> newBoolLiteral((Boolean) value); + case STRING -> newStringLiteral((String) value); + case BYTES -> newBytesLiteral(((ByteString) value).toByteArray()); + case MESSAGE -> newMessageValue((Message) value); + case ENUM -> newIntLiteral((long) ((EnumValueDescriptor) value).getNumber()); + case GROUP -> + throw new UnsupportedOperationException("Legacy GROUP fields are not supported by CEL."); + }; + } + /** Fold creates a fold for one variable comprehension instruction. */ public final CelExpr fold( String iterVar,