Skip to content

Commit fca25fe

Browse files
l46kokcopybara-github
authored andcommitted
Support wrappers in select optimized ASTs
PiperOrigin-RevId: 995482415
1 parent fa4a240 commit fca25fe

14 files changed

Lines changed: 483 additions & 1346 deletions

File tree

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

Lines changed: 157 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import static com.google.common.base.Preconditions.checkNotNull;
1818

19+
import com.google.common.annotations.VisibleForTesting;
1920
import com.google.common.base.Defaults;
2021
import com.google.common.collect.ImmutableList;
2122
import com.google.common.collect.ImmutableMap;
@@ -29,6 +30,7 @@
2930
import com.google.protobuf.MessageLite;
3031
import com.google.protobuf.WireFormat;
3132
import dev.cel.common.annotations.Internal;
33+
import dev.cel.common.exceptions.CelAttributeNotFoundException;
3234
import dev.cel.common.internal.CelLiteDescriptorPool;
3335
import dev.cel.common.internal.WellKnownProto;
3436
import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor;
@@ -59,6 +61,8 @@
5961
public final class ProtoLiteCelValueConverter extends BaseProtoCelValueConverter {
6062
private static final String MAP_KEY_FIELD_NAME = "key";
6163
private static final String MAP_VALUE_FIELD_NAME = "value";
64+
private static final int MAP_KEY_FIELD_NUMBER = 1;
65+
private static final int MAP_VALUE_FIELD_NUMBER = 2;
6266

6367
private final CelLiteDescriptorPool descriptorPool;
6468

@@ -157,11 +161,6 @@ private static boolean isStructLike(@Nullable WellKnownProto wellKnownProto) {
157161
return wellKnownProto == null || wellKnownProto == WellKnownProto.FIELD_MASK;
158162
}
159163

160-
Object getDefaultCelValue(String protoTypeName, String fieldName) {
161-
MessageLiteDescriptor messageDescriptor = descriptorPool.getDescriptorOrThrow(protoTypeName);
162-
return getDefaultCelValue(messageDescriptor.getByFieldNameOrThrow(fieldName));
163-
}
164-
165164
Object getDefaultCelValue(FieldLiteDescriptor fieldDescriptor) {
166165
return toRuntimeValue(getDefaultValue(fieldDescriptor));
167166
}
@@ -172,6 +171,12 @@ Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName, int fiel
172171
.flatMap(desc -> desc.findByFieldNumber(fieldNumber));
173172
}
174173

174+
Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName, String fieldName) {
175+
return descriptorPool
176+
.findDescriptor(protoTypeName)
177+
.flatMap(desc -> desc.findByFieldName(fieldName));
178+
}
179+
175180
MessageLite parseMessageLite(ByteString bytes, String protoTypeName) {
176181
MessageLiteDescriptor descriptor = descriptorPool.getDescriptorOrThrow(protoTypeName);
177182
return parseMessageLite(bytes, descriptor);
@@ -194,21 +199,6 @@ private static MessageLite mergeMessageLite(
194199
}
195200
}
196201

197-
Optional<Object> tryDecodeProtoMessage(ByteString bytes, String protoTypeName) {
198-
return descriptorPool
199-
.findDescriptor(protoTypeName)
200-
.map(descriptor -> decodeProtoMessage(bytes, protoTypeName, descriptor));
201-
}
202-
203-
private Object decodeProtoMessage(
204-
ByteString bytes, String protoTypeName, MessageLiteDescriptor descriptor) {
205-
WellKnownProto wellKnownProto = WellKnownProto.getByTypeName(protoTypeName).orElse(null);
206-
if (isStructLike(wellKnownProto)) {
207-
return ProtoMessageLiteValue.create(bytes, protoTypeName, this);
208-
}
209-
return fromWellKnownProto(parseMessageLite(bytes, descriptor), checkNotNull(wellKnownProto));
210-
}
211-
212202
@Override
213203
public Object toRuntimeValue(Object value) {
214204
checkNotNull(value);
@@ -284,12 +274,10 @@ private Object getScalarDefaultValue(FieldLiteDescriptor fieldDescriptor) {
284274
}
285275

286276
private Map.Entry<Object, Object> readSingleMapEntry(
287-
CodedInputStream inputStream, FieldLiteDescriptor fieldDescriptor) throws IOException {
288-
String entryTypeName = fieldDescriptor.getFieldProtoTypeName();
289-
MessageLiteDescriptor entryDescriptor = descriptorPool.getDescriptorOrThrow(entryTypeName);
290-
FieldLiteDescriptor keyDescriptor = entryDescriptor.getByFieldNameOrThrow(MAP_KEY_FIELD_NAME);
291-
FieldLiteDescriptor valueDescriptor =
292-
entryDescriptor.getByFieldNameOrThrow(MAP_VALUE_FIELD_NAME);
277+
CodedInputStream inputStream,
278+
FieldLiteDescriptor keyDescriptor,
279+
FieldLiteDescriptor valueDescriptor)
280+
throws IOException {
293281
int length = inputStream.readInt32();
294282
int oldLimit = inputStream.pushLimit(length);
295283
Object key = null;
@@ -317,6 +305,11 @@ private Map.Entry<Object, Object> readSingleMapEntry(
317305
return new AbstractMap.SimpleImmutableEntry<>(key, value);
318306
}
319307

308+
/**
309+
* Decodes only {@code fieldDescriptor}'s occurrences in {@code bytes} into its CEL value,
310+
* skipping every other field. Returns null if the field is absent (or a repeated field has only
311+
* empty packed records on the wire).
312+
*/
320313
@Nullable Object readSingleField(ByteString bytes, FieldLiteDescriptor fieldDescriptor)
321314
throws IOException {
322315
CodedInputStream inputStream = bytes.newCodedInput();
@@ -331,20 +324,13 @@ private Map.Entry<Object, Object> readSingleMapEntry(
331324
int tagWireType = WireFormat.getTagWireType(tag);
332325
fieldValue = readFieldValue(tagWireType, inputStream, fieldDescriptor, fieldValue);
333326
}
334-
// Only this field is decoded, so unlike readAllFields, a failed conversion can't affect access
335-
// to any other field.
336327
return fieldValue == null ? null : resolveFieldValue(finalizeFieldValue(fieldValue));
337328
}
338329

339330
boolean hasSingleField(ByteString bytes, FieldLiteDescriptor fieldDescriptor) throws IOException {
340-
return hasSingleField(
341-
bytes,
342-
fieldDescriptor.getFieldNumber(),
343-
fieldDescriptor.getEncodingType().equals(EncodingType.LIST) && isPackable(fieldDescriptor));
344-
}
345-
346-
static boolean hasSingleField(ByteString bytes, int targetFieldNumber, boolean isPackableList)
347-
throws IOException {
331+
int targetFieldNumber = fieldDescriptor.getFieldNumber();
332+
boolean isPackableList =
333+
fieldDescriptor.getEncodingType().equals(EncodingType.LIST) && isPackable(fieldDescriptor);
348334
CodedInputStream inputStream = bytes.newCodedInput();
349335
for (int tag = inputStream.readTag(); tag != 0; tag = inputStream.readTag()) {
350336
int fieldNumber = WireFormat.getTagFieldNumber(tag);
@@ -371,48 +357,127 @@ static boolean hasSingleField(ByteString bytes, int targetFieldNumber, boolean i
371357
}
372358

373359
/**
374-
* Decodes every known field in {@code bytes}, keyed by field name. Each value must be passed to
375-
* {@link #resolveFieldValue} to obtain its CEL value.
360+
* Selects {@code field} from {@code bytes}, decoding it by the type information in {@code field}
361+
* for fields missing from the descriptor pool. Returns the field's default value if it's absent.
362+
* Throws {@link CelAttributeNotFoundException} if {@code field} has no type code.
376363
*/
377-
ImmutableMap<String, Object> readAllFields(ByteString bytes, String protoTypeName)
378-
throws IOException {
379-
MessageLiteDescriptor messageDescriptor = descriptorPool.getDescriptorOrThrow(protoTypeName);
380-
if (bytes.isEmpty()) {
381-
return ImmutableMap.of();
364+
Object selectByFieldNumber(ByteString bytes, SelectField field) throws IOException {
365+
if (field.typeCode() == SelectField.NO_TYPE_CODE) {
366+
throw CelAttributeNotFoundException.forFieldResolution(field.fieldName());
367+
}
368+
Object fieldValue = readFieldByNumber(bytes, field);
369+
if (fieldValue != null) {
370+
return fieldValue;
382371
}
383-
return readAllFields(bytes.newCodedInput(), messageDescriptor);
372+
if (field.defaultValue() != null) {
373+
return field.defaultValue();
374+
}
375+
return getDefaultCelValue(newFieldDescriptor(field));
376+
}
377+
378+
/**
379+
* Finds {@code field} in {@code bytes}, decoding it by the type information in {@code field} for
380+
* fields missing from the descriptor pool. A field without a type code is decoded as a message.
381+
*/
382+
Optional<Object> findByFieldNumber(ByteString bytes, SelectField field) throws IOException {
383+
return Optional.ofNullable(readFieldByNumber(bytes, field));
384+
}
385+
386+
/** Returns whether {@code field} is present in {@code bytes}. */
387+
boolean hasFieldByNumber(ByteString bytes, SelectField field) throws IOException {
388+
return hasSingleField(bytes, newFieldDescriptor(field));
384389
}
385390

386-
private ImmutableMap<String, Object> readAllFields(
387-
CodedInputStream inputStream, MessageLiteDescriptor messageDescriptor) throws IOException {
388-
Map<String, Object> fieldValues = new LinkedHashMap<>();
391+
private @Nullable Object readFieldByNumber(ByteString bytes, SelectField field)
392+
throws IOException {
393+
FieldLiteDescriptor fieldDescriptor = newFieldDescriptor(field);
394+
SelectField.MapEntrySpec mapEntrySpec = field.mapEntrySpec();
395+
if (mapEntrySpec == null) {
396+
return readSingleField(bytes, fieldDescriptor);
397+
}
398+
// The map entry type has no descriptor either, so its key and value are described by the spec.
399+
FieldLiteDescriptor keyDescriptor =
400+
newFieldDescriptor(
401+
MAP_KEY_FIELD_NUMBER,
402+
MAP_KEY_FIELD_NAME,
403+
EncodingType.SINGULAR,
404+
mapEntrySpec.keyTypeCode(),
405+
/* protoTypeName= */ "");
406+
FieldLiteDescriptor valueDescriptor =
407+
newFieldDescriptor(
408+
MAP_VALUE_FIELD_NUMBER,
409+
MAP_VALUE_FIELD_NAME,
410+
EncodingType.SINGULAR,
411+
mapEntrySpec.valueTypeCode(),
412+
field.protoTypeName());
413+
CodedInputStream inputStream = bytes.newCodedInput();
414+
Map<Object, Object> mapValues = null;
389415
for (int tag = inputStream.readTag(); tag != 0; tag = inputStream.readTag()) {
390-
int tagWireType = WireFormat.getTagWireType(tag);
391-
int fieldNumber = WireFormat.getTagFieldNumber(tag);
392-
FieldLiteDescriptor fieldDescriptor =
393-
messageDescriptor.findByFieldNumber(fieldNumber).orElse(null);
394-
if (fieldDescriptor == null) {
416+
if (WireFormat.getTagFieldNumber(tag) != field.fieldNumber()) {
395417
skipWireField(tag, inputStream);
396418
continue;
397419
}
398-
399-
String fieldName = fieldDescriptor.getFieldName();
400-
Object fieldValue =
401-
readFieldValue(tagWireType, inputStream, fieldDescriptor, fieldValues.get(fieldName));
402-
if (fieldValue != null) {
403-
fieldValues.put(fieldName, fieldValue);
404-
}
405-
}
406-
407-
fieldValues.replaceAll((fieldName, fieldValue) -> finalizeFieldValue(fieldValue));
408-
return ImmutableMap.copyOf(fieldValues);
409-
}
410-
411-
/**
412-
* Returns the CEL value of a field decoded by {@link #readAllFields}, completing any conversion
413-
* that was deferred.
414-
*/
415-
Object resolveFieldValue(Object fieldValue) {
420+
mapValues =
421+
readMapField(
422+
WireFormat.getTagWireType(tag),
423+
inputStream,
424+
fieldDescriptor,
425+
keyDescriptor,
426+
valueDescriptor,
427+
mapValues);
428+
}
429+
return mapValues == null ? null : resolveFieldValue(finalizeFieldValue(mapValues));
430+
}
431+
432+
/** Describes {@code field} by the type information it carries. */
433+
private static FieldLiteDescriptor newFieldDescriptor(SelectField field) {
434+
if (field.mapEntrySpec() != null) {
435+
// SelectField doesn't name the map entry type; its protoTypeName() is the map's value type.
436+
return newFieldDescriptor(
437+
field.fieldNumber(),
438+
field.fieldName(),
439+
EncodingType.MAP,
440+
SelectField.MESSAGE_TYPE_CODE,
441+
/* protoTypeName= */ "");
442+
}
443+
if (field.typeCode() == SelectField.NO_TYPE_CODE) {
444+
// Only presence tests omit the type code. Their presence check doesn't depend on the type,
445+
// and the fields they navigate through are always messages.
446+
return newFieldDescriptor(
447+
field.fieldNumber(),
448+
field.fieldName(),
449+
EncodingType.SINGULAR,
450+
SelectField.MESSAGE_TYPE_CODE,
451+
/* protoTypeName= */ "");
452+
}
453+
return newFieldDescriptor(
454+
field.fieldNumber(),
455+
field.fieldName(),
456+
field.defaultValue() instanceof List ? EncodingType.LIST : EncodingType.SINGULAR,
457+
field.typeCode(),
458+
field.protoTypeName());
459+
}
460+
461+
private static FieldLiteDescriptor newFieldDescriptor(
462+
int fieldNumber,
463+
String fieldName,
464+
EncodingType encodingType,
465+
int typeCode,
466+
String protoTypeName) {
467+
FieldLiteDescriptor.Type protoFieldType = FieldLiteDescriptor.Type.forNumber(typeCode);
468+
return new FieldLiteDescriptor(
469+
fieldNumber,
470+
fieldName,
471+
// FieldLiteDescriptor.JavaType's constants match WireFormat.JavaType's by name.
472+
JavaType.valueOf(protoFieldType.toWireFormatFieldType().getJavaType().name()),
473+
encodingType,
474+
protoFieldType,
475+
/* isPacked= */ false,
476+
protoTypeName);
477+
}
478+
479+
/** Returns the CEL value of a scanned field, completing any conversion that was deferred. */
480+
private Object resolveFieldValue(Object fieldValue) {
416481
if (fieldValue instanceof DeferredConversion) {
417482
return toRuntimeValue(((DeferredConversion) fieldValue).value);
418483
}
@@ -520,18 +585,38 @@ private Object readSingularField(
520585
return repeatedValues;
521586
}
522587

588+
private Map<Object, Object> readMapField(
589+
int tagWireType,
590+
CodedInputStream inputStream,
591+
FieldLiteDescriptor fieldDescriptor,
592+
@Nullable Object existingValue)
593+
throws IOException {
594+
MessageLiteDescriptor entryDescriptor =
595+
descriptorPool.getDescriptorOrThrow(fieldDescriptor.getFieldProtoTypeName());
596+
return readMapField(
597+
tagWireType,
598+
inputStream,
599+
fieldDescriptor,
600+
entryDescriptor.getByFieldNameOrThrow(MAP_KEY_FIELD_NAME),
601+
entryDescriptor.getByFieldNameOrThrow(MAP_VALUE_FIELD_NAME),
602+
existingValue);
603+
}
604+
523605
// Safe because MAP fields only ever store a LinkedHashMap as their accumulated value.
524606
@SuppressWarnings("unchecked")
525607
private Map<Object, Object> readMapField(
526608
int tagWireType,
527609
CodedInputStream inputStream,
528610
FieldLiteDescriptor fieldDescriptor,
611+
FieldLiteDescriptor keyDescriptor,
612+
FieldLiteDescriptor valueDescriptor,
529613
@Nullable Object existingValue)
530614
throws IOException {
531615
checkWireType(tagWireType, fieldDescriptor);
532616
Map<Object, Object> mapValues =
533617
existingValue != null ? (Map<Object, Object>) existingValue : new LinkedHashMap<>();
534-
Map.Entry<Object, Object> mapEntry = readSingleMapEntry(inputStream, fieldDescriptor);
618+
Map.Entry<Object, Object> mapEntry =
619+
readSingleMapEntry(inputStream, keyDescriptor, valueDescriptor);
535620
mapValues.put(mapEntry.getKey(), mapEntry.getValue());
536621
return mapValues;
537622
}
@@ -565,6 +650,7 @@ private static boolean isPackable(FieldLiteDescriptor fieldDescriptor) {
565650
return fieldDescriptor.getProtoFieldType().toWireFormatFieldType().isPackable();
566651
}
567652

653+
@VisibleForTesting
568654
static void skipWireField(int tag, CodedInputStream inputStream) throws IOException {
569655
int tagWireType = WireFormat.getTagWireType(tag);
570656
switch (tagWireType) {
@@ -582,25 +668,6 @@ static void skipWireField(int tag, CodedInputStream inputStream) throws IOExcept
582668
}
583669
}
584670

585-
static Object readUnknownField(int tagWireType, CodedInputStream inputStream) throws IOException {
586-
switch (tagWireType) {
587-
case WireFormat.WIRETYPE_VARINT:
588-
return inputStream.readInt64();
589-
case WireFormat.WIRETYPE_FIXED64:
590-
return inputStream.readFixed64();
591-
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
592-
return inputStream.readBytes();
593-
case WireFormat.WIRETYPE_FIXED32:
594-
return inputStream.readFixed32();
595-
case WireFormat.WIRETYPE_START_GROUP:
596-
case WireFormat.WIRETYPE_END_GROUP:
597-
// TODO: Support groups
598-
throw new UnsupportedOperationException("Groups are not supported");
599-
default:
600-
throw new IllegalArgumentException("Unknown wire type: " + tagWireType);
601-
}
602-
}
603-
604671
/**
605672
* A field value holding well-known type messages, whose conversion to CEL values is deferred
606673
* until {@link #resolveFieldValue}.

0 commit comments

Comments
 (0)