Skip to content

Commit 1e6e212

Browse files
l46kokcopybara-github
authored andcommitted
Keep each lite message's descriptor instead of building its CelType on every hop
PiperOrigin-RevId: 997600157
1 parent cb53abe commit 1e6e212

19 files changed

Lines changed: 902 additions & 203 deletions

‎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: 134 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
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;
@@ -118,34 +119,39 @@ private Object readLengthDelimitedField(
118119
return CelByteString.of(inputStream.readByteArray());
119120
case MESSAGE:
120121
return mergeOrReadMessageField(
121-
inputStream.readBytes(), fieldDescriptor.getFieldProtoTypeName(), existingValue);
122+
inputStream.readBytes(),
123+
fieldDescriptor.getFieldProtoTypeName(),
124+
existingValue,
125+
/* isView= */ true);
122126
case STRING:
123127
return inputStream.readStringRequireUtf8();
124128
default:
125129
throw new IllegalStateException("Unexpected field type: " + fieldType);
126130
}
127131
}
128132

133+
// Reads bytes of their own, not a view of another message's.
129134
private Object readMessageField(ByteString bytes, String fieldProtoTypeName) {
130-
return mergeOrReadMessageField(bytes, fieldProtoTypeName, /* existingValue= */ null);
135+
return mergeOrReadMessageField(
136+
bytes, fieldProtoTypeName, /* existingValue= */ null, /* isView= */ false);
131137
}
132138

133139
private Object mergeOrReadMessageField(
134-
ByteString bytes, String fieldProtoTypeName, @Nullable Object existingValue) {
140+
ByteString bytes, String fieldProtoTypeName, @Nullable Object existingValue, boolean isView) {
135141
MessageLiteDescriptor descriptor =
136142
descriptorPool.findDescriptor(fieldProtoTypeName).orElse(null);
137143
if (descriptor == null) {
138144
if (existingValue instanceof RawProtoMessageLiteValue) {
139145
bytes = ((RawProtoMessageLiteValue) existingValue).toByteString().concat(bytes);
140146
}
141-
return RawProtoMessageLiteValue.create(bytes, fieldProtoTypeName, this, /* isView= */ true);
147+
return RawProtoMessageLiteValue.create(bytes, fieldProtoTypeName, this, isView);
142148
}
143149
WellKnownProto wellKnownProto = WellKnownProto.getByTypeName(fieldProtoTypeName).orElse(null);
144150
if (isStructLike(wellKnownProto)) {
145151
if (existingValue instanceof ProtoMessageLiteValue) {
146152
bytes = ((ProtoMessageLiteValue) existingValue).toByteString().concat(bytes);
147153
}
148-
return ProtoMessageLiteValue.create(bytes, fieldProtoTypeName, this);
154+
return ProtoMessageLiteValue.create(bytes, descriptor, this);
149155
}
150156
if (existingValue instanceof MessageLite) {
151157
return mergeMessageLite(((MessageLite) existingValue).toBuilder(), bytes, fieldProtoTypeName);
@@ -163,24 +169,19 @@ Object getDefaultCelValue(FieldLiteDescriptor fieldDescriptor) {
163169
return toRuntimeValue(getDefaultValue(fieldDescriptor));
164170
}
165171

166-
private Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName, int fieldNumber) {
167-
return descriptorPool
168-
.findDescriptor(protoTypeName)
169-
.flatMap(desc -> desc.findByFieldNumber(fieldNumber));
172+
// A selected field's default value: the one in the SelectField, else its type's.
173+
Object getDefaultCelValue(SelectField field, FieldLiteDescriptor fieldDescriptor) {
174+
return field.defaultValue() != null
175+
? field.defaultValue()
176+
: getDefaultCelValue(fieldDescriptor);
170177
}
171178

172-
Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName, String fieldName) {
173-
return descriptorPool
174-
.findDescriptor(protoTypeName)
175-
.flatMap(desc -> desc.findByFieldName(fieldName));
179+
private @Nullable FieldLiteDescriptor findFieldDescriptor(String protoTypeName, int fieldNumber) {
180+
MessageLiteDescriptor descriptor = descriptorPool.findDescriptor(protoTypeName).orElse(null);
181+
return descriptor == null ? null : descriptor.findByFieldNumber(fieldNumber);
176182
}
177183

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) {
184+
static MessageLite parseMessageLite(ByteString bytes, MessageLiteDescriptor descriptor) {
184185
if (bytes.isEmpty()) {
185186
return descriptor.newMessageBuilder().getDefaultInstanceForType();
186187
}
@@ -216,7 +217,7 @@ private Object toRuntimeValue(MessageLite msg, MessageLiteDescriptor descriptor)
216217
WellKnownProto wellKnownProto =
217218
WellKnownProto.getByTypeName(descriptor.getProtoTypeName()).orElse(null);
218219
if (isStructLike(wellKnownProto)) {
219-
return ProtoMessageLiteValue.create(msg, descriptor.getProtoTypeName(), this);
220+
return ProtoMessageLiteValue.create(msg, descriptor, this);
220221
}
221222

222223
return fromWellKnownProto(msg, checkNotNull(wellKnownProto));
@@ -316,15 +317,8 @@ private Map.Entry<Object, Object> readSingleMapEntry(
316317
return scanField(bytes, protoTypeName, fieldDescriptor, null, null);
317318
}
318319

319-
/** Reads {@code field}, by its own type information if {@code fieldDescriptor} is null. */
320-
private @Nullable Object readField(
321-
ByteString bytes,
322-
String protoTypeName,
323-
@Nullable FieldLiteDescriptor fieldDescriptor,
324-
SelectField field) {
325-
if (fieldDescriptor != null) {
326-
return readField(bytes, protoTypeName, fieldDescriptor);
327-
}
320+
/** Reads {@code field} using the type information it carries. */
321+
private @Nullable Object readField(ByteString bytes, String protoTypeName, SelectField field) {
328322
SelectField.MapEntrySpec mapEntrySpec = field.mapEntrySpec();
329323
if (mapEntrySpec == null) {
330324
return readField(bytes, protoTypeName, newFieldDescriptor(field));
@@ -355,6 +349,9 @@ private Map.Entry<Object, Object> readSingleMapEntry(
355349
FieldLiteDescriptor fieldDescriptor,
356350
@Nullable FieldLiteDescriptor keyDescriptor,
357351
@Nullable FieldLiteDescriptor valueDescriptor) {
352+
if (fieldDescriptor.getProtoFieldType().equals(FieldLiteDescriptor.Type.GROUP)) {
353+
throw new UnsupportedOperationException("Groups are not supported");
354+
}
358355
CodedInputStream inputStream = bytes.newCodedInput();
359356
// Submessages alias bytes; unwrapping parses or copies them, so no view outlives evaluation.
360357
inputStream.enableAliasing(true);
@@ -400,40 +397,31 @@ private Map.Entry<Object, Object> readSingleMapEntry(
400397
}
401398

402399
/**
403-
* Selects {@code field} from {@code bytes}, decoding it by the type information in {@code field}
404-
* for fields missing from the descriptor pool. Returns the field's default value if it's absent.
400+
* Selects {@code field}, which its message's descriptor doesn't have, from {@code bytes} by the
401+
* type information it carries. Returns the field's default value if it's absent.
405402
*/
406403
Object selectByFieldNumber(ByteString bytes, String protoTypeName, SelectField field) {
407-
FieldLiteDescriptor fieldDescriptor =
408-
findFieldDescriptor(protoTypeName, field.fieldNumber()).orElse(null);
409-
Object fieldValue = readField(bytes, protoTypeName, fieldDescriptor, field);
410-
if (fieldValue != null) {
411-
return fieldValue;
412-
}
413-
if (field.defaultValue() != null) {
414-
return field.defaultValue();
415-
}
416-
return getDefaultCelValue(
417-
fieldDescriptor != null ? fieldDescriptor : newFieldDescriptor(field));
404+
Object fieldValue = readField(bytes, protoTypeName, field);
405+
return fieldValue != null ? fieldValue : getDefaultCelValue(field, newFieldDescriptor(field));
418406
}
419407

420408
/**
421-
* Finds {@code field} in {@code bytes}, decoding it by the type information in {@code field} for
422-
* fields missing from the descriptor pool. A field without a type code is decoded as a message.
409+
* Finds {@code field}, which its message's descriptor doesn't have, in {@code bytes} by the type
410+
* information it carries. A field without a type code is decoded as a message.
423411
*/
424412
Optional<Object> findByFieldNumber(ByteString bytes, String protoTypeName, SelectField field) {
425-
FieldLiteDescriptor fieldDescriptor =
426-
findFieldDescriptor(protoTypeName, field.fieldNumber()).orElse(null);
427-
return Optional.ofNullable(readField(bytes, protoTypeName, fieldDescriptor, field));
413+
return Optional.ofNullable(readField(bytes, protoTypeName, field));
428414
}
429415

430416
/** Returns whether {@code field} is present in {@code bytes}. */
431417
boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField field) {
432-
FieldLiteDescriptor fieldDescriptor =
433-
findFieldDescriptor(protoTypeName, field.fieldNumber()).orElse(null);
418+
FieldLiteDescriptor fieldDescriptor = findFieldDescriptor(protoTypeName, field.fieldNumber());
434419
if (fieldDescriptor == null) {
435420
fieldDescriptor = newFieldDescriptor(field);
436421
}
422+
if (fieldDescriptor.getProtoFieldType().equals(FieldLiteDescriptor.Type.GROUP)) {
423+
throw new UnsupportedOperationException("Groups are not supported");
424+
}
437425
boolean isPackableList =
438426
fieldDescriptor.getEncodingType().equals(EncodingType.LIST) && isPackable(fieldDescriptor);
439427
CodedInputStream inputStream = bytes.newCodedInput();
@@ -464,6 +452,103 @@ boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField fie
464452
return false;
465453
}
466454

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

0 commit comments

Comments
 (0)