package com.fasterxml.jackson.dataformat.protobuf.schema;
import java.util.*;
import com.fasterxml.jackson.core.SerializableString;
import com.squareup.protoparser.FieldElement;
import com.squareup.protoparser.OptionElement;
public class ProtobufField
implements Comparable<ProtobufField>
{
public final int id;
public final int typedTag;
public final String name;
public final FieldType type;
public final int wireType;
public final boolean required, repeated, packed, deprecated;
public final boolean usesZigZag;
protected ProtobufMessage messageType;
protected final EnumLookup enumValues;
public ProtobufField next;
public final boolean isObject;
public final boolean isStdEnum;
public ProtobufField(FieldElement nativeField, FieldType type) {
this(nativeField, type, null, null);
}
public ProtobufField(FieldElement nativeField, ProtobufMessage msg) {
this(nativeField, FieldType.MESSAGE, msg, null);
}
public ProtobufField(FieldElement nativeField, ProtobufEnum et) {
this(nativeField, FieldType.ENUM, null, et);
}
public static ProtobufField unknownField() {
return new ProtobufField(null, FieldType.MESSAGE, null, null);
}
protected ProtobufField(FieldElement nativeField, FieldType type,
ProtobufMessage msg, ProtobufEnum et)
{
this.type = type;
wireType = type.getWireType();
usesZigZag = type.usesZigZag();
if (et == null) {
enumValues = EnumLookup.empty();
isStdEnum = false;
} else {
enumValues = EnumLookup.construct(et);
isStdEnum = et.usesStandardIndexing();
}
messageType = msg;
if (nativeField == null) {
typedTag = id = 0;
repeated = required = deprecated = packed = false;
name = "UNKNOWN";
} else {
id = nativeField.tag();
name = nativeField.name();
switch (nativeField.label()) {
case REPEATED:
required = false;
repeated = true;
break;
case REQUIRED:
required = true;
repeated = false;
break;
default:
required = repeated = false;
break;
}
packed = _findBooleanOption(nativeField, "packed");
deprecated = _findBooleanOption(nativeField, "deprecated");
if (repeated && packed) {
typedTag = (id << 3) + WireType.LENGTH_PREFIXED;
} else {
typedTag = (id << 3) + wireType;
}
}
isObject = (type == FieldType.MESSAGE);
}
private static boolean _findBooleanOption(FieldElement f, String key)
{
for (OptionElement opt : f.options()) {
if (key.equals(opt.name())) {
Object val = opt.value();
if (val instanceof Boolean) {
return ((Boolean) val).booleanValue();
}
return "true".equals(String.valueOf(val).trim());
}
}
return false;
}
public void assignMessageType(ProtobufMessage msgType) {
if (type != FieldType.MESSAGE) {
throw new IllegalStateException("Can not assign message type for non-message field '"+name+"'");
}
messageType = msgType;
}
public void assignNext(ProtobufField n) {
if (this.next != null) {
throw new IllegalStateException("Can not overwrite 'next' after being set");
}
this.next = n;
}
public final ProtobufMessage getMessageType() {
return messageType;
}
public final ProtobufField nextOrThisIf(int idToMatch) {
if ((next != null) && (next.id == idToMatch)) {
return next;
}
if (idToMatch == id) {
return this;
}
return null;
}
public final ProtobufField nextIf(String nameToMatch) {
if (next != null) {
if ((nameToMatch == next.name) || nameToMatch.equals(next.name)) {
return next;
}
}
return null;
}
public final int findEnumIndex(SerializableString key) {
return enumValues.findEnumIndex(key);
}
public final int findEnumIndex(String key) {
return enumValues.findEnumIndex(key);
}
public final String findEnumByIndex(int index) {
return enumValues.findEnumByIndex(index);
}
public Collection<String> getEnumValues() {
return enumValues.getEnumValues();
}
public final boolean isArray() {
return repeated;
}
public final boolean isValidFor(int typeTag) {
return (typeTag == wireType)
|| (packed && repeated && typeTag == WireType.LENGTH_PREFIXED);
}
@Override
public String toString()
{
return "Field '"+name+"', tag="+typedTag+", wireType="+wireType+", fieldType="+type;
}
@Override
public int compareTo(ProtobufField other) {
return id - other.id;
}
}