Skip to content

Commit 2da42a4

Browse files
l46kokcopybara-github
authored andcommitted
Change name based lite field access to scan a single field
PiperOrigin-RevId: 996120916
1 parent 6aea2df commit 2da42a4

6 files changed

Lines changed: 198 additions & 153 deletions

File tree

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

Lines changed: 13 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,6 @@ private static boolean isStructLike(@Nullable WellKnownProto wellKnownProto) {
161161
return wellKnownProto == null || wellKnownProto == WellKnownProto.FIELD_MASK;
162162
}
163163

164-
Object getDefaultCelValue(String protoTypeName, String fieldName) {
165-
MessageLiteDescriptor messageDescriptor = descriptorPool.getDescriptorOrThrow(protoTypeName);
166-
return getDefaultCelValue(messageDescriptor.getByFieldNameOrThrow(fieldName));
167-
}
168-
169164
Object getDefaultCelValue(FieldLiteDescriptor fieldDescriptor) {
170165
return toRuntimeValue(getDefaultValue(fieldDescriptor));
171166
}
@@ -176,6 +171,12 @@ Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName, int fiel
176171
.flatMap(desc -> desc.findByFieldNumber(fieldNumber));
177172
}
178173

174+
Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName, String fieldName) {
175+
return descriptorPool
176+
.findDescriptor(protoTypeName)
177+
.flatMap(desc -> desc.findByFieldName(fieldName));
178+
}
179+
179180
MessageLite parseMessageLite(ByteString bytes, String protoTypeName) {
180181
MessageLiteDescriptor descriptor = descriptorPool.getDescriptorOrThrow(protoTypeName);
181182
return parseMessageLite(bytes, descriptor);
@@ -304,6 +305,11 @@ private Map.Entry<Object, Object> readSingleMapEntry(
304305
return new AbstractMap.SimpleImmutableEntry<>(key, value);
305306
}
306307

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+
*/
307313
@Nullable Object readSingleField(ByteString bytes, FieldLiteDescriptor fieldDescriptor)
308314
throws IOException {
309315
CodedInputStream inputStream = bytes.newCodedInput();
@@ -318,8 +324,6 @@ private Map.Entry<Object, Object> readSingleMapEntry(
318324
int tagWireType = WireFormat.getTagWireType(tag);
319325
fieldValue = readFieldValue(tagWireType, inputStream, fieldDescriptor, fieldValue);
320326
}
321-
// Only this field is decoded, so unlike readAllFields, a failed conversion can't affect access
322-
// to any other field.
323327
return fieldValue == null ? null : resolveFieldValue(finalizeFieldValue(fieldValue));
324328
}
325329

@@ -472,49 +476,8 @@ private static FieldLiteDescriptor newFieldDescriptor(
472476
protoTypeName);
473477
}
474478

475-
/**
476-
* Decodes every known field in {@code bytes}, keyed by field name. Each value must be passed to
477-
* {@link #resolveFieldValue} to obtain its CEL value.
478-
*/
479-
ImmutableMap<String, Object> readAllFields(ByteString bytes, String protoTypeName)
480-
throws IOException {
481-
MessageLiteDescriptor messageDescriptor = descriptorPool.getDescriptorOrThrow(protoTypeName);
482-
if (bytes.isEmpty()) {
483-
return ImmutableMap.of();
484-
}
485-
return readAllFields(bytes.newCodedInput(), messageDescriptor);
486-
}
487-
488-
private ImmutableMap<String, Object> readAllFields(
489-
CodedInputStream inputStream, MessageLiteDescriptor messageDescriptor) throws IOException {
490-
Map<String, Object> fieldValues = new LinkedHashMap<>();
491-
for (int tag = inputStream.readTag(); tag != 0; tag = inputStream.readTag()) {
492-
int tagWireType = WireFormat.getTagWireType(tag);
493-
int fieldNumber = WireFormat.getTagFieldNumber(tag);
494-
FieldLiteDescriptor fieldDescriptor =
495-
messageDescriptor.findByFieldNumber(fieldNumber).orElse(null);
496-
if (fieldDescriptor == null) {
497-
skipWireField(tag, inputStream);
498-
continue;
499-
}
500-
501-
String fieldName = fieldDescriptor.getFieldName();
502-
Object fieldValue =
503-
readFieldValue(tagWireType, inputStream, fieldDescriptor, fieldValues.get(fieldName));
504-
if (fieldValue != null) {
505-
fieldValues.put(fieldName, fieldValue);
506-
}
507-
}
508-
509-
fieldValues.replaceAll((fieldName, fieldValue) -> finalizeFieldValue(fieldValue));
510-
return ImmutableMap.copyOf(fieldValues);
511-
}
512-
513-
/**
514-
* Returns the CEL value of a field decoded by {@link #readAllFields}, completing any conversion
515-
* that was deferred.
516-
*/
517-
Object resolveFieldValue(Object fieldValue) {
479+
/** Returns the CEL value of a scanned field, completing any conversion that was deferred. */
480+
private Object resolveFieldValue(Object fieldValue) {
518481
if (fieldValue instanceof DeferredConversion) {
519482
return toRuntimeValue(((DeferredConversion) fieldValue).value);
520483
}

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

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818

1919
import com.google.auto.value.AutoValue;
2020
import com.google.auto.value.extension.memoized.Memoized;
21-
import com.google.common.collect.ImmutableMap;
2221
import com.google.errorprone.annotations.Immutable;
2322
import com.google.protobuf.ByteString;
2423
import com.google.protobuf.MessageLite;
24+
import dev.cel.common.exceptions.CelAttributeNotFoundException;
2525
import dev.cel.common.types.CelType;
2626
import dev.cel.common.types.StructTypeReference;
2727
import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor;
@@ -93,16 +93,6 @@ ByteString toByteString() {
9393
return bytes != null ? bytes : serializedRawValue();
9494
}
9595

96-
@Memoized
97-
ImmutableMap<String, Object> fieldValues() {
98-
try {
99-
return protoLiteCelValueConverter().readAllFields(toByteString(), celType().name());
100-
} catch (IOException e) {
101-
throw new IllegalArgumentException(
102-
"Failed to decode proto message of type: " + celType().name(), e);
103-
}
104-
}
105-
10696
@Override
10797
public boolean isZeroValue() {
10898
ByteString bytes = wireBytes();
@@ -131,28 +121,39 @@ public final int hashCode() {
131121

132122
@Override
133123
public Object select(String field) {
134-
return find(field)
135-
.orElseGet(() -> protoLiteCelValueConverter().getDefaultCelValue(celType().name(), field));
124+
Optional<FieldLiteDescriptor> fd = findFieldDescriptor(field);
125+
if (!fd.isPresent()) {
126+
throw CelAttributeNotFoundException.of(
127+
String.format("field '%s' is not declared in message '%s'", field, celType().name()));
128+
}
129+
Object fieldValue = readField(fd.get());
130+
return fieldValue != null
131+
? fieldValue
132+
: protoLiteCelValueConverter().getDefaultCelValue(fd.get());
136133
}
137134

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

144145
@Override
145146
public Object selectByFieldNumber(SelectField field) {
146-
FieldLiteDescriptor fd = findFieldDescriptor(field);
147-
if (fd != null) {
148-
Object known = readField(fd);
147+
Optional<FieldLiteDescriptor> fd = findFieldDescriptor(field);
148+
if (fd.isPresent()) {
149+
Object known = readField(fd.get());
149150
if (known != null) {
150151
return known;
151152
}
152153
if (field.defaultValue() != null) {
153154
return field.defaultValue();
154155
}
155-
return protoLiteCelValueConverter().getDefaultCelValue(fd);
156+
return protoLiteCelValueConverter().getDefaultCelValue(fd.get());
156157
}
157158
try {
158159
return protoLiteCelValueConverter().selectByFieldNumber(toByteString(), field);
@@ -164,9 +165,9 @@ public Object selectByFieldNumber(SelectField field) {
164165

165166
@Override
166167
public boolean hasFieldByNumber(SelectField field) {
167-
FieldLiteDescriptor fd = findFieldDescriptor(field);
168-
if (fd != null) {
169-
return hasField(fd);
168+
Optional<FieldLiteDescriptor> fd = findFieldDescriptor(field);
169+
if (fd.isPresent()) {
170+
return hasField(fd.get());
170171
}
171172
try {
172173
return protoLiteCelValueConverter().hasFieldByNumber(toByteString(), field);
@@ -178,9 +179,9 @@ public boolean hasFieldByNumber(SelectField field) {
178179

179180
@Override
180181
public Optional<Object> findByFieldNumber(SelectField field) {
181-
FieldLiteDescriptor fd = findFieldDescriptor(field);
182-
if (fd != null) {
183-
return Optional.ofNullable(readField(fd));
182+
Optional<FieldLiteDescriptor> fd = findFieldDescriptor(field);
183+
if (fd.isPresent()) {
184+
return Optional.ofNullable(readField(fd.get()));
184185
}
185186
try {
186187
return protoLiteCelValueConverter().findByFieldNumber(toByteString(), field);
@@ -208,10 +209,12 @@ private boolean hasField(FieldLiteDescriptor fd) {
208209
}
209210
}
210211

211-
private @Nullable FieldLiteDescriptor findFieldDescriptor(SelectField field) {
212-
return protoLiteCelValueConverter()
213-
.findFieldDescriptor(celType().name(), field.fieldNumber())
214-
.orElse(null);
212+
private Optional<FieldLiteDescriptor> findFieldDescriptor(SelectField field) {
213+
return protoLiteCelValueConverter().findFieldDescriptor(celType().name(), field.fieldNumber());
214+
}
215+
216+
private Optional<FieldLiteDescriptor> findFieldDescriptor(String fieldName) {
217+
return protoLiteCelValueConverter().findFieldDescriptor(celType().name(), fieldName);
215218
}
216219

217220
static ProtoMessageLiteValue create(

0 commit comments

Comments
 (0)