Skip to content

Commit 1856808

Browse files
l46kokcopybara-github
authored andcommitted
No public description
PiperOrigin-RevId: 997600157
1 parent 32ba216 commit 1856808

18 files changed

Lines changed: 883 additions & 150 deletions

File tree

‎common/src/main/java/dev/cel/common/values/BUILD.bazel‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ java_library(
329329
deps = [
330330
":base_proto_cel_value_converter",
331331
":optimized_selectable",
332+
":preadapted_list",
332333
":select_field",
333334
":values",
334335
"//:auto_value",
@@ -360,6 +361,7 @@ cel_android_library(
360361
deps = [
361362
":base_proto_cel_value_converter_android",
362363
":optimized_selectable_android",
364+
":preadapted_list_android",
363365
":select_field_android",
364366
":values_android",
365367
"//:auto_value",

‎common/src/main/java/dev/cel/common/values/ProtoLiteCelValueConverter.java‎

Lines changed: 128 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@
2525
import com.google.protobuf.ByteString;
2626
import com.google.protobuf.CodedInputStream;
2727
import com.google.protobuf.ExtensionRegistryLite;
28+
import com.google.protobuf.Internal.EnumLite;
2829
import com.google.protobuf.InvalidProtocolBufferException;
2930
import com.google.protobuf.MessageLite;
3031
import com.google.protobuf.WireFormat;
3132
import dev.cel.common.annotations.Internal;
3233
import dev.cel.common.internal.CelLiteDescriptorPool;
3334
import dev.cel.common.internal.WellKnownProto;
35+
import dev.cel.protobuf.CelLiteDescriptor;
3436
import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor;
3537
import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor.EncodingType;
3638
import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor.JavaType;
@@ -118,34 +120,39 @@ private Object readLengthDelimitedField(
118120
return CelByteString.of(inputStream.readByteArray());
119121
case MESSAGE:
120122
return mergeOrReadMessageField(
121-
inputStream.readBytes(), fieldDescriptor.getFieldProtoTypeName(), existingValue);
123+
inputStream.readBytes(),
124+
fieldDescriptor.getFieldProtoTypeName(),
125+
existingValue,
126+
/* isView= */ true);
122127
case STRING:
123128
return inputStream.readStringRequireUtf8();
124129
default:
125130
throw new IllegalStateException("Unexpected field type: " + fieldType);
126131
}
127132
}
128133

134+
// Reads bytes of their own, not a view of another message's.
129135
private Object readMessageField(ByteString bytes, String fieldProtoTypeName) {
130-
return mergeOrReadMessageField(bytes, fieldProtoTypeName, /* existingValue= */ null);
136+
return mergeOrReadMessageField(
137+
bytes, fieldProtoTypeName, /* existingValue= */ null, /* isView= */ false);
131138
}
132139

133140
private Object mergeOrReadMessageField(
134-
ByteString bytes, String fieldProtoTypeName, @Nullable Object existingValue) {
141+
ByteString bytes, String fieldProtoTypeName, @Nullable Object existingValue, boolean isView) {
135142
MessageLiteDescriptor descriptor =
136143
descriptorPool.findDescriptor(fieldProtoTypeName).orElse(null);
137144
if (descriptor == null) {
138145
if (existingValue instanceof RawProtoMessageLiteValue) {
139146
bytes = ((RawProtoMessageLiteValue) existingValue).toByteString().concat(bytes);
140147
}
141-
return RawProtoMessageLiteValue.create(bytes, fieldProtoTypeName, this, /* isView= */ true);
148+
return RawProtoMessageLiteValue.create(bytes, fieldProtoTypeName, this, isView);
142149
}
143150
WellKnownProto wellKnownProto = WellKnownProto.getByTypeName(fieldProtoTypeName).orElse(null);
144151
if (isStructLike(wellKnownProto)) {
145152
if (existingValue instanceof ProtoMessageLiteValue) {
146153
bytes = ((ProtoMessageLiteValue) existingValue).toByteString().concat(bytes);
147154
}
148-
return ProtoMessageLiteValue.create(bytes, fieldProtoTypeName, this);
155+
return ProtoMessageLiteValue.create(bytes, descriptor, this);
149156
}
150157
if (existingValue instanceof MessageLite) {
151158
return mergeMessageLite(((MessageLite) existingValue).toBuilder(), bytes, fieldProtoTypeName);
@@ -169,18 +176,7 @@ private Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName,
169176
.flatMap(desc -> desc.findByFieldNumber(fieldNumber));
170177
}
171178

172-
Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName, String fieldName) {
173-
return descriptorPool
174-
.findDescriptor(protoTypeName)
175-
.flatMap(desc -> desc.findByFieldName(fieldName));
176-
}
177-
178-
MessageLite parseMessageLite(ByteString bytes, String protoTypeName) {
179-
MessageLiteDescriptor descriptor = descriptorPool.getDescriptorOrThrow(protoTypeName);
180-
return parseMessageLite(bytes, descriptor);
181-
}
182-
183-
private static MessageLite parseMessageLite(ByteString bytes, MessageLiteDescriptor descriptor) {
179+
static MessageLite parseMessageLite(ByteString bytes, MessageLiteDescriptor descriptor) {
184180
if (bytes.isEmpty()) {
185181
return descriptor.newMessageBuilder().getDefaultInstanceForType();
186182
}
@@ -216,7 +212,7 @@ private Object toRuntimeValue(MessageLite msg, MessageLiteDescriptor descriptor)
216212
WellKnownProto wellKnownProto =
217213
WellKnownProto.getByTypeName(descriptor.getProtoTypeName()).orElse(null);
218214
if (isStructLike(wellKnownProto)) {
219-
return ProtoMessageLiteValue.create(msg, descriptor.getProtoTypeName(), this);
215+
return ProtoMessageLiteValue.create(msg, descriptor, this);
220216
}
221217

222218
return fromWellKnownProto(msg, checkNotNull(wellKnownProto));
@@ -464,6 +460,120 @@ boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField fie
464460
return false;
465461
}
466462

463+
/**
464+
* Reads {@code fieldDescriptor} of {@code message} with its generated getter rather than from
465+
* wire bytes: its CEL value, null if it's absent, or {@link CelLiteDescriptor#NO_GETTER} if it
466+
* can't be read that way.
467+
*/
468+
@SuppressWarnings("ReferenceEquality") // NO_GETTER is a sentinel instance.
469+
@Nullable Object readFieldByGetter(
470+
ProtoMessageLiteValue message, FieldLiteDescriptor fieldDescriptor) {
471+
MessageLite msg = message.rawValue();
472+
if (msg == null) {
473+
return CelLiteDescriptor.NO_GETTER;
474+
}
475+
Object value = message.descriptor().getFieldValue(msg, fieldDescriptor.getFieldNumber());
476+
if (value == null || value == CelLiteDescriptor.NO_GETTER) {
477+
return value;
478+
}
479+
switch (fieldDescriptor.getEncodingType()) {
480+
case LIST:
481+
List<?> list = (List<?>) value;
482+
if (list.isEmpty()) {
483+
return null;
484+
}
485+
switch (fieldDescriptor.getProtoFieldType()) {
486+
case INT64:
487+
case SINT64:
488+
case SFIXED64:
489+
case DOUBLE:
490+
case BOOL:
491+
case STRING:
492+
// These elements are their own CEL values, so the immutable list needn't be copied.
493+
return CelPreAdaptedList.wrap(list);
494+
default:
495+
break;
496+
}
497+
ImmutableList.Builder<Object> listBuilder =
498+
ImmutableList.builderWithExpectedSize(list.size());
499+
for (int i = 0; i < list.size(); i++) {
500+
listBuilder.add(fromGetterValue(list.get(i), fieldDescriptor));
501+
}
502+
return listBuilder.build();
503+
case MAP:
504+
Map<?, ?> map = (Map<?, ?>) value;
505+
if (map.isEmpty()) {
506+
return null;
507+
}
508+
MessageLiteDescriptor entryDescriptor =
509+
descriptorPool.getDescriptorOrThrow(fieldDescriptor.getFieldProtoTypeName());
510+
FieldLiteDescriptor keyDescriptor =
511+
entryDescriptor.getByFieldNumberOrThrow(MAP_KEY_FIELD_NUMBER);
512+
FieldLiteDescriptor valueDescriptor =
513+
entryDescriptor.getByFieldNumberOrThrow(MAP_VALUE_FIELD_NUMBER);
514+
ImmutableMap.Builder<Object, Object> mapBuilder =
515+
ImmutableMap.builderWithExpectedSize(map.size());
516+
for (Map.Entry<?, ?> entry : map.entrySet()) {
517+
mapBuilder.put(
518+
fromGetterValue(entry.getKey(), keyDescriptor),
519+
fromGetterValue(entry.getValue(), valueDescriptor));
520+
}
521+
return mapBuilder.buildOrThrow();
522+
case SINGULAR:
523+
return fromGetterValue(value, fieldDescriptor);
524+
}
525+
throw new IllegalStateException(
526+
"Unexpected encoding type: " + fieldDescriptor.getEncodingType());
527+
}
528+
529+
/** Like {@link #hasFieldByNumber}, through the field's generated getter if it has one. */
530+
@SuppressWarnings("ReferenceEquality") // NO_GETTER is a sentinel instance.
531+
Object hasByGetter(ProtoMessageLiteValue message, SelectField field) {
532+
MessageLite msg = message.rawValue();
533+
if (msg == null) {
534+
return CelLiteDescriptor.NO_GETTER;
535+
}
536+
Object value = message.descriptor().getFieldValue(msg, field.fieldNumber());
537+
if (value == CelLiteDescriptor.NO_GETTER) {
538+
return value;
539+
}
540+
if (value instanceof List) {
541+
return !((List<?>) value).isEmpty();
542+
}
543+
if (value instanceof Map) {
544+
return !((Map<?, ?>) value).isEmpty();
545+
}
546+
return value != null;
547+
}
548+
549+
/** Converts a field's (or element's) Java value as returned by its getter to its CEL value. */
550+
private Object fromGetterValue(Object value, FieldLiteDescriptor fieldDescriptor) {
551+
switch (fieldDescriptor.getProtoFieldType()) {
552+
case UINT32:
553+
case FIXED32:
554+
return UnsignedLong.fromLongBits(Integer.toUnsignedLong((Integer) value));
555+
case UINT64:
556+
case FIXED64:
557+
return UnsignedLong.fromLongBits((Long) value);
558+
case ENUM:
559+
// Open enums are read as their numbers; closed ones as enum constants.
560+
return value instanceof Integer
561+
? ((Integer) value).longValue()
562+
: (long) ((EnumLite) value).getNumber();
563+
case MESSAGE:
564+
MessageLite message = (MessageLite) value;
565+
MessageLiteDescriptor descriptor = descriptorPool.findDescriptor(message).orElse(null);
566+
// A submessage whose class has no descriptor is read from its own bytes, not its root's:
567+
// by its type's descriptor if the pool has one for another class (such as an older
568+
// version of it), or else descriptorless.
569+
return descriptor != null
570+
? toRuntimeValue(message, descriptor)
571+
: readMessageField(message.toByteString(), fieldDescriptor.getFieldProtoTypeName());
572+
default:
573+
return super.toRuntimeValue(value);
574+
}
575+
}
576+
467577
/** Describes {@code field} by the type information it carries, built once and kept on it. */
468578
private static FieldLiteDescriptor newFieldDescriptor(SelectField field) {
469579
Object cached = field.liteFieldDescriptor();

‎common/src/main/java/dev/cel/common/values/ProtoMessageLiteValue.java‎

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
import dev.cel.common.exceptions.CelAttributeNotFoundException;
2525
import dev.cel.common.types.CelType;
2626
import dev.cel.common.types.StructTypeReference;
27+
import dev.cel.protobuf.CelLiteDescriptor;
2728
import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor;
29+
import dev.cel.protobuf.CelLiteDescriptor.MessageLiteDescriptor;
2830
import java.util.Objects;
2931
import java.util.Optional;
3032
import org.jspecify.annotations.Nullable;
@@ -66,20 +68,24 @@ abstract class ProtoMessageLiteValue extends StructValue<String, MessageLite>
6668
// re-serializing intermediate hops; lazily parsed into a MessageLite only if value() is called.
6769
abstract @Nullable ByteString wireBytes();
6870

69-
@Override
70-
public abstract CelType celType();
71+
abstract MessageLiteDescriptor descriptor();
7172

7273
abstract ProtoLiteCelValueConverter protoLiteCelValueConverter();
7374

75+
@Override
76+
public CelType celType() {
77+
// Built on demand, since one of these values is created on every hop but rarely asked its type.
78+
return StructTypeReference.create(descriptor().getProtoTypeName());
79+
}
80+
7481
@Memoized
7582
@Override
7683
public MessageLite value() {
7784
MessageLite msg = rawValue();
7885
if (msg != null) {
7986
return msg;
8087
}
81-
return protoLiteCelValueConverter()
82-
.parseMessageLite(checkNotNull(wireBytes()), celType().name());
88+
return ProtoLiteCelValueConverter.parseMessageLite(checkNotNull(wireBytes()), descriptor());
8389
}
8490

8591
@Memoized
@@ -110,80 +116,102 @@ public final boolean equals(Object other) {
110116
return false;
111117
}
112118
ProtoMessageLiteValue that = (ProtoMessageLiteValue) other;
113-
return this.celType().equals(that.celType()) && this.value().equals(that.value());
119+
return this.descriptor().getProtoTypeName().equals(that.descriptor().getProtoTypeName())
120+
&& this.value().equals(that.value());
114121
}
115122

116123
@Override
117124
public final int hashCode() {
118-
return Objects.hash(value(), celType());
125+
return Objects.hash(value(), descriptor().getProtoTypeName());
119126
}
120127

121128
@Override
122129
public Object select(String field) {
123-
FieldLiteDescriptor fd = findFieldDescriptor(field).orElse(null);
130+
FieldLiteDescriptor fd = descriptor().findByFieldName(field).orElse(null);
124131
if (fd == null) {
125132
throw CelAttributeNotFoundException.of(
126-
String.format("field '%s' is not declared in message '%s'", field, celType().name()));
133+
String.format(
134+
"field '%s' is not declared in message '%s'",
135+
field, descriptor().getProtoTypeName()));
127136
}
128137
Object fieldValue = readField(fd);
129138
return fieldValue != null ? fieldValue : protoLiteCelValueConverter().getDefaultCelValue(fd);
130139
}
131140

132141
@Override
133142
public Optional<Object> find(String field) {
134-
FieldLiteDescriptor fd = findFieldDescriptor(field).orElse(null);
135143
// Per SelectableValue#find, a field that doesn't exist is reported as absent.
136-
return Optional.ofNullable(fd).map(value -> readField(value));
144+
return descriptor().findByFieldName(field).map(this::readField);
137145
}
138146

147+
// An in-memory message is read through its descriptor's generated getters, falling back to its
148+
// wire bytes (which serializes it) only for fields without one, such as those unknown to its
149+
// descriptor. Other messages are read from their wire bytes.
150+
139151
@Override
140152
public Object selectByFieldNumber(SelectField field) {
141-
return protoLiteCelValueConverter()
142-
.selectByFieldNumber(toByteString(), celType().name(), field);
153+
FieldLiteDescriptor fd = descriptor().findByFieldNumber(field.fieldNumber()).orElse(null);
154+
if (fd == null) {
155+
return protoLiteCelValueConverter()
156+
.selectByFieldNumber(toByteString(), descriptor().getProtoTypeName(), field);
157+
}
158+
Object fieldValue = readField(fd);
159+
if (fieldValue != null) {
160+
return fieldValue;
161+
}
162+
return field.defaultValue() != null
163+
? field.defaultValue()
164+
: protoLiteCelValueConverter().getDefaultCelValue(fd);
143165
}
144166

145167
@Override
168+
@SuppressWarnings("ReferenceEquality") // NO_GETTER is a sentinel instance.
146169
public boolean hasFieldByNumber(SelectField field) {
147-
return protoLiteCelValueConverter().hasFieldByNumber(toByteString(), celType().name(), field);
170+
Object present = protoLiteCelValueConverter().hasByGetter(this, field);
171+
return present != CelLiteDescriptor.NO_GETTER
172+
? (Boolean) present
173+
: protoLiteCelValueConverter()
174+
.hasFieldByNumber(toByteString(), descriptor().getProtoTypeName(), field);
148175
}
149176

150177
@Override
151178
public Optional<Object> findByFieldNumber(SelectField field) {
152-
return protoLiteCelValueConverter().findByFieldNumber(toByteString(), celType().name(), field);
179+
FieldLiteDescriptor fd = descriptor().findByFieldNumber(field.fieldNumber()).orElse(null);
180+
return fd != null
181+
? Optional.ofNullable(readField(fd))
182+
: protoLiteCelValueConverter()
183+
.findByFieldNumber(toByteString(), descriptor().getProtoTypeName(), field);
153184
}
154185

186+
@SuppressWarnings("ReferenceEquality") // NO_GETTER is a sentinel instance.
155187
private @Nullable Object readField(FieldLiteDescriptor fd) {
156-
return protoLiteCelValueConverter().readField(toByteString(), celType().name(), fd);
157-
}
158-
159-
private Optional<FieldLiteDescriptor> findFieldDescriptor(String fieldName) {
160-
return protoLiteCelValueConverter().findFieldDescriptor(celType().name(), fieldName);
188+
Object value = protoLiteCelValueConverter().readFieldByGetter(this, fd);
189+
return value != CelLiteDescriptor.NO_GETTER
190+
? value
191+
: protoLiteCelValueConverter()
192+
.readField(toByteString(), descriptor().getProtoTypeName(), fd);
161193
}
162194

163195
static ProtoMessageLiteValue create(
164-
MessageLite value, String typeName, ProtoLiteCelValueConverter protoLiteCelValueConverter) {
196+
MessageLite value,
197+
MessageLiteDescriptor descriptor,
198+
ProtoLiteCelValueConverter protoLiteCelValueConverter) {
165199
checkNotNull(value);
166-
checkNotNull(typeName);
200+
checkNotNull(descriptor);
167201
checkNotNull(protoLiteCelValueConverter);
168202
return new AutoValue_ProtoMessageLiteValue(
169-
value,
170-
/* wireBytes= */ null,
171-
StructTypeReference.create(typeName),
172-
protoLiteCelValueConverter);
203+
value, /* wireBytes= */ null, descriptor, protoLiteCelValueConverter);
173204
}
174205

175206
static ProtoMessageLiteValue create(
176207
ByteString wireBytes,
177-
String typeName,
208+
MessageLiteDescriptor descriptor,
178209
ProtoLiteCelValueConverter protoLiteCelValueConverter) {
179210
checkNotNull(wireBytes);
180-
checkNotNull(typeName);
211+
checkNotNull(descriptor);
181212
checkNotNull(protoLiteCelValueConverter);
182213
return new AutoValue_ProtoMessageLiteValue(
183-
/* rawValue= */ null,
184-
wireBytes,
185-
StructTypeReference.create(typeName),
186-
protoLiteCelValueConverter);
214+
/* rawValue= */ null, wireBytes, descriptor, protoLiteCelValueConverter);
187215
}
188216

189217
ProtoMessageLiteValue() {}

0 commit comments

Comments
 (0)