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 @@ -464,20 +464,29 @@ boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField fie
return false;
}

/** Describes {@code field} by the type information it carries. */
/** Describes {@code field} by the type information it carries, built once and kept on it. */
private static FieldLiteDescriptor newFieldDescriptor(SelectField field) {
Object cached = field.liteFieldDescriptor();
if (cached != null) {
return (FieldLiteDescriptor) cached;
}
// Only presence tests omit the type code: their presence check doesn't depend on the type, and
// the fields they navigate through are messages, as are map entries.
boolean isMap = field.mapEntrySpec() != null;
boolean isMessage = isMap || field.typeCode() == SelectField.NO_TYPE_CODE;
return newFieldDescriptor(
field.fieldNumber(),
field.fieldName(),
isMap
? EncodingType.MAP
: (field.defaultValue() instanceof List ? EncodingType.LIST : EncodingType.SINGULAR),
isMessage ? SelectField.MESSAGE_TYPE_CODE : field.typeCode(),
field.protoTypeName());
FieldLiteDescriptor fieldDescriptor =
newFieldDescriptor(
field.fieldNumber(),
field.fieldName(),
isMap
? EncodingType.MAP
: (field.defaultValue() instanceof List
? EncodingType.LIST
: EncodingType.SINGULAR),
isMessage ? SelectField.MESSAGE_TYPE_CODE : field.typeCode(),
field.protoTypeName());
field.setLiteFieldDescriptor(fieldDescriptor);
return fieldDescriptor;
}

private static FieldLiteDescriptor newFieldDescriptor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,17 @@ abstract class RawProtoMessageLiteValue extends StructValue<String, WireMessageL
public abstract ByteString toByteString();

@Override
public abstract CelType celType();
public abstract String protoTypeName();

abstract ProtoLiteCelValueConverter protoLiteCelValueConverter();

// Set when toByteString() may alias a parent message's buffer.
abstract boolean isView();

@Override
public String protoTypeName() {
return celType().name();
public CelType celType() {
// Built on demand, since one of these values is created on every hop but rarely asked its type.
return StructTypeReference.create(protoTypeName());
}

@Override
Expand Down Expand Up @@ -117,23 +118,22 @@ private CelAttributeNotFoundException newUnoptimizedFieldResolutionException(Str
String.format(
"Error resolving field '%s' on '%s'. Field selection by name is not supported on raw"
+ " proto wire bytes; register its CelLiteDescriptor or enable SelectOptimizer.",
field, celType().name()));
field, protoTypeName()));
}

@Override
public Object selectByFieldNumber(SelectField field) {
return protoLiteCelValueConverter()
.selectByFieldNumber(toByteString(), celType().name(), field);
return protoLiteCelValueConverter().selectByFieldNumber(toByteString(), protoTypeName(), field);
}

@Override
public boolean hasFieldByNumber(SelectField field) {
return protoLiteCelValueConverter().hasFieldByNumber(toByteString(), celType().name(), field);
return protoLiteCelValueConverter().hasFieldByNumber(toByteString(), protoTypeName(), field);
}

@Override
public Optional<Object> findByFieldNumber(SelectField field) {
return protoLiteCelValueConverter().findByFieldNumber(toByteString(), celType().name(), field);
return protoLiteCelValueConverter().findByFieldNumber(toByteString(), protoTypeName(), field);
}

static RawProtoMessageLiteValue create(
Expand All @@ -158,8 +158,7 @@ static RawProtoMessageLiteValue create(
checkNotNull(protoLiteCelValueConverter);
return new AutoValue_RawProtoMessageLiteValue(
rawWireBytes,
StructTypeReference.create(
protoTypeName.isEmpty() ? UNKNOWN_MESSAGE_TYPE_NAME : protoTypeName),
protoTypeName.isEmpty() ? UNKNOWN_MESSAGE_TYPE_NAME : protoTypeName,
protoLiteCelValueConverter,
isView);
}
Expand Down
16 changes: 15 additions & 1 deletion common/src/main/java/dev/cel/common/values/SelectField.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
@AutoValue
@AutoValue.CopyAnnotations
@Immutable
@SuppressWarnings("Immutable") // Default value is an immutable CEL literal or null
// Default value is an immutable CEL literal or null; liteFieldDescriptor is a memo of this field.
@SuppressWarnings("Immutable")
public abstract class SelectField {

private static final int MAX_FIELD_NUMBER = 536870911;
Expand Down Expand Up @@ -83,6 +84,19 @@ public abstract class SelectField {
*/
abstract @Nullable MapEntrySpec mapEntrySpec();

// The lite runtime's FieldLiteDescriptor for this field, built from this field alone on first
// use so descriptorless hops don't rebuild it. Typed Object to keep this target free of protobuf
// deps. A race at most rebuilds it, as the descriptor's fields are all final.
private @Nullable Object liteFieldDescriptor;

@Nullable Object liteFieldDescriptor() {
return liteFieldDescriptor;
}

void setLiteFieldDescriptor(Object liteFieldDescriptor) {
this.liteFieldDescriptor = liteFieldDescriptor;
}

/**
* Creates a presence-test qualifier hop.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,20 @@ public void selectByFieldNumber_presentOnWire_decoded() throws Exception {
assertThat(val).isEqualTo("hello");
}

@Test
public void selectByFieldNumber_twice_reusesFieldDescriptor() throws Exception {
RawProtoMessageLiteValue raw =
RawProtoMessageLiteValue.create(encode(out -> out.writeInt64(1, 42L)), EMPTY_CONVERTER);
SelectField field = SelectField.create(1L, "single_int64", 3, 0L);
raw.selectByFieldNumber(field);
Object fieldDescriptor = field.liteFieldDescriptor();

raw.selectByFieldNumber(field);

assertThat(fieldDescriptor).isNotNull();
assertThat(field.liteFieldDescriptor()).isSameInstanceAs(fieldDescriptor);
}

@Test
public void selectByFieldNumber_absentWithDefaultValue_returnsDefault() {
RawProtoMessageLiteValue raw =
Expand Down
Loading