Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,6 @@ private static boolean isStructLike(@Nullable WellKnownProto wellKnownProto) {
return wellKnownProto == null || wellKnownProto == WellKnownProto.FIELD_MASK;
}

Object getDefaultCelValue(String protoTypeName, String fieldName) {
MessageLiteDescriptor messageDescriptor = descriptorPool.getDescriptorOrThrow(protoTypeName);
return getDefaultCelValue(messageDescriptor.getByFieldNameOrThrow(fieldName));
}

Object getDefaultCelValue(FieldLiteDescriptor fieldDescriptor) {
return toRuntimeValue(getDefaultValue(fieldDescriptor));
}
Expand All @@ -176,6 +171,12 @@ Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName, int fiel
.flatMap(desc -> desc.findByFieldNumber(fieldNumber));
}

Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName, String fieldName) {
return descriptorPool
.findDescriptor(protoTypeName)
.flatMap(desc -> desc.findByFieldName(fieldName));
}

MessageLite parseMessageLite(ByteString bytes, String protoTypeName) {
MessageLiteDescriptor descriptor = descriptorPool.getDescriptorOrThrow(protoTypeName);
return parseMessageLite(bytes, descriptor);
Expand Down Expand Up @@ -304,6 +305,11 @@ private Map.Entry<Object, Object> readSingleMapEntry(
return new AbstractMap.SimpleImmutableEntry<>(key, value);
}

/**
* Decodes only {@code fieldDescriptor}'s occurrences in {@code bytes} into its CEL value,
* skipping every other field. Returns null if the field is absent (or a repeated field has only
* empty packed records on the wire).
*/
@Nullable Object readSingleField(ByteString bytes, FieldLiteDescriptor fieldDescriptor)
throws IOException {
CodedInputStream inputStream = bytes.newCodedInput();
Expand All @@ -318,8 +324,6 @@ private Map.Entry<Object, Object> readSingleMapEntry(
int tagWireType = WireFormat.getTagWireType(tag);
fieldValue = readFieldValue(tagWireType, inputStream, fieldDescriptor, fieldValue);
}
// Only this field is decoded, so unlike readAllFields, a failed conversion can't affect access
// to any other field.
return fieldValue == null ? null : resolveFieldValue(finalizeFieldValue(fieldValue));
}

Expand Down Expand Up @@ -472,49 +476,8 @@ private static FieldLiteDescriptor newFieldDescriptor(
protoTypeName);
}

/**
* Decodes every known field in {@code bytes}, keyed by field name. Each value must be passed to
* {@link #resolveFieldValue} to obtain its CEL value.
*/
ImmutableMap<String, Object> readAllFields(ByteString bytes, String protoTypeName)
throws IOException {
MessageLiteDescriptor messageDescriptor = descriptorPool.getDescriptorOrThrow(protoTypeName);
if (bytes.isEmpty()) {
return ImmutableMap.of();
}
return readAllFields(bytes.newCodedInput(), messageDescriptor);
}

private ImmutableMap<String, Object> readAllFields(
CodedInputStream inputStream, MessageLiteDescriptor messageDescriptor) throws IOException {
Map<String, Object> fieldValues = new LinkedHashMap<>();
for (int tag = inputStream.readTag(); tag != 0; tag = inputStream.readTag()) {
int tagWireType = WireFormat.getTagWireType(tag);
int fieldNumber = WireFormat.getTagFieldNumber(tag);
FieldLiteDescriptor fieldDescriptor =
messageDescriptor.findByFieldNumber(fieldNumber).orElse(null);
if (fieldDescriptor == null) {
skipWireField(tag, inputStream);
continue;
}

String fieldName = fieldDescriptor.getFieldName();
Object fieldValue =
readFieldValue(tagWireType, inputStream, fieldDescriptor, fieldValues.get(fieldName));
if (fieldValue != null) {
fieldValues.put(fieldName, fieldValue);
}
}

fieldValues.replaceAll((fieldName, fieldValue) -> finalizeFieldValue(fieldValue));
return ImmutableMap.copyOf(fieldValues);
}

/**
* Returns the CEL value of a field decoded by {@link #readAllFields}, completing any conversion
* that was deferred.
*/
Object resolveFieldValue(Object fieldValue) {
/** Returns the CEL value of a scanned field, completing any conversion that was deferred. */
private Object resolveFieldValue(Object fieldValue) {
if (fieldValue instanceof DeferredConversion) {
return toRuntimeValue(((DeferredConversion) fieldValue).value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@

import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.annotations.Immutable;
import com.google.protobuf.ByteString;
import com.google.protobuf.MessageLite;
import dev.cel.common.exceptions.CelAttributeNotFoundException;
import dev.cel.common.types.CelType;
import dev.cel.common.types.StructTypeReference;
import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor;
Expand Down Expand Up @@ -93,16 +93,6 @@ ByteString toByteString() {
return bytes != null ? bytes : serializedRawValue();
}

@Memoized
ImmutableMap<String, Object> fieldValues() {
try {
return protoLiteCelValueConverter().readAllFields(toByteString(), celType().name());
} catch (IOException e) {
throw new IllegalArgumentException(
"Failed to decode proto message of type: " + celType().name(), e);
}
}

@Override
public boolean isZeroValue() {
ByteString bytes = wireBytes();
Expand Down Expand Up @@ -131,28 +121,39 @@ public final int hashCode() {

@Override
public Object select(String field) {
return find(field)
.orElseGet(() -> protoLiteCelValueConverter().getDefaultCelValue(celType().name(), field));
Optional<FieldLiteDescriptor> fd = findFieldDescriptor(field);
if (!fd.isPresent()) {
throw CelAttributeNotFoundException.of(
String.format("field '%s' is not declared in message '%s'", field, celType().name()));
}
Object fieldValue = readField(fd.get());
return fieldValue != null
? fieldValue
: protoLiteCelValueConverter().getDefaultCelValue(fd.get());
}

@Override
public Optional<Object> find(String field) {
return Optional.ofNullable(fieldValues().get(field))
.map(protoLiteCelValueConverter()::resolveFieldValue);
Optional<FieldLiteDescriptor> fd = findFieldDescriptor(field);
if (!fd.isPresent()) {
// Per SelectableValue#find, a field that doesn't exist is reported as absent.
return Optional.empty();
}
return Optional.ofNullable(readField(fd.get()));
}

@Override
public Object selectByFieldNumber(SelectField field) {
FieldLiteDescriptor fd = findFieldDescriptor(field);
if (fd != null) {
Object known = readField(fd);
Optional<FieldLiteDescriptor> fd = findFieldDescriptor(field);
if (fd.isPresent()) {
Object known = readField(fd.get());
if (known != null) {
return known;
}
if (field.defaultValue() != null) {
return field.defaultValue();
}
return protoLiteCelValueConverter().getDefaultCelValue(fd);
return protoLiteCelValueConverter().getDefaultCelValue(fd.get());
}
try {
return protoLiteCelValueConverter().selectByFieldNumber(toByteString(), field);
Expand All @@ -164,9 +165,9 @@ public Object selectByFieldNumber(SelectField field) {

@Override
public boolean hasFieldByNumber(SelectField field) {
FieldLiteDescriptor fd = findFieldDescriptor(field);
if (fd != null) {
return hasField(fd);
Optional<FieldLiteDescriptor> fd = findFieldDescriptor(field);
if (fd.isPresent()) {
return hasField(fd.get());
}
try {
return protoLiteCelValueConverter().hasFieldByNumber(toByteString(), field);
Expand All @@ -178,9 +179,9 @@ public boolean hasFieldByNumber(SelectField field) {

@Override
public Optional<Object> findByFieldNumber(SelectField field) {
FieldLiteDescriptor fd = findFieldDescriptor(field);
if (fd != null) {
return Optional.ofNullable(readField(fd));
Optional<FieldLiteDescriptor> fd = findFieldDescriptor(field);
if (fd.isPresent()) {
return Optional.ofNullable(readField(fd.get()));
}
try {
return protoLiteCelValueConverter().findByFieldNumber(toByteString(), field);
Expand Down Expand Up @@ -208,10 +209,12 @@ private boolean hasField(FieldLiteDescriptor fd) {
}
}

private @Nullable FieldLiteDescriptor findFieldDescriptor(SelectField field) {
return protoLiteCelValueConverter()
.findFieldDescriptor(celType().name(), field.fieldNumber())
.orElse(null);
private Optional<FieldLiteDescriptor> findFieldDescriptor(SelectField field) {
return protoLiteCelValueConverter().findFieldDescriptor(celType().name(), field.fieldNumber());
}

private Optional<FieldLiteDescriptor> findFieldDescriptor(String fieldName) {
return protoLiteCelValueConverter().findFieldDescriptor(celType().name(), fieldName);
}

static ProtoMessageLiteValue create(
Expand Down
Loading
Loading