diff options
70 files changed, 5088 insertions, 1265 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 7cc10e12..2a86a63c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,8 +1,41 @@ -version 2.0.4: +????-??-?? version 2.0.4: + + General + * Repeated fields of primitive types (types other that string, group, and + nested messages) may now use the option [packed = true] to get a more + efficient encoding. In the new encoding, the entire list is written + as a single byte blob using the "length-delimited" wire type. Within + this blob, the individual values are encoded the same way they would + be normally except without a tag before each value (thus, they are + tightly "packed"). + + C++ + * UnknownFieldSet now supports STL-like iteration. + * Message interface has method ParseFromBoundedZeroCopyStream() which parses + a limited number of bytes from an input stream rather than parsing until + EOF. + + Java + * Fixed bug where Message.mergeFrom(Message) failed to merge extensions. + * Message interface has new method toBuilder() which is equivalent to + newBuilderForType().mergeFrom(this). + * All enums now implement the ProtocolMessageEnum interface. + * Setting a field to null now throws NullPointerException. + * Fixed tendency for TextFormat's parsing to overflow the stack when + parsing large string values. The underlying problem is with Java's + regex implementation (which unfortunately uses recursive backtracking + rather than building an NFA). Worked around by making use of possesive + quantifiers. Python * Added slicing support for repeated scalar fields. Added slice retrieval and removal of repeated composite fields. + * Updated RPC interfaces to allow for blocking operation. A client may + now pass None for a callback when making an RPC, in which case the + call will block until the response is received, and the response + object will be returned directly to the caller. This interface change + cannot be used in practice until RPC implementations are updated to + implement it. 2008-11-25 version 2.0.3: diff --git a/Makefile.am b/Makefile.am index c3d40b1f..b4ceacd4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,6 +45,7 @@ EXTRA_DIST = \ java/src/main/java/com/google/protobuf/GeneratedMessage.java \ java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \ java/src/main/java/com/google/protobuf/Message.java \ + java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java \ java/src/main/java/com/google/protobuf/RpcCallback.java \ java/src/main/java/com/google/protobuf/RpcChannel.java \ java/src/main/java/com/google/protobuf/RpcController.java \ diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java index 2f61859d..24c32a47 100644 --- a/java/src/main/java/com/google/protobuf/AbstractMessage.java +++ b/java/src/main/java/com/google/protobuf/AbstractMessage.java @@ -86,8 +86,25 @@ public abstract class AbstractMessage implements Message { for (Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) { FieldDescriptor field = entry.getKey(); if (field.isRepeated()) { - for (Object element : (List) entry.getValue()) { - output.writeField(field.getType(), field.getNumber(), element); + List valueList = (List) entry.getValue(); + if (field.getOptions().getPacked()) { + + output.writeTag(field.getNumber(), + WireFormat.WIRETYPE_LENGTH_DELIMITED); + int dataSize = 0; + for (Object element : valueList) { + dataSize += CodedOutputStream.computeFieldSizeNoTag( + field.getType(), element); + } + output.writeRawVarint32(dataSize); + + for (Object element : valueList) { + output.writeFieldNoTag(field.getType(), element); + } + } else { + for (Object element : valueList) { + output.writeField(field.getType(), field.getNumber(), element); + } } } else { output.writeField(field.getType(), field.getNumber(), entry.getValue()); @@ -145,9 +162,21 @@ public abstract class AbstractMessage implements Message { for (Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) { FieldDescriptor field = entry.getKey(); if (field.isRepeated()) { - for (Object element : (List) entry.getValue()) { - size += CodedOutputStream.computeFieldSize( - field.getType(), field.getNumber(), element); + List valueList = (List) entry.getValue(); + if (field.getOptions().getPacked()) { + int dataSize = 0; + for (Object element : valueList) { + dataSize += CodedOutputStream.computeFieldSizeNoTag( + field.getType(), element); + } + size += dataSize; + size += CodedOutputStream.computeTagSize(field.getNumber()); + size += CodedOutputStream.computeRawVarint32Size(dataSize); + } else { + for (Object element : valueList) { + size += CodedOutputStream.computeFieldSize( + field.getType(), field.getNumber(), element); + } } } else { size += CodedOutputStream.computeFieldSize( @@ -165,7 +194,7 @@ public abstract class AbstractMessage implements Message { memoizedSize = size; return size; } - + @Override public boolean equals(Object other) { if (other == this) { @@ -180,7 +209,7 @@ public abstract class AbstractMessage implements Message { } return getAllFields().equals(otherMessage.getAllFields()); } - + @Override public int hashCode() { int hash = 41; diff --git a/java/src/main/java/com/google/protobuf/CodedInputStream.java b/java/src/main/java/com/google/protobuf/CodedInputStream.java index caef068b..8f277a9f 100644 --- a/java/src/main/java/com/google/protobuf/CodedInputStream.java +++ b/java/src/main/java/com/google/protobuf/CodedInputStream.java @@ -193,7 +193,7 @@ public final class CodedInputStream { /** Read a {@code string} field value from the stream. */ public String readString() throws IOException { int size = readRawVarint32(); - if (size < bufferSize - bufferPos && size > 0) { + if (size <= (bufferSize - bufferPos) && size > 0) { // Fast path: We already have the bytes in a contiguous buffer, so // just copy directly from it. String result = new String(buffer, bufferPos, size, "UTF-8"); @@ -584,6 +584,19 @@ public final class CodedInputStream { } /** + * Returns the number of bytes to be read before the current limit. + * If no limit is set, returns -1. + */ + public int getBytesUntilLimit() { + if (currentLimit == Integer.MAX_VALUE) { + return -1; + } + + int currentAbsolutePosition = totalBytesRetired + bufferPos; + return currentLimit - currentAbsolutePosition; + } + + /** * Called with {@code this.buffer} is empty to read more bytes from the * input. If {@code mustSucceed} is true, refillBuffer() gurantees that * either there will be at least one byte in the buffer when it returns diff --git a/java/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/src/main/java/com/google/protobuf/CodedOutputStream.java index d232841a..e8be8611 100644 --- a/java/src/main/java/com/google/protobuf/CodedOutputStream.java +++ b/java/src/main/java/com/google/protobuf/CodedOutputStream.java @@ -118,71 +118,61 @@ public final class CodedOutputStream { /** Write a {@code double} field, including tag, to the stream. */ public void writeDouble(int fieldNumber, double value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); - writeRawLittleEndian64(Double.doubleToRawLongBits(value)); + writeDoubleNoTag(value); } /** Write a {@code float} field, including tag, to the stream. */ public void writeFloat(int fieldNumber, float value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); - writeRawLittleEndian32(Float.floatToRawIntBits(value)); + writeFloatNoTag(value); } /** Write a {@code uint64} field, including tag, to the stream. */ public void writeUInt64(int fieldNumber, long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeRawVarint64(value); + writeUInt64NoTag(value); } /** Write an {@code int64} field, including tag, to the stream. */ public void writeInt64(int fieldNumber, long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeRawVarint64(value); + writeInt64NoTag(value); } /** Write an {@code int32} field, including tag, to the stream. */ public void writeInt32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - if (value >= 0) { - writeRawVarint32(value); - } else { - // Must sign-extend. - writeRawVarint64(value); - } + writeInt32NoTag(value); } /** Write a {@code fixed64} field, including tag, to the stream. */ public void writeFixed64(int fieldNumber, long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); - writeRawLittleEndian64(value); + writeFixed64NoTag(value); } /** Write a {@code fixed32} field, including tag, to the stream. */ public void writeFixed32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); - writeRawLittleEndian32(value); + writeFixed32NoTag(value); } /** Write a {@code bool} field, including tag, to the stream. */ public void writeBool(int fieldNumber, boolean value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeRawByte(value ? 1 : 0); + writeBoolNoTag(value); } /** Write a {@code string} field, including tag, to the stream. */ public void writeString(int fieldNumber, String value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); - // Unfortunately there does not appear to be any way to tell Java to encode - // UTF-8 directly into our buffer, so we have to let it create its own byte - // array and then copy. - byte[] bytes = value.getBytes("UTF-8"); - writeRawVarint32(bytes.length); - writeRawBytes(bytes); + writeStringNoTag(value); } /** Write a {@code group} field, including tag, to the stream. */ public void writeGroup(int fieldNumber, Message value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); - value.writeTo(this); + writeGroupNoTag(value); writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); } @@ -190,29 +180,26 @@ public final class CodedOutputStream { public void writeUnknownGroup(int fieldNumber, UnknownFieldSet value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); - value.writeTo(this); + writeUnknownGroupNoTag(value); writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); } /** Write an embedded message field, including tag, to the stream. */ public void writeMessage(int fieldNumber, Message value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); - writeRawVarint32(value.getSerializedSize()); - value.writeTo(this); + writeMessageNoTag(value); } /** Write a {@code bytes} field, including tag, to the stream. */ public void writeBytes(int fieldNumber, ByteString value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); - byte[] bytes = value.toByteArray(); - writeRawVarint32(bytes.length); - writeRawBytes(bytes); + writeBytesNoTag(value); } /** Write a {@code uint32} field, including tag, to the stream. */ public void writeUInt32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeRawVarint32(value); + writeUInt32NoTag(value); } /** @@ -221,31 +208,31 @@ public final class CodedOutputStream { */ public void writeEnum(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeRawVarint32(value); + writeEnumNoTag(value); } /** Write an {@code sfixed32} field, including tag, to the stream. */ public void writeSFixed32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); - writeRawLittleEndian32(value); + writeSFixed32NoTag(value); } /** Write an {@code sfixed64} field, including tag, to the stream. */ public void writeSFixed64(int fieldNumber, long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); - writeRawLittleEndian64(value); + writeSFixed64NoTag(value); } /** Write an {@code sint32} field, including tag, to the stream. */ public void writeSInt32(int fieldNumber, int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeRawVarint32(encodeZigZag32(value)); + writeSInt32NoTag(value); } /** Write an {@code sint64} field, including tag, to the stream. */ public void writeSInt64(int fieldNumber, long value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeRawVarint64(encodeZigZag64(value)); + writeSInt64NoTag(value); } /** @@ -283,32 +270,168 @@ public final class CodedOutputStream { * this field. */ public void writeField(Descriptors.FieldDescriptor.Type type, - int number, Object value) throws IOException { + int number, + Object value) throws IOException { + // Special case for groups, which need a start and end tag; other fields + // can just use writeTag() and writeFieldNoTag(). + if (type == Descriptors.FieldDescriptor.Type.GROUP) { + writeGroup(number, (Message) value); + } else { + writeTag(number, WireFormat.getWireFormatForFieldType(type)); + writeFieldNoTag(type, value); + } + } + + /** + * Write a field of arbitrary type, without its tag, to the stream. + * + * @param type The field's type. + * @param value Object representing the field's value. Must be of the exact + * type which would be returned by + * {@link Message#getField(Descriptors.FieldDescriptor)} for + * this field. + */ + public void writeFieldNoTag(Descriptors.FieldDescriptor.Type type, + Object value) throws IOException { switch (type) { - case DOUBLE : writeDouble (number, (Double )value); break; - case FLOAT : writeFloat (number, (Float )value); break; - case INT64 : writeInt64 (number, (Long )value); break; - case UINT64 : writeUInt64 (number, (Long )value); break; - case INT32 : writeInt32 (number, (Integer )value); break; - case FIXED64 : writeFixed64 (number, (Long )value); break; - case FIXED32 : writeFixed32 (number, (Integer )value); break; - case BOOL : writeBool (number, (Boolean )value); break; - case STRING : writeString (number, (String )value); break; - case GROUP : writeGroup (number, (Message )value); break; - case MESSAGE : writeMessage (number, (Message )value); break; - case BYTES : writeBytes (number, (ByteString)value); break; - case UINT32 : writeUInt32 (number, (Integer )value); break; - case SFIXED32: writeSFixed32(number, (Integer )value); break; - case SFIXED64: writeSFixed64(number, (Long )value); break; - case SINT32 : writeSInt32 (number, (Integer )value); break; - case SINT64 : writeSInt64 (number, (Long )value); break; + case DOUBLE : writeDoubleNoTag ((Double ) value); break; + case FLOAT : writeFloatNoTag ((Float ) value); break; + case INT64 : writeInt64NoTag ((Long ) value); break; + case UINT64 : writeUInt64NoTag ((Long ) value); break; + case INT32 : writeInt32NoTag ((Integer ) value); break; + case FIXED64 : writeFixed64NoTag ((Long ) value); break; + case FIXED32 : writeFixed32NoTag ((Integer ) value); break; + case BOOL : writeBoolNoTag ((Boolean ) value); break; + case STRING : writeStringNoTag ((String ) value); break; + case GROUP : writeGroupNoTag ((Message ) value); break; + case MESSAGE : writeMessageNoTag ((Message ) value); break; + case BYTES : writeBytesNoTag ((ByteString) value); break; + case UINT32 : writeUInt32NoTag ((Integer ) value); break; + case SFIXED32: writeSFixed32NoTag((Integer ) value); break; + case SFIXED64: writeSFixed64NoTag((Long ) value); break; + case SINT32 : writeSInt32NoTag ((Integer ) value); break; + case SINT64 : writeSInt64NoTag ((Long ) value); break; case ENUM: - writeEnum(number, ((Descriptors.EnumValueDescriptor)value).getNumber()); + writeEnumNoTag(((Descriptors.EnumValueDescriptor) value).getNumber()); break; } } + // ----------------------------------------------------------------- + + /** Write a {@code double} field to the stream. */ + public void writeDoubleNoTag(double value) throws IOException { + writeRawLittleEndian64(Double.doubleToRawLongBits(value)); + } + + /** Write a {@code float} field to the stream. */ + public void writeFloatNoTag(float value) throws IOException { + writeRawLittleEndian32(Float.floatToRawIntBits(value)); + } + + /** Write a {@code uint64} field to the stream. */ + public void writeUInt64NoTag(long value) throws IOException { + writeRawVarint64(value); + } + + /** Write an {@code int64} field to the stream. */ + public void writeInt64NoTag(long value) throws IOException { + writeRawVarint64(value); + } + + /** Write an {@code int32} field to the stream. */ + public void writeInt32NoTag(int value) throws IOException { + if (value >= 0) { + writeRawVarint32(value); + } else { + // Must sign-extend. + writeRawVarint64(value); + } + } + + /** Write a {@code fixed64} field to the stream. */ + public void writeFixed64NoTag(long value) throws IOException { + writeRawLittleEndian64(value); + } + + /** Write a {@code fixed32} field to the stream. */ + public void writeFixed32NoTag(int value) throws IOException { + writeRawLittleEndian32(value); + } + + /** Write a {@code bool} field to the stream. */ + public void writeBoolNoTag(boolean value) throws IOException { + writeRawByte(value ? 1 : 0); + } + + /** Write a {@code string} field to the stream. */ + public void writeStringNoTag(String value) throws IOException { + // Unfortunately there does not appear to be any way to tell Java to encode + // UTF-8 directly into our buffer, so we have to let it create its own byte + // array and then copy. + byte[] bytes = value.getBytes("UTF-8"); + writeRawVarint32(bytes.length); + writeRawBytes(bytes); + } + + /** Write a {@code group} field to the stream. */ + public void writeGroupNoTag(Message value) throws IOException { + value.writeTo(this); + } + + /** Write a group represented by an {@link UnknownFieldSet}. */ + public void writeUnknownGroupNoTag(UnknownFieldSet value) + throws IOException { + value.writeTo(this); + } + + /** Write an embedded message field to the stream. */ + public void writeMessageNoTag(Message value) throws IOException { + writeRawVarint32(value.getSerializedSize()); + value.writeTo(this); + } + + /** Write a {@code bytes} field to the stream. */ + public void writeBytesNoTag(ByteString value) throws IOException { + byte[] bytes = value.toByteArray(); + writeRawVarint32(bytes.length); + writeRawBytes(bytes); + } + + /** Write a {@code uint32} field to the stream. */ + public void writeUInt32NoTag(int value) throws IOException { + writeRawVarint32(value); + } + + /** + * Write an enum field to the stream. Caller is responsible + * for converting the enum value to its numeric value. + */ + public void writeEnumNoTag(int value) throws IOException { + writeRawVarint32(value); + } + + /** Write an {@code sfixed32} field to the stream. */ + public void writeSFixed32NoTag(int value) throws IOException { + writeRawLittleEndian32(value); + } + + /** Write an {@code sfixed64} field to the stream. */ + public void writeSFixed64NoTag(long value) throws IOException { + writeRawLittleEndian64(value); + } + + /** Write an {@code sint32} field to the stream. */ + public void writeSInt32NoTag(int value) throws IOException { + writeRawVarint32(encodeZigZag32(value)); + } + + /** Write an {@code sint64} field to the stream. */ + public void writeSInt64NoTag(long value) throws IOException { + writeRawVarint64(encodeZigZag64(value)); + } + // ================================================================= /** @@ -316,7 +439,7 @@ public final class CodedOutputStream { * {@code double} field, including tag. */ public static int computeDoubleSize(int fieldNumber, double value) { - return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE; + return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value); } /** @@ -324,7 +447,7 @@ public final class CodedOutputStream { * {@code float} field, including tag. */ public static int computeFloatSize(int fieldNumber, float value) { - return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE; + return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value); } /** @@ -332,7 +455,7 @@ public final class CodedOutputStream { * {@code uint64} field, including tag. */ public static int computeUInt64Size(int fieldNumber, long value) { - return computeTagSize(fieldNumber) + computeRawVarint64Size(value); + return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value); } /** @@ -340,7 +463,7 @@ public final class CodedOutputStream { * {@code int64} field, including tag. */ public static int computeInt64Size(int fieldNumber, long value) { - return computeTagSize(fieldNumber) + computeRawVarint64Size(value); + return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value); } /** @@ -348,12 +471,7 @@ public final class CodedOutputStream { * {@code int32} field, including tag. */ public static int computeInt32Size(int fieldNumber, int value) { - if (value >= 0) { - return computeTagSize(fieldNumber) + computeRawVarint32Size(value); - } else { - // Must sign-extend. - return computeTagSize(fieldNumber) + 10; - } + return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value); } /** @@ -361,7 +479,7 @@ public final class CodedOutputStream { * {@code fixed64} field, including tag. */ public static int computeFixed64Size(int fieldNumber, long value) { - return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE; + return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value); } /** @@ -369,7 +487,7 @@ public final class CodedOutputStream { * {@code fixed32} field, including tag. */ public static int computeFixed32Size(int fieldNumber, int value) { - return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE; + return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value); } /** @@ -377,7 +495,7 @@ public final class CodedOutputStream { * {@code bool} field, including tag. */ public static int computeBoolSize(int fieldNumber, boolean value) { - return computeTagSize(fieldNumber) + 1; + return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value); } /** @@ -385,14 +503,7 @@ public final class CodedOutputStream { * {@code string} field, including tag. */ public static int computeStringSize(int fieldNumber, String value) { - try { - byte[] bytes = value.getBytes("UTF-8"); - return computeTagSize(fieldNumber) + - computeRawVarint32Size(bytes.length) + - bytes.length; - } catch (java.io.UnsupportedEncodingException e) { - throw new RuntimeException("UTF-8 not supported.", e); - } + return computeTagSize(fieldNumber) + computeStringSizeNoTag(value); } /** @@ -400,7 +511,7 @@ public final class CodedOutputStream { * {@code group} field, including tag. */ public static int computeGroupSize(int fieldNumber, Message value) { - return computeTagSize(fieldNumber) * 2 + value.getSerializedSize(); + return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value); } /** @@ -410,7 +521,8 @@ public final class CodedOutputStream { */ public static int computeUnknownGroupSize(int fieldNumber, UnknownFieldSet value) { - return computeTagSize(fieldNumber) * 2 + value.getSerializedSize(); + return computeTagSize(fieldNumber) * 2 + + computeUnknownGroupSizeNoTag(value); } /** @@ -418,8 +530,7 @@ public final class CodedOutputStream { * embedded message field, including tag. */ public static int computeMessageSize(int fieldNumber, Message value) { - int size = value.getSerializedSize(); - return computeTagSize(fieldNumber) + computeRawVarint32Size(size) + size; + return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value); } /** @@ -427,9 +538,7 @@ public final class CodedOutputStream { * {@code bytes} field, including tag. */ public static int computeBytesSize(int fieldNumber, ByteString value) { - return computeTagSize(fieldNumber) + - computeRawVarint32Size(value.size()) + - value.size(); + return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value); } /** @@ -437,7 +546,7 @@ public final class CodedOutputStream { * {@code uint32} field, including tag. */ public static int computeUInt32Size(int fieldNumber, int value) { - return computeTagSize(fieldNumber) + computeRawVarint32Size(value); + return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value); } /** @@ -446,7 +555,7 @@ public final class CodedOutputStream { * enum value to its numeric value. */ public static int computeEnumSize(int fieldNumber, int value) { - return computeTagSize(fieldNumber) + computeRawVarint32Size(value); + return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value); } /** @@ -454,7 +563,7 @@ public final class CodedOutputStream { * {@code sfixed32} field, including tag. */ public static int computeSFixed32Size(int fieldNumber, int value) { - return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE; + return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value); } /** @@ -462,7 +571,7 @@ public final class CodedOutputStream { * {@code sfixed64} field, including tag. */ public static int computeSFixed64Size(int fieldNumber, long value) { - return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE; + return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value); } /** @@ -470,8 +579,7 @@ public final class CodedOutputStream { * {@code sint32} field, including tag. */ public static int computeSInt32Size(int fieldNumber, int value) { - return computeTagSize(fieldNumber) + - computeRawVarint32Size(encodeZigZag32(value)); + return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value); } /** @@ -479,8 +587,7 @@ public final class CodedOutputStream { * {@code sint64} field, including tag. */ public static int computeSInt64Size(int fieldNumber, long value) { - return computeTagSize(fieldNumber) + - computeRawVarint64Size(encodeZigZag64(value)); + return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value); } /** @@ -507,6 +614,174 @@ public final class CodedOutputStream { computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value); } + // ----------------------------------------------------------------- + + /** + * Compute the number of bytes that would be needed to encode a + * {@code double} field, including tag. + */ + public static int computeDoubleSizeNoTag(double value) { + return LITTLE_ENDIAN_64_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code float} field, including tag. + */ + public static int computeFloatSizeNoTag(float value) { + return LITTLE_ENDIAN_32_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code uint64} field, including tag. + */ + public static int computeUInt64SizeNoTag(long value) { + return computeRawVarint64Size(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code int64} field, including tag. + */ + public static int computeInt64SizeNoTag(long value) { + return computeRawVarint64Size(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code int32} field, including tag. + */ + public static int computeInt32SizeNoTag(int value) { + if (value >= 0) { + return computeRawVarint32Size(value); + } else { + // Must sign-extend. + return 10; + } + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code fixed64} field. + */ + public static int computeFixed64SizeNoTag(long value) { + return LITTLE_ENDIAN_64_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code fixed32} field. + */ + public static int computeFixed32SizeNoTag(int value) { + return LITTLE_ENDIAN_32_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bool} field. + */ + public static int computeBoolSizeNoTag(boolean value) { + return 1; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code string} field. + */ + public static int computeStringSizeNoTag(String value) { + try { + byte[] bytes = value.getBytes("UTF-8"); + return computeRawVarint32Size(bytes.length) + + bytes.length; + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException("UTF-8 not supported.", e); + } + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code group} field. + */ + public static int computeGroupSizeNoTag(Message value) { + return value.getSerializedSize(); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code group} field represented by an {@code UnknownFieldSet}, including + * tag. + */ + public static int computeUnknownGroupSizeNoTag(UnknownFieldSet value) { + return value.getSerializedSize(); + } + + /** + * Compute the number of bytes that would be needed to encode an embedded + * message field. + */ + public static int computeMessageSizeNoTag(Message value) { + int size = value.getSerializedSize(); + return computeRawVarint32Size(size) + size; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bytes} field. + */ + public static int computeBytesSizeNoTag(ByteString value) { + return computeRawVarint32Size(value.size()) + + value.size(); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code uint32} field. + */ + public static int computeUInt32SizeNoTag(int value) { + return computeRawVarint32Size(value); + } + + /** + * Compute the number of bytes that would be needed to encode an enum field. + * Caller is responsible for converting the enum value to its numeric value. + */ + public static int computeEnumSizeNoTag(int value) { + return computeRawVarint32Size(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed32} field. + */ + public static int computeSFixed32SizeNoTag(int value) { + return LITTLE_ENDIAN_32_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed64} field. + */ + public static int computeSFixed64SizeNoTag(long value) { + return LITTLE_ENDIAN_64_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sint32} field. + */ + public static int computeSInt32SizeNoTag(int value) { + return computeRawVarint32Size(encodeZigZag32(value)); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sint64} field. + */ + public static int computeSInt64SizeNoTag(long value) { + return computeRawVarint64Size(encodeZigZag64(value)); + } + /** * Compute the number of bytes that would be needed to encode a * field of arbitrary type, including tag, to the stream. @@ -521,28 +796,48 @@ public final class CodedOutputStream { public static int computeFieldSize( Descriptors.FieldDescriptor.Type type, int number, Object value) { + int tagSize = computeTagSize(number); + if (type == Descriptors.FieldDescriptor.Type.GROUP) { + tagSize *= 2; + } + return tagSize + computeFieldSizeNoTag(type, value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * field of arbitrary type, excluding tag, to the stream. + * + * @param type The field's type. + * @param number The field's number. + * @param value Object representing the field's value. Must be of the exact + * type which would be returned by + * {@link Message#getField(Descriptors.FieldDescriptor)} for + * this field. + */ + public static int computeFieldSizeNoTag( + Descriptors.FieldDescriptor.Type type, Object value) { switch (type) { - case DOUBLE : return computeDoubleSize (number, (Double )value); - case FLOAT : return computeFloatSize (number, (Float )value); - case INT64 : return computeInt64Size (number, (Long )value); - case UINT64 : return computeUInt64Size (number, (Long )value); - case INT32 : return computeInt32Size (number, (Integer )value); - case FIXED64 : return computeFixed64Size (number, (Long )value); - case FIXED32 : return computeFixed32Size (number, (Integer )value); - case BOOL : return computeBoolSize (number, (Boolean )value); - case STRING : return computeStringSize (number, (String )value); - case GROUP : return computeGroupSize (number, (Message )value); - case MESSAGE : return computeMessageSize (number, (Message )value); - case BYTES : return computeBytesSize (number, (ByteString)value); - case UINT32 : return computeUInt32Size (number, (Integer )value); - case SFIXED32: return computeSFixed32Size(number, (Integer )value); - case SFIXED64: return computeSFixed64Size(number, (Long )value); - case SINT32 : return computeSInt32Size (number, (Integer )value); - case SINT64 : return computeSInt64Size (number, (Long )value); + case DOUBLE : return computeDoubleSizeNoTag ((Double )value); + case FLOAT : return computeFloatSizeNoTag ((Float )value); + case INT64 : return computeInt64SizeNoTag ((Long )value); + case UINT64 : return computeUInt64SizeNoTag ((Long )value); + case INT32 : return computeInt32SizeNoTag ((Integer )value); + case FIXED64 : return computeFixed64SizeNoTag ((Long )value); + case FIXED32 : return computeFixed32SizeNoTag ((Integer )value); + case BOOL : return computeBoolSizeNoTag ((Boolean )value); + case STRING : return computeStringSizeNoTag ((String )value); + case GROUP : return computeGroupSizeNoTag ((Message )value); + case MESSAGE : return computeMessageSizeNoTag ((Message )value); + case BYTES : return computeBytesSizeNoTag ((ByteString)value); + case UINT32 : return computeUInt32SizeNoTag ((Integer )value); + case SFIXED32: return computeSFixed32SizeNoTag((Integer )value); + case SFIXED64: return computeSFixed64SizeNoTag((Long )value); + case SINT32 : return computeSInt32SizeNoTag ((Integer )value); + case SINT64 : return computeSInt64SizeNoTag ((Long )value); case ENUM: - return computeEnumSize(number, - ((Descriptors.EnumValueDescriptor)value).getNumber()); + return computeEnumSizeNoTag( + ((Descriptors.EnumValueDescriptor)value).getNumber()); } throw new RuntimeException( diff --git a/java/src/main/java/com/google/protobuf/Descriptors.java b/java/src/main/java/com/google/protobuf/Descriptors.java index ee4d4e3a..80266a59 100644 --- a/java/src/main/java/com/google/protobuf/Descriptors.java +++ b/java/src/main/java/com/google/protobuf/Descriptors.java @@ -857,6 +857,19 @@ public final class Descriptors { "Field numbers must be positive integers."); } + // Only repeated primitive fields may be packed. + if (proto.getOptions().getPacked()) { + if (proto.getLabel() != FieldDescriptorProto.Label.LABEL_REPEATED || + proto.getType() == FieldDescriptorProto.Type.TYPE_STRING || + proto.getType() == FieldDescriptorProto.Type.TYPE_GROUP || + proto.getType() == FieldDescriptorProto.Type.TYPE_MESSAGE || + proto.getType() == FieldDescriptorProto.Type.TYPE_BYTES) { + throw new DescriptorValidationException(this, + "[packed = true] can only be specified for repeated primitive " + + "fields."); + } + } + if (isExtension) { if (!proto.hasExtendee()) { throw new DescriptorValidationException(this, diff --git a/java/src/main/java/com/google/protobuf/DynamicMessage.java b/java/src/main/java/com/google/protobuf/DynamicMessage.java index fefa23ec..99ae253c 100644 --- a/java/src/main/java/com/google/protobuf/DynamicMessage.java +++ b/java/src/main/java/com/google/protobuf/DynamicMessage.java @@ -211,6 +211,10 @@ public final class DynamicMessage extends AbstractMessage { return new Builder(type); } + public Builder toBuilder() { + return newBuilderForType().mergeFrom(this); + } + /** Verifies that the field is a field of this message. */ private void verifyContainingType(FieldDescriptor field) { if (field.getContainingType() != type) { @@ -251,6 +255,7 @@ public final class DynamicMessage extends AbstractMessage { } fields.mergeFrom(other); + mergeUnknownFields(other.getUnknownFields()); return this; } diff --git a/java/src/main/java/com/google/protobuf/FieldSet.java b/java/src/main/java/com/google/protobuf/FieldSet.java index 98a1c328..01da3faf 100644 --- a/java/src/main/java/com/google/protobuf/FieldSet.java +++ b/java/src/main/java/com/google/protobuf/FieldSet.java @@ -351,8 +351,7 @@ final class FieldSet { setField(field, entry.getValue()); } else { setField(field, - existingValue.newBuilderForType() - .mergeFrom(existingValue) + existingValue.toBuilder() .mergeFrom((Message)entry.getValue()) .build()); } @@ -384,8 +383,7 @@ final class FieldSet { setField(field, value); } else { setField(field, - existingValue.newBuilderForType() - .mergeFrom(existingValue) + existingValue.toBuilder() .mergeFrom((Message)value) .build()); } @@ -463,60 +461,83 @@ final class FieldSet { } if (field == null || - wireType != WireFormat.getWireFormatForFieldType(field.getType())) { + wireType != WireFormat.getWireFormatForField(field)) { // Unknown field or wrong wire type. Skip. return unknownFields.mergeFieldFrom(tag, input); } else { - Object value; - switch (field.getType()) { - case GROUP: { - Message.Builder subBuilder; - if (defaultInstance != null) { - subBuilder = defaultInstance.newBuilderForType(); - } else { - subBuilder = builder.newBuilderForField(field); + if (field.getOptions().getPacked()) { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (field.getType() == FieldDescriptor.Type.ENUM) { + while (input.getBytesUntilLimit() > 0) { + int rawValue = input.readEnum(); + Object value = field.getEnumType().findValueByNumber(rawValue); + if (value == null) { + // If the number isn't recognized as a valid value for this + // enum, drop it (don't even add it to unknownFields). + return true; + } + builder.addRepeatedField(field, value); } - if (!field.isRepeated()) { - subBuilder.mergeFrom((Message) builder.getField(field)); + } else { + while (input.getBytesUntilLimit() > 0) { + Object value = input.readPrimitiveField(field.getType()); + builder.addRepeatedField(field, value); } - input.readGroup(field.getNumber(), subBuilder, extensionRegistry); - value = subBuilder.build(); - break; } - case MESSAGE: { - Message.Builder subBuilder; - if (defaultInstance != null) { - subBuilder = defaultInstance.newBuilderForType(); - } else { - subBuilder = builder.newBuilderForField(field); + input.popLimit(limit); + } else { + Object value; + switch (field.getType()) { + case GROUP: { + Message.Builder subBuilder; + if (defaultInstance != null) { + subBuilder = defaultInstance.newBuilderForType(); + } else { + subBuilder = builder.newBuilderForField(field); + } + if (!field.isRepeated()) { + subBuilder.mergeFrom((Message) builder.getField(field)); + } + input.readGroup(field.getNumber(), subBuilder, extensionRegistry); + value = subBuilder.build(); + break; } - if (!field.isRepeated()) { - subBuilder.mergeFrom((Message) builder.getField(field)); + case MESSAGE: { + Message.Builder subBuilder; + if (defaultInstance != null) { + subBuilder = defaultInstance.newBuilderForType(); + } else { + subBuilder = builder.newBuilderForField(field); + } + if (!field.isRepeated()) { + subBuilder.mergeFrom((Message) builder.getField(field)); + } + input.readMessage(subBuilder, extensionRegistry); + value = subBuilder.build(); + break; } - input.readMessage(subBuilder, extensionRegistry); - value = subBuilder.build(); - break; - } - case ENUM: { - int rawValue = input.readEnum(); - value = field.getEnumType().findValueByNumber(rawValue); - // If the number isn't recognized as a valid value for this enum, - // drop it. - if (value == null) { - unknownFields.mergeVarintField(fieldNumber, rawValue); - return true; + case ENUM: { + int rawValue = input.readEnum(); + value = field.getEnumType().findValueByNumber(rawValue); + // If the number isn't recognized as a valid value for this enum, + // drop it. + if (value == null) { + unknownFields.mergeVarintField(fieldNumber, rawValue); + return true; + } + break; } - break; + default: + value = input.readPrimitiveField(field.getType()); + break; } - default: - value = input.readPrimitiveField(field.getType()); - break; - } - if (field.isRepeated()) { - builder.addRepeatedField(field, value); - } else { - builder.setField(field, value); + if (field.isRepeated()) { + builder.addRepeatedField(field, value); + } else { + builder.setField(field, value); + } } } @@ -636,8 +657,24 @@ final class FieldSet { output.writeMessageSetExtension(field.getNumber(), (Message)value); } else { if (field.isRepeated()) { - for (Object element : (List)value) { - output.writeField(field.getType(), field.getNumber(), element); + List valueList = (List)value; + if (field.getOptions().getPacked()) { + output.writeTag(field.getNumber(), + WireFormat.WIRETYPE_LENGTH_DELIMITED); + // Compute the total data size so the length can be written. + int dataSize = 0; + for (Object element : valueList) { + dataSize += output.computeFieldSizeNoTag(field.getType(), element); + } + output.writeRawVarint32(dataSize); + // Write the data itself, without any tags. + for (Object element : valueList) { + output.writeFieldNoTag(field.getType(), element); + } + } else { + for (Object element : valueList) { + output.writeField(field.getType(), field.getNumber(), element); + } } } else { output.writeField(field.getType(), field.getNumber(), value); @@ -658,12 +695,23 @@ final class FieldSet { if (field.isExtension() && field.getContainingType().getOptions().getMessageSetWireFormat()) { size += CodedOutputStream.computeMessageSetExtensionSize( - field.getNumber(), (Message)value); + field.getNumber(), (Message) value); } else { if (field.isRepeated()) { - for (Object element : (List)value) { - size += CodedOutputStream.computeFieldSize( - field.getType(), field.getNumber(), element); + if (field.getOptions().getPacked()) { + int dataSize = 0; + for (Object element : (List)value) { + dataSize += CodedOutputStream.computeFieldSizeNoTag( + field.getType(), element); + } + size += dataSize + + CodedOutputStream.computeTagSize(field.getNumber()) + + CodedOutputStream.computeRawVarint32Size(dataSize); + } else { + for (Object element : (List)value) { + size += CodedOutputStream.computeFieldSize( + field.getType(), field.getNumber(), element); + } } } else { size += CodedOutputStream.computeFieldSize( diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/src/main/java/com/google/protobuf/GeneratedMessage.java index b1be8b14..77c88c30 100644 --- a/java/src/main/java/com/google/protobuf/GeneratedMessage.java +++ b/java/src/main/java/com/google/protobuf/GeneratedMessage.java @@ -31,8 +31,8 @@ package com.google.protobuf; import com.google.protobuf.Descriptors.Descriptor; -import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.EnumValueDescriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; import java.io.IOException; import java.lang.reflect.Method; @@ -75,7 +75,7 @@ public abstract class GeneratedMessage extends AbstractMessage { Descriptor descriptor = internalGetFieldAccessorTable().descriptor; for (FieldDescriptor field : descriptor.getFields()) { if (field.isRepeated()) { - List value = (List)getField(field); + List value = (List) getField(field); if (!value.isEmpty()) { result.put(field, value); } @@ -87,7 +87,7 @@ public abstract class GeneratedMessage extends AbstractMessage { } return result; } - + public boolean isInitialized() { for (FieldDescriptor field : getDescriptorForType().getFields()) { // Check that all required fields are present. @@ -99,7 +99,9 @@ public abstract class GeneratedMessage extends AbstractMessage { // Check that embedded messages are initialized. if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { if (field.isRepeated()) { - for (Message element : (List<Message>) getField(field)) { + @SuppressWarnings("unchecked") + List<Message> messageList = (List<Message>) getField(field); + for (Message element : messageList) { if (!element.isInitialized()) { return false; } @@ -189,7 +191,7 @@ public abstract class GeneratedMessage extends AbstractMessage { setField(field, entry.getValue()); } } - return (BuilderType)this; + return (BuilderType) this; } public Descriptor getDescriptorForType() { @@ -214,7 +216,7 @@ public abstract class GeneratedMessage extends AbstractMessage { // The underlying list object is still modifiable at this point. // Make sure not to expose the modifiable list to the caller. return Collections.unmodifiableList( - (List)internalGetResult().getField(field)); + (List) internalGetResult().getField(field)); } else { return internalGetResult().getField(field); } @@ -223,12 +225,12 @@ public abstract class GeneratedMessage extends AbstractMessage { public BuilderType setField(Descriptors.FieldDescriptor field, Object value) { internalGetFieldAccessorTable().getField(field).set(this, value); - return (BuilderType)this; + return (BuilderType) this; } public BuilderType clearField(Descriptors.FieldDescriptor field) { internalGetFieldAccessorTable().getField(field).clear(this); - return (BuilderType)this; + return (BuilderType) this; } public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) { @@ -244,13 +246,13 @@ public abstract class GeneratedMessage extends AbstractMessage { int index, Object value) { internalGetFieldAccessorTable().getField(field) .setRepeated(this, index, value); - return (BuilderType)this; + return (BuilderType) this; } public BuilderType addRepeatedField(Descriptors.FieldDescriptor field, Object value) { internalGetFieldAccessorTable().getField(field).addRepeated(this, value); - return (BuilderType)this; + return (BuilderType) this; } public final UnknownFieldSet getUnknownFields() { @@ -259,7 +261,7 @@ public abstract class GeneratedMessage extends AbstractMessage { public final BuilderType setUnknownFields(UnknownFieldSet unknownFields) { internalGetResult().unknownFields = unknownFields; - return (BuilderType)this; + return (BuilderType) this; } public final BuilderType mergeUnknownFields(UnknownFieldSet unknownFields) { @@ -268,7 +270,7 @@ public abstract class GeneratedMessage extends AbstractMessage { UnknownFieldSet.newBuilder(result.unknownFields) .mergeFrom(unknownFields) .build(); - return (BuilderType)this; + return (BuilderType) this; } public boolean isInitialized() { @@ -287,7 +289,18 @@ public abstract class GeneratedMessage extends AbstractMessage { return unknownFields.mergeFieldFrom(tag, input); } + /** + * Adds the {@code values} to the {@code list}. + * + * @throws NullPointerException if any of the elements of {@code values} is + * null. + */ protected <T> void addAll(Iterable<T> values, Collection<? super T> list) { + for (T value : values) { + if (value == null) { + throw new NullPointerException(); + } + } if (values instanceof Collection) { @SuppressWarnings("unsafe") Collection<T> collection = (Collection<T>) values; @@ -378,9 +391,9 @@ public abstract class GeneratedMessage extends AbstractMessage { verifyExtensionContainingType(extension); Object value = extensions.getField(extension.getDescriptor()); if (value == null) { - return (Type)extension.getMessageDefaultInstance(); + return (Type) extension.getMessageDefaultInstance(); } else { - return (Type)extension.fromReflectionType(value); + return (Type) extension.fromReflectionType(value); } } @@ -389,7 +402,7 @@ public abstract class GeneratedMessage extends AbstractMessage { public final <Type> Type getExtension( GeneratedExtension<MessageType, List<Type>> extension, int index) { verifyExtensionContainingType(extension); - return (Type)extension.singularFromReflectionType( + return (Type) extension.singularFromReflectionType( extensions.getRepeatedField(extension.getDescriptor(), index)); } @@ -397,7 +410,7 @@ public abstract class GeneratedMessage extends AbstractMessage { protected boolean extensionsAreInitialized() { return extensions.isInitialized(); } - + public boolean isInitialized() { return super.isInitialized() && extensionsAreInitialized(); } @@ -580,7 +593,7 @@ public abstract class GeneratedMessage extends AbstractMessage { message.verifyExtensionContainingType(extension); message.extensions.setField(extension.getDescriptor(), extension.toReflectionType(value)); - return (BuilderType)this; + return (BuilderType) this; } /** Set the value of one element of a repeated extension. */ @@ -592,7 +605,7 @@ public abstract class GeneratedMessage extends AbstractMessage { message.extensions.setRepeatedField( extension.getDescriptor(), index, extension.singularToReflectionType(value)); - return (BuilderType)this; + return (BuilderType) this; } /** Append a value to a repeated extension. */ @@ -602,7 +615,7 @@ public abstract class GeneratedMessage extends AbstractMessage { message.verifyExtensionContainingType(extension); message.extensions.addRepeatedField( extension.getDescriptor(), extension.singularToReflectionType(value)); - return (BuilderType)this; + return (BuilderType) this; } /** Clear an extension. */ @@ -611,7 +624,7 @@ public abstract class GeneratedMessage extends AbstractMessage { ExtendableMessage<MessageType> message = internalGetResult(); message.verifyExtensionContainingType(extension); message.extensions.clearField(extension.getDescriptor()); - return (BuilderType)this; + return (BuilderType) this; } /** @@ -639,7 +652,7 @@ public abstract class GeneratedMessage extends AbstractMessage { ExtendableMessage<MessageType> message = internalGetResult(); message.verifyContainingType(field); message.extensions.setField(field, value); - return (BuilderType)this; + return (BuilderType) this; } else { return super.setField(field, value); } @@ -650,7 +663,7 @@ public abstract class GeneratedMessage extends AbstractMessage { ExtendableMessage<MessageType> message = internalGetResult(); message.verifyContainingType(field); message.extensions.clearField(field); - return (BuilderType)this; + return (BuilderType) this; } else { return super.clearField(field); } @@ -662,7 +675,7 @@ public abstract class GeneratedMessage extends AbstractMessage { ExtendableMessage<MessageType> message = internalGetResult(); message.verifyContainingType(field); message.extensions.setRepeatedField(field, index, value); - return (BuilderType)this; + return (BuilderType) this; } else { return super.setRepeatedField(field, index, value); } @@ -674,11 +687,15 @@ public abstract class GeneratedMessage extends AbstractMessage { ExtendableMessage<MessageType> message = internalGetResult(); message.verifyContainingType(field); message.extensions.addRepeatedField(field, value); - return (BuilderType)this; + return (BuilderType) this; } else { return super.addRepeatedField(field, value); } } + + protected final void mergeExtensionFields(ExtendableMessage other) { + internalGetResult().extensions.mergeFrom(other.extensions); + } } // ----------------------------------------------------------------- @@ -750,8 +767,8 @@ public abstract class GeneratedMessage extends AbstractMessage { enumValueOf = null; enumGetValueDescriptor = null; messageDefaultInstance = - (Message)invokeOrDie(getMethodOrDie(type, "getDefaultInstance"), - null); + (Message) invokeOrDie(getMethodOrDie(type, "getDefaultInstance"), + null); break; case ENUM: enumValueOf = getMethodOrDie(type, "valueOf", @@ -797,7 +814,7 @@ public abstract class GeneratedMessage extends AbstractMessage { descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) { // Must convert the whole list. List result = new ArrayList(); - for (Object element : (List)value) { + for (Object element : (List) value) { result.add(singularFromReflectionType(element)); } return result; @@ -826,10 +843,10 @@ public abstract class GeneratedMessage extends AbstractMessage { // This should not happen in normal use. But, to be nice, we'll // copy the message to whatever type the caller was expecting. return messageDefaultInstance.newBuilderForType() - .mergeFrom((Message)value).build(); + .mergeFrom((Message) value).build(); } case ENUM: - return invokeOrDie(enumValueOf, null, (EnumValueDescriptor)value); + return invokeOrDie(enumValueOf, null, (EnumValueDescriptor) value); default: return value; } @@ -847,7 +864,7 @@ public abstract class GeneratedMessage extends AbstractMessage { if (descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) { // Must convert the whole list. List result = new ArrayList(); - for (Object element : (List)value) { + for (Object element : (List) value) { result.add(singularToReflectionType(element)); } return result; @@ -900,9 +917,9 @@ public abstract class GeneratedMessage extends AbstractMessage { } catch (java.lang.reflect.InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof RuntimeException) { - throw (RuntimeException)cause; + throw (RuntimeException) cause; } else if (cause instanceof Error) { - throw (Error)cause; + throw (Error) cause; } else { throw new RuntimeException( "Unexpected exception thrown by generated accessor method.", cause); @@ -915,6 +932,7 @@ public abstract class GeneratedMessage extends AbstractMessage { * with access to the fields of a message object using Java reflection. */ public static final class FieldAccessorTable { + /** * Construct a FieldAccessorTable for a particular message class. Only * one FieldAccessorTable should ever be constructed per class. @@ -1039,7 +1057,7 @@ public abstract class GeneratedMessage extends AbstractMessage { "addRepeatedField() called on a singular field."); } public boolean has(GeneratedMessage message) { - return (Boolean)invokeOrDie(hasMethod, message); + return (Boolean) invokeOrDie(hasMethod, message); } public int getRepeatedCount(GeneratedMessage message) { throw new UnsupportedOperationException( @@ -1092,7 +1110,7 @@ public abstract class GeneratedMessage extends AbstractMessage { // 2) Insures that the caller cannot modify the list later on and // have the modifications be reflected in the message. clear(builder); - for (Object element : (List)value) { + for (Object element : (List) value) { addRepeated(builder, element); } } @@ -1111,7 +1129,7 @@ public abstract class GeneratedMessage extends AbstractMessage { "hasField() called on a singular field."); } public int getRepeatedCount(GeneratedMessage message) { - return (Integer)invokeOrDie(getCountMethod, message); + return (Integer) invokeOrDie(getCountMethod, message); } public void clear(GeneratedMessage.Builder builder) { invokeOrDie(clearMethod, builder); @@ -1169,7 +1187,7 @@ public abstract class GeneratedMessage extends AbstractMessage { @SuppressWarnings("unchecked") public Object get(GeneratedMessage message) { List newList = new ArrayList(); - for (Object element : (List)super.get(message)) { + for (Object element : (List) super.get(message)) { newList.add(invokeOrDie(getValueDescriptorMethod, element)); } return Collections.unmodifiableList(newList); @@ -1210,8 +1228,8 @@ public abstract class GeneratedMessage extends AbstractMessage { // is an alternative implementation of the same type -- e.g. a // DynamicMessage -- we should accept it. In this case we can make // a copy of the message. - return ((Message.Builder)invokeOrDie(newBuilderMethod, null)) - .mergeFrom((Message)value).build(); + return ((Message.Builder) invokeOrDie(newBuilderMethod, null)) + .mergeFrom((Message) value).build(); } } @@ -1219,7 +1237,7 @@ public abstract class GeneratedMessage extends AbstractMessage { super.set(builder, coerceType(value)); } public Message.Builder newBuilder() { - return (Message.Builder)invokeOrDie(newBuilderMethod, null); + return (Message.Builder) invokeOrDie(newBuilderMethod, null); } } @@ -1244,8 +1262,8 @@ public abstract class GeneratedMessage extends AbstractMessage { // is an alternative implementation of the same type -- e.g. a // DynamicMessage -- we should accept it. In this case we can make // a copy of the message. - return ((Message.Builder)invokeOrDie(newBuilderMethod, null)) - .mergeFrom((Message)value).build(); + return ((Message.Builder) invokeOrDie(newBuilderMethod, null)) + .mergeFrom((Message) value).build(); } } @@ -1257,7 +1275,7 @@ public abstract class GeneratedMessage extends AbstractMessage { super.addRepeated(builder, coerceType(value)); } public Message.Builder newBuilder() { - return (Message.Builder)invokeOrDie(newBuilderMethod, null); + return (Message.Builder) invokeOrDie(newBuilderMethod, null); } } } diff --git a/java/src/main/java/com/google/protobuf/Message.java b/java/src/main/java/com/google/protobuf/Message.java index 9635387a..2f8700db 100644 --- a/java/src/main/java/com/google/protobuf/Message.java +++ b/java/src/main/java/com/google/protobuf/Message.java @@ -195,6 +195,12 @@ public interface Message { Builder newBuilderForType(); /** + * Constructs a builder initialized with the current message. Use this to + * derive a new message from the current one. + */ + Builder toBuilder(); + + /** * Abstract interface implemented by Protocol Message builders. */ public static interface Builder extends Cloneable { diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java index 3a1b1d4e..3dcf68c8 100644 --- a/java/src/main/java/com/google/protobuf/TextFormat.java +++ b/java/src/main/java/com/google/protobuf/TextFormat.java @@ -397,13 +397,15 @@ public final class TextFormat { private int previousLine = 0; private int previousColumn = 0; + // We use possesive quantifiers (*+ and ++) because otherwise the Java + // regex matcher has stack overflows on large inputs. private static Pattern WHITESPACE = - Pattern.compile("(\\s|(#.*$))+", Pattern.MULTILINE); + Pattern.compile("(\\s|(#.*$))++", Pattern.MULTILINE); private static Pattern TOKEN = Pattern.compile( - "[a-zA-Z_][0-9a-zA-Z_+-]*|" + // an identifier - "[0-9+-][0-9a-zA-Z_.+-]*|" + // a number - "\"([^\"\n\\\\]|\\\\.)*(\"|\\\\?$)|" + // a double-quoted string - "\'([^\"\n\\\\]|\\\\.)*(\'|\\\\?$)", // a single-quoted string + "[a-zA-Z_][0-9a-zA-Z_+-]*+|" + // an identifier + "[0-9+-][0-9a-zA-Z_.+-]*+|" + // a number + "\"([^\"\n\\\\]|\\\\.)*+(\"|\\\\?$)|" + // a double-quoted string + "\'([^\"\n\\\\]|\\\\.)*+(\'|\\\\?$)", // a single-quoted string Pattern.MULTILINE); private static Pattern DOUBLE_INFINITY = Pattern.compile( diff --git a/java/src/main/java/com/google/protobuf/WireFormat.java b/java/src/main/java/com/google/protobuf/WireFormat.java index ff042c05..2faf2448 100644 --- a/java/src/main/java/com/google/protobuf/WireFormat.java +++ b/java/src/main/java/com/google/protobuf/WireFormat.java @@ -96,6 +96,16 @@ public final class WireFormat { "There is no way to get here, but the compiler thinks otherwise."); } + /** Given a field descriptor, returns the wire type. This differs from + * getWireFormatForFieldType for packed repeated fields. */ + static int getWireFormatForField(Descriptors.FieldDescriptor descriptor) { + if (descriptor.getOptions().getPacked()) { + return WIRETYPE_LENGTH_DELIMITED; + } else { + return getWireFormatForFieldType(descriptor.getType()); + } + } + // Field numbers for feilds in MessageSet wire format. static final int MESSAGE_SET_ITEM = 1; static final int MESSAGE_SET_TYPE_ID = 2; diff --git a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java index 10ab7e75..da073561 100644 --- a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java +++ b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java @@ -34,6 +34,7 @@ import protobuf_unittest.UnittestProto; import protobuf_unittest.UnittestProto.ForeignMessage; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllExtensions; +import protobuf_unittest.UnittestProto.TestPackedTypes; import protobuf_unittest.UnittestProto.TestRequired; import protobuf_unittest.UnittestProto.TestRequiredForeign; import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize; @@ -91,6 +92,9 @@ public class AbstractMessageTest extends TestCase { public Builder newBuilderForType() { return new Builder(wrappedMessage.newBuilderForType()); } + public Builder toBuilder() { + return new Builder(wrappedMessage.toBuilder()); + } static class Builder extends AbstractMessage.Builder<Builder> { private final Message.Builder wrappedBuilder; @@ -215,6 +219,25 @@ public class AbstractMessageTest extends TestCase { TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage); } + public void testPackedSerialization() throws Exception { + Message abstractMessage = + new AbstractMessageWrapper(TestUtil.getPackedSet()); + + TestUtil.assertPackedFieldsSet( + TestPackedTypes.parseFrom(abstractMessage.toByteString())); + + assertEquals(TestUtil.getPackedSet().toByteString(), + abstractMessage.toByteString()); + } + + public void testPackedParsing() throws Exception { + AbstractMessageWrapper.Builder builder = + new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder()); + AbstractMessageWrapper message = + builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build(); + TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage); + } + public void testOptimizedForSize() throws Exception { // We're mostly only checking that this class was compiled successfully. TestOptimizedForSize message = diff --git a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java index 5a96e3e6..c42b485c 100644 --- a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java +++ b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java @@ -31,6 +31,7 @@ package com.google.protobuf; import protobuf_unittest.UnittestProto.TestAllTypes; +import protobuf_unittest.UnittestProto.TestPackedTypes; import junit.framework.TestCase; @@ -290,4 +291,14 @@ public class CodedOutputStreamTest extends TestCase { assertEqualBytes(rawBytes, rawOutput.toByteArray()); } } + + /** Tests writing a whole message with every packed field type. Ensures the + * wire format of packed fields is compatible with C++. */ + public void testWriteWholePackedFieldsMessage() throws Exception { + TestPackedTypes message = TestUtil.getPackedSet(); + + byte[] rawBytes = message.toByteArray(); + assertEqualBytes(TestUtil.getGoldenPackedFieldsMessage().toByteArray(), + rawBytes); + } } diff --git a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java index e2c15c64..fc53c531 100644 --- a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java +++ b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java @@ -32,8 +32,10 @@ package com.google.protobuf; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllExtensions; +import protobuf_unittest.UnittestProto.TestPackedTypes; import junit.framework.TestCase; +import java.util.Arrays; /** * Unit test for {@link DynamicMessage}. See also {@link MessageTest}, which @@ -48,6 +50,8 @@ public class DynamicMessageTest extends TestCase { TestUtil.ReflectionTester extensionsReflectionTester = new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(), TestUtil.getExtensionRegistry()); + TestUtil.ReflectionTester packedReflectionTester = + new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null); public void testDynamicMessageAccessors() throws Exception { Message.Builder builder = @@ -57,6 +61,12 @@ public class DynamicMessageTest extends TestCase { reflectionTester.assertAllFieldsSetViaReflection(message); } + public void testDynamicMessageSettersRejectNull() throws Exception { + Message.Builder builder = + DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); + reflectionTester.assertReflectionSettersRejectNull(builder); + } + public void testDynamicMessageExtensionAccessors() throws Exception { // We don't need to extensively test DynamicMessage's handling of // extensions because, frankly, it doesn't do anything special with them. @@ -68,6 +78,12 @@ public class DynamicMessageTest extends TestCase { extensionsReflectionTester.assertAllFieldsSetViaReflection(message); } + public void testDynamicMessageExtensionSettersRejectNull() throws Exception { + Message.Builder builder = + DynamicMessage.newBuilder(TestAllExtensions.getDescriptor()); + extensionsReflectionTester.assertReflectionSettersRejectNull(builder); + } + public void testDynamicMessageRepeatedSetters() throws Exception { Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); @@ -77,6 +93,12 @@ public class DynamicMessageTest extends TestCase { reflectionTester.assertRepeatedFieldsModifiedViaReflection(message); } + public void testDynamicMessageRepeatedSettersRejectNull() throws Exception { + Message.Builder builder = + DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); + reflectionTester.assertReflectionRepeatedSettersRejectNull(builder); + } + public void testDynamicMessageDefaults() throws Exception { reflectionTester.assertClearViaReflection( DynamicMessage.getDefaultInstance(TestAllTypes.getDescriptor())); @@ -123,6 +145,33 @@ public class DynamicMessageTest extends TestCase { reflectionTester.assertAllFieldsSetViaReflection(message2); } + public void testDynamicMessagePackedSerialization() throws Exception { + Message.Builder builder = + DynamicMessage.newBuilder(TestPackedTypes.getDescriptor()); + packedReflectionTester.setPackedFieldsViaReflection(builder); + Message message = builder.build(); + + ByteString rawBytes = message.toByteString(); + TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes); + + TestUtil.assertPackedFieldsSet(message2); + + // In fact, the serialized forms should be exactly the same, byte-for-byte. + assertEquals(TestUtil.getPackedSet().toByteString(), rawBytes); + } + + public void testDynamicMessagePackedParsing() throws Exception { + TestPackedTypes.Builder builder = TestPackedTypes.newBuilder(); + TestUtil.setPackedFields(builder); + TestPackedTypes message = builder.build(); + + ByteString rawBytes = message.toByteString(); + + Message message2 = + DynamicMessage.parseFrom(TestPackedTypes.getDescriptor(), rawBytes); + packedReflectionTester.assertPackedFieldsSetViaReflection(message2); + } + public void testDynamicMessageCopy() throws Exception { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); TestUtil.setAllFields(builder); @@ -131,4 +180,23 @@ public class DynamicMessageTest extends TestCase { DynamicMessage copy = DynamicMessage.newBuilder(message).build(); reflectionTester.assertAllFieldsSetViaReflection(copy); } + + public void testToBuilder() throws Exception { + DynamicMessage.Builder builder = + DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); + reflectionTester.setAllFieldsViaReflection(builder); + int unknownFieldNum = 9; + long unknownFieldVal = 90; + builder.setUnknownFields(UnknownFieldSet.newBuilder() + .addField(unknownFieldNum, + UnknownFieldSet.Field.newBuilder() + .addVarint(unknownFieldVal).build()) + .build()); + DynamicMessage message = builder.build(); + + DynamicMessage derived = message.toBuilder().build(); + reflectionTester.assertAllFieldsSetViaReflection(derived); + assertEquals(Arrays.asList(unknownFieldVal), + derived.getUnknownFields().getField(unknownFieldNum).getVarintList()); + } } diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java index 95c269a2..0ecdc6ae 100644 --- a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java +++ b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java @@ -71,6 +71,72 @@ public class GeneratedMessageTest extends TestCase { TestUtil.assertAllFieldsSet(message); } + public void testSettersRejectNull() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + try { + builder.setOptionalString(null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.setOptionalBytes(null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.setOptionalNestedMessage((TestAllTypes.NestedMessage) null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.setOptionalNestedMessage( + (TestAllTypes.NestedMessage.Builder) null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.setOptionalNestedEnum(null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.addRepeatedString(null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.addRepeatedBytes(null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.addRepeatedNestedMessage((TestAllTypes.NestedMessage) null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.addRepeatedNestedMessage( + (TestAllTypes.NestedMessage.Builder) null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.addRepeatedNestedEnum(null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + } + public void testRepeatedSetters() throws Exception { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); TestUtil.setAllFields(builder); @@ -79,6 +145,55 @@ public class GeneratedMessageTest extends TestCase { TestUtil.assertRepeatedFieldsModified(message); } + public void testRepeatedSettersRejectNull() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + + builder.addRepeatedString("one"); + builder.addRepeatedString("two"); + try { + builder.setRepeatedString(1, null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + + builder.addRepeatedBytes(TestUtil.toBytes("one")); + builder.addRepeatedBytes(TestUtil.toBytes("two")); + try { + builder.setRepeatedBytes(1, null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + + builder.addRepeatedNestedMessage( + TestAllTypes.NestedMessage.newBuilder().setBb(218).build()); + builder.addRepeatedNestedMessage( + TestAllTypes.NestedMessage.newBuilder().setBb(456).build()); + try { + builder.setRepeatedNestedMessage(1, (TestAllTypes.NestedMessage) null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.setRepeatedNestedMessage( + 1, (TestAllTypes.NestedMessage.Builder) null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + + builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.FOO); + builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAR); + try { + builder.setRepeatedNestedEnum(1, null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + } + public void testRepeatedAppend() throws Exception { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); @@ -97,6 +212,42 @@ public class GeneratedMessageTest extends TestCase { assertEquals(12, message.getRepeatedForeignMessage(0).getC()); } + public void testRepeatedAppendRejectsNull() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + + ForeignMessage foreignMessage = + ForeignMessage.newBuilder().setC(12).build(); + try { + builder.addAllRepeatedForeignMessage( + Arrays.asList(foreignMessage, (ForeignMessage) null)); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + + try { + builder.addAllRepeatedForeignEnum( + Arrays.asList(ForeignEnum.FOREIGN_BAZ, null)); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + + try { + builder.addAllRepeatedString(Arrays.asList("one", null)); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + + try { + builder.addAllRepeatedBytes(Arrays.asList(TestUtil.toBytes("one"), null)); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + } + public void testSettingForeignMessageUsingBuilder() throws Exception { TestAllTypes message = TestAllTypes.newBuilder() // Pass builder for foreign message instance. @@ -146,6 +297,11 @@ public class GeneratedMessageTest extends TestCase { TestUtil.assertAllFieldsSet(message); } + public void testReflectionSettersRejectNull() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + reflectionTester.assertReflectionSettersRejectNull(builder); + } + public void testReflectionRepeatedSetters() throws Exception { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); reflectionTester.setAllFieldsViaReflection(builder); @@ -154,6 +310,11 @@ public class GeneratedMessageTest extends TestCase { TestUtil.assertRepeatedFieldsModified(message); } + public void testReflectionRepeatedSettersRejectNull() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + reflectionTester.assertReflectionRepeatedSettersRejectNull(builder); + } + public void testReflectionDefaults() throws Exception { reflectionTester.assertClearViaReflection( TestAllTypes.getDefaultInstance()); @@ -161,6 +322,11 @@ public class GeneratedMessageTest extends TestCase { TestAllTypes.newBuilder().build()); } + public void testEnumInterface() throws Exception { + assertTrue(TestAllTypes.getDefaultInstance().getDefaultNestedEnum() + instanceof ProtocolMessageEnum); + } + // ================================================================= // Extensions. @@ -202,6 +368,11 @@ public class GeneratedMessageTest extends TestCase { TestUtil.assertAllExtensionsSet(message); } + public void testExtensionReflectionSettersRejectNull() throws Exception { + TestAllExtensions.Builder builder = TestAllExtensions.newBuilder(); + extensionsReflectionTester.assertReflectionSettersRejectNull(builder); + } + public void testExtensionReflectionRepeatedSetters() throws Exception { TestAllExtensions.Builder builder = TestAllExtensions.newBuilder(); extensionsReflectionTester.setAllFieldsViaReflection(builder); @@ -210,6 +381,13 @@ public class GeneratedMessageTest extends TestCase { TestUtil.assertRepeatedExtensionsModified(message); } + public void testExtensionReflectionRepeatedSettersRejectNull() + throws Exception { + TestAllExtensions.Builder builder = TestAllExtensions.newBuilder(); + extensionsReflectionTester.assertReflectionRepeatedSettersRejectNull( + builder); + } + public void testExtensionReflectionDefaults() throws Exception { extensionsReflectionTester.assertClearViaReflection( TestAllExtensions.getDefaultInstance()); @@ -231,6 +409,17 @@ public class GeneratedMessageTest extends TestCase { .getExtensionCount(UnittestProto.repeatedInt32Extension)); } + public void testExtensionMergeFrom() throws Exception { + TestAllExtensions original = + TestAllExtensions.newBuilder() + .setExtension(UnittestProto.optionalInt32Extension, 1).build(); + TestAllExtensions merged = + TestAllExtensions.newBuilder().mergeFrom(original).build(); + assertTrue(merged.hasExtension(UnittestProto.optionalInt32Extension)); + assertEquals( + 1, (int) merged.getExtension(UnittestProto.optionalInt32Extension)); + } + // ================================================================= // multiple_files_test @@ -266,7 +455,7 @@ public class GeneratedMessageTest extends TestCase { TestOptionalOptimizedForSize message = TestOptionalOptimizedForSize.getDefaultInstance(); assertTrue(message.isInitialized()); - + message = TestOptionalOptimizedForSize.newBuilder().setO( TestRequiredOptimizedForSize.newBuilder().buildPartial() ).buildPartial(); @@ -292,4 +481,11 @@ public class GeneratedMessageTest extends TestCase { assertTrue(builder.isInitialized()); assertTrue(builder.buildPartial().isInitialized()); } + + public void testToBuilder() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + TestUtil.setAllFields(builder); + TestAllTypes message = builder.build(); + TestUtil.assertAllFieldsSet(message.toBuilder().build()); + } } diff --git a/java/src/test/java/com/google/protobuf/TestUtil.java b/java/src/test/java/com/google/protobuf/TestUtil.java index d99ab85e..2f47b714 100644 --- a/java/src/test/java/com/google/protobuf/TestUtil.java +++ b/java/src/test/java/com/google/protobuf/TestUtil.java @@ -28,17 +28,105 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Note: This file contains many lines over 80 characters. It even contains -// many lines over 100 characters, which fails a presubmit test. However, -// given the extremely repetitive nature of the file, I (kenton) feel that -// having similar components of each statement line up is more important than -// avoiding horizontal scrolling. So, I am bypassing the presubmit check. - package com.google.protobuf; import protobuf_unittest.UnittestProto; -import protobuf_unittest.UnittestProto.TestAllTypes; + +// The static imports are to avoid 100+ char lines. The following is roughly equivalent to +// import static protobuf_unittest.UnittestProto.*; +import static protobuf_unittest.UnittestProto.defaultInt32Extension; +import static protobuf_unittest.UnittestProto.defaultInt64Extension; +import static protobuf_unittest.UnittestProto.defaultUint32Extension; +import static protobuf_unittest.UnittestProto.defaultUint64Extension; +import static protobuf_unittest.UnittestProto.defaultSint32Extension; +import static protobuf_unittest.UnittestProto.defaultSint64Extension; +import static protobuf_unittest.UnittestProto.defaultFixed32Extension; +import static protobuf_unittest.UnittestProto.defaultFixed64Extension; +import static protobuf_unittest.UnittestProto.defaultSfixed32Extension; +import static protobuf_unittest.UnittestProto.defaultSfixed64Extension; +import static protobuf_unittest.UnittestProto.defaultFloatExtension; +import static protobuf_unittest.UnittestProto.defaultDoubleExtension; +import static protobuf_unittest.UnittestProto.defaultBoolExtension; +import static protobuf_unittest.UnittestProto.defaultStringExtension; +import static protobuf_unittest.UnittestProto.defaultBytesExtension; +import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension; +import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension; +import static protobuf_unittest.UnittestProto.defaultImportEnumExtension; +import static protobuf_unittest.UnittestProto.defaultStringPieceExtension; +import static protobuf_unittest.UnittestProto.defaultCordExtension; + +import static protobuf_unittest.UnittestProto.optionalInt32Extension; +import static protobuf_unittest.UnittestProto.optionalInt64Extension; +import static protobuf_unittest.UnittestProto.optionalUint32Extension; +import static protobuf_unittest.UnittestProto.optionalUint64Extension; +import static protobuf_unittest.UnittestProto.optionalSint32Extension; +import static protobuf_unittest.UnittestProto.optionalSint64Extension; +import static protobuf_unittest.UnittestProto.optionalFixed32Extension; +import static protobuf_unittest.UnittestProto.optionalFixed64Extension; +import static protobuf_unittest.UnittestProto.optionalSfixed32Extension; +import static protobuf_unittest.UnittestProto.optionalSfixed64Extension; +import static protobuf_unittest.UnittestProto.optionalFloatExtension; +import static protobuf_unittest.UnittestProto.optionalDoubleExtension; +import static protobuf_unittest.UnittestProto.optionalBoolExtension; +import static protobuf_unittest.UnittestProto.optionalStringExtension; +import static protobuf_unittest.UnittestProto.optionalBytesExtension; +import static protobuf_unittest.UnittestProto.optionalGroupExtension; +import static protobuf_unittest.UnittestProto.optionalNestedMessageExtension; +import static protobuf_unittest.UnittestProto.optionalForeignMessageExtension; +import static protobuf_unittest.UnittestProto.optionalImportMessageExtension; +import static protobuf_unittest.UnittestProto.optionalNestedEnumExtension; +import static protobuf_unittest.UnittestProto.optionalForeignEnumExtension; +import static protobuf_unittest.UnittestProto.optionalImportEnumExtension; +import static protobuf_unittest.UnittestProto.optionalStringPieceExtension; +import static protobuf_unittest.UnittestProto.optionalCordExtension; + +import static protobuf_unittest.UnittestProto.repeatedInt32Extension; +import static protobuf_unittest.UnittestProto.repeatedInt64Extension; +import static protobuf_unittest.UnittestProto.repeatedUint32Extension; +import static protobuf_unittest.UnittestProto.repeatedUint64Extension; +import static protobuf_unittest.UnittestProto.repeatedSint32Extension; +import static protobuf_unittest.UnittestProto.repeatedSint64Extension; +import static protobuf_unittest.UnittestProto.repeatedFixed32Extension; +import static protobuf_unittest.UnittestProto.repeatedFixed64Extension; +import static protobuf_unittest.UnittestProto.repeatedSfixed32Extension; +import static protobuf_unittest.UnittestProto.repeatedSfixed64Extension; +import static protobuf_unittest.UnittestProto.repeatedFloatExtension; +import static protobuf_unittest.UnittestProto.repeatedDoubleExtension; +import static protobuf_unittest.UnittestProto.repeatedBoolExtension; +import static protobuf_unittest.UnittestProto.repeatedStringExtension; +import static protobuf_unittest.UnittestProto.repeatedBytesExtension; +import static protobuf_unittest.UnittestProto.repeatedGroupExtension; +import static protobuf_unittest.UnittestProto.repeatedNestedMessageExtension; +import static protobuf_unittest.UnittestProto.repeatedForeignMessageExtension; +import static protobuf_unittest.UnittestProto.repeatedImportMessageExtension; +import static protobuf_unittest.UnittestProto.repeatedNestedEnumExtension; +import static protobuf_unittest.UnittestProto.repeatedForeignEnumExtension; +import static protobuf_unittest.UnittestProto.repeatedImportEnumExtension; +import static protobuf_unittest.UnittestProto.repeatedStringPieceExtension; +import static protobuf_unittest.UnittestProto.repeatedCordExtension; + +import static protobuf_unittest.UnittestProto.OptionalGroup_extension; +import static protobuf_unittest.UnittestProto.RepeatedGroup_extension; + +import static protobuf_unittest.UnittestProto.packedInt32Extension; +import static protobuf_unittest.UnittestProto.packedInt64Extension; +import static protobuf_unittest.UnittestProto.packedUint32Extension; +import static protobuf_unittest.UnittestProto.packedUint64Extension; +import static protobuf_unittest.UnittestProto.packedSint32Extension; +import static protobuf_unittest.UnittestProto.packedSint64Extension; +import static protobuf_unittest.UnittestProto.packedFixed32Extension; +import static protobuf_unittest.UnittestProto.packedFixed64Extension; +import static protobuf_unittest.UnittestProto.packedSfixed32Extension; +import static protobuf_unittest.UnittestProto.packedSfixed64Extension; +import static protobuf_unittest.UnittestProto.packedFloatExtension; +import static protobuf_unittest.UnittestProto.packedDoubleExtension; +import static protobuf_unittest.UnittestProto.packedBoolExtension; +import static protobuf_unittest.UnittestProto.packedEnumExtension; + import protobuf_unittest.UnittestProto.TestAllExtensions; +import protobuf_unittest.UnittestProto.TestAllTypes; +import protobuf_unittest.UnittestProto.TestPackedExtensions; +import protobuf_unittest.UnittestProto.TestPackedTypes; import protobuf_unittest.UnittestProto.ForeignMessage; import protobuf_unittest.UnittestProto.ForeignEnum; import com.google.protobuf.test.UnittestImport.ImportMessage; @@ -63,7 +151,7 @@ class TestUtil { private TestUtil() {} /** Helper to convert a String to ByteString. */ - private static ByteString toBytes(String str) { + static ByteString toBytes(String str) { try { return ByteString.copyFrom(str.getBytes("UTF-8")); } catch(java.io.UnsupportedEncodingException e) { @@ -91,6 +179,18 @@ class TestUtil { return builder.build(); } + public static TestPackedTypes getPackedSet() { + TestPackedTypes.Builder builder = TestPackedTypes.newBuilder(); + setPackedFields(builder); + return builder.build(); + } + + public static TestPackedExtensions getPackedExtensionsSet() { + TestPackedExtensions.Builder builder = TestPackedExtensions.newBuilder(); + setPackedExtensions(builder); + return builder.build(); + } + /** * Set every field of {@code message} to the values expected by * {@code assertAllFieldsSet()}. @@ -770,141 +870,129 @@ class TestUtil { * {@code assertAllExtensionsSet()}. */ public static void setAllExtensions(TestAllExtensions.Builder message) { - message.setExtension(UnittestProto.optionalInt32Extension , 101); - message.setExtension(UnittestProto.optionalInt64Extension , 102L); - message.setExtension(UnittestProto.optionalUint32Extension , 103); - message.setExtension(UnittestProto.optionalUint64Extension , 104L); - message.setExtension(UnittestProto.optionalSint32Extension , 105); - message.setExtension(UnittestProto.optionalSint64Extension , 106L); - message.setExtension(UnittestProto.optionalFixed32Extension , 107); - message.setExtension(UnittestProto.optionalFixed64Extension , 108L); - message.setExtension(UnittestProto.optionalSfixed32Extension, 109); - message.setExtension(UnittestProto.optionalSfixed64Extension, 110L); - message.setExtension(UnittestProto.optionalFloatExtension , 111F); - message.setExtension(UnittestProto.optionalDoubleExtension , 112D); - message.setExtension(UnittestProto.optionalBoolExtension , true); - message.setExtension(UnittestProto.optionalStringExtension , "115"); - message.setExtension(UnittestProto.optionalBytesExtension , toBytes("116")); - - message.setExtension(UnittestProto.optionalGroupExtension, - UnittestProto.OptionalGroup_extension.newBuilder().setA(117).build()); - message.setExtension(UnittestProto.optionalNestedMessageExtension, + message.setExtension(optionalInt32Extension , 101); + message.setExtension(optionalInt64Extension , 102L); + message.setExtension(optionalUint32Extension , 103); + message.setExtension(optionalUint64Extension , 104L); + message.setExtension(optionalSint32Extension , 105); + message.setExtension(optionalSint64Extension , 106L); + message.setExtension(optionalFixed32Extension , 107); + message.setExtension(optionalFixed64Extension , 108L); + message.setExtension(optionalSfixed32Extension, 109); + message.setExtension(optionalSfixed64Extension, 110L); + message.setExtension(optionalFloatExtension , 111F); + message.setExtension(optionalDoubleExtension , 112D); + message.setExtension(optionalBoolExtension , true); + message.setExtension(optionalStringExtension , "115"); + message.setExtension(optionalBytesExtension , toBytes("116")); + + message.setExtension(optionalGroupExtension, + OptionalGroup_extension.newBuilder().setA(117).build()); + message.setExtension(optionalNestedMessageExtension, TestAllTypes.NestedMessage.newBuilder().setBb(118).build()); - message.setExtension(UnittestProto.optionalForeignMessageExtension, + message.setExtension(optionalForeignMessageExtension, ForeignMessage.newBuilder().setC(119).build()); - message.setExtension(UnittestProto.optionalImportMessageExtension, + message.setExtension(optionalImportMessageExtension, ImportMessage.newBuilder().setD(120).build()); - message.setExtension(UnittestProto.optionalNestedEnumExtension, - TestAllTypes.NestedEnum.BAZ); - message.setExtension(UnittestProto.optionalForeignEnumExtension, - ForeignEnum.FOREIGN_BAZ); - message.setExtension(UnittestProto.optionalImportEnumExtension, - ImportEnum.IMPORT_BAZ); + message.setExtension(optionalNestedEnumExtension, TestAllTypes.NestedEnum.BAZ); + message.setExtension(optionalForeignEnumExtension, ForeignEnum.FOREIGN_BAZ); + message.setExtension(optionalImportEnumExtension, ImportEnum.IMPORT_BAZ); - message.setExtension(UnittestProto.optionalStringPieceExtension, "124"); - message.setExtension(UnittestProto.optionalCordExtension, "125"); + message.setExtension(optionalStringPieceExtension, "124"); + message.setExtension(optionalCordExtension, "125"); // ----------------------------------------------------------------- - message.addExtension(UnittestProto.repeatedInt32Extension , 201); - message.addExtension(UnittestProto.repeatedInt64Extension , 202L); - message.addExtension(UnittestProto.repeatedUint32Extension , 203); - message.addExtension(UnittestProto.repeatedUint64Extension , 204L); - message.addExtension(UnittestProto.repeatedSint32Extension , 205); - message.addExtension(UnittestProto.repeatedSint64Extension , 206L); - message.addExtension(UnittestProto.repeatedFixed32Extension , 207); - message.addExtension(UnittestProto.repeatedFixed64Extension , 208L); - message.addExtension(UnittestProto.repeatedSfixed32Extension, 209); - message.addExtension(UnittestProto.repeatedSfixed64Extension, 210L); - message.addExtension(UnittestProto.repeatedFloatExtension , 211F); - message.addExtension(UnittestProto.repeatedDoubleExtension , 212D); - message.addExtension(UnittestProto.repeatedBoolExtension , true); - message.addExtension(UnittestProto.repeatedStringExtension , "215"); - message.addExtension(UnittestProto.repeatedBytesExtension , toBytes("216")); - - message.addExtension(UnittestProto.repeatedGroupExtension, - UnittestProto.RepeatedGroup_extension.newBuilder().setA(217).build()); - message.addExtension(UnittestProto.repeatedNestedMessageExtension, + message.addExtension(repeatedInt32Extension , 201); + message.addExtension(repeatedInt64Extension , 202L); + message.addExtension(repeatedUint32Extension , 203); + message.addExtension(repeatedUint64Extension , 204L); + message.addExtension(repeatedSint32Extension , 205); + message.addExtension(repeatedSint64Extension , 206L); + message.addExtension(repeatedFixed32Extension , 207); + message.addExtension(repeatedFixed64Extension , 208L); + message.addExtension(repeatedSfixed32Extension, 209); + message.addExtension(repeatedSfixed64Extension, 210L); + message.addExtension(repeatedFloatExtension , 211F); + message.addExtension(repeatedDoubleExtension , 212D); + message.addExtension(repeatedBoolExtension , true); + message.addExtension(repeatedStringExtension , "215"); + message.addExtension(repeatedBytesExtension , toBytes("216")); + + message.addExtension(repeatedGroupExtension, + RepeatedGroup_extension.newBuilder().setA(217).build()); + message.addExtension(repeatedNestedMessageExtension, TestAllTypes.NestedMessage.newBuilder().setBb(218).build()); - message.addExtension(UnittestProto.repeatedForeignMessageExtension, + message.addExtension(repeatedForeignMessageExtension, ForeignMessage.newBuilder().setC(219).build()); - message.addExtension(UnittestProto.repeatedImportMessageExtension, + message.addExtension(repeatedImportMessageExtension, ImportMessage.newBuilder().setD(220).build()); - message.addExtension(UnittestProto.repeatedNestedEnumExtension, - TestAllTypes.NestedEnum.BAR); - message.addExtension(UnittestProto.repeatedForeignEnumExtension, - ForeignEnum.FOREIGN_BAR); - message.addExtension(UnittestProto.repeatedImportEnumExtension, - ImportEnum.IMPORT_BAR); + message.addExtension(repeatedNestedEnumExtension, TestAllTypes.NestedEnum.BAR); + message.addExtension(repeatedForeignEnumExtension, ForeignEnum.FOREIGN_BAR); + message.addExtension(repeatedImportEnumExtension, ImportEnum.IMPORT_BAR); - message.addExtension(UnittestProto.repeatedStringPieceExtension, "224"); - message.addExtension(UnittestProto.repeatedCordExtension, "225"); + message.addExtension(repeatedStringPieceExtension, "224"); + message.addExtension(repeatedCordExtension, "225"); // Add a second one of each field. - message.addExtension(UnittestProto.repeatedInt32Extension , 301); - message.addExtension(UnittestProto.repeatedInt64Extension , 302L); - message.addExtension(UnittestProto.repeatedUint32Extension , 303); - message.addExtension(UnittestProto.repeatedUint64Extension , 304L); - message.addExtension(UnittestProto.repeatedSint32Extension , 305); - message.addExtension(UnittestProto.repeatedSint64Extension , 306L); - message.addExtension(UnittestProto.repeatedFixed32Extension , 307); - message.addExtension(UnittestProto.repeatedFixed64Extension , 308L); - message.addExtension(UnittestProto.repeatedSfixed32Extension, 309); - message.addExtension(UnittestProto.repeatedSfixed64Extension, 310L); - message.addExtension(UnittestProto.repeatedFloatExtension , 311F); - message.addExtension(UnittestProto.repeatedDoubleExtension , 312D); - message.addExtension(UnittestProto.repeatedBoolExtension , false); - message.addExtension(UnittestProto.repeatedStringExtension , "315"); - message.addExtension(UnittestProto.repeatedBytesExtension , toBytes("316")); - - message.addExtension(UnittestProto.repeatedGroupExtension, - UnittestProto.RepeatedGroup_extension.newBuilder().setA(317).build()); - message.addExtension(UnittestProto.repeatedNestedMessageExtension, + message.addExtension(repeatedInt32Extension , 301); + message.addExtension(repeatedInt64Extension , 302L); + message.addExtension(repeatedUint32Extension , 303); + message.addExtension(repeatedUint64Extension , 304L); + message.addExtension(repeatedSint32Extension , 305); + message.addExtension(repeatedSint64Extension , 306L); + message.addExtension(repeatedFixed32Extension , 307); + message.addExtension(repeatedFixed64Extension , 308L); + message.addExtension(repeatedSfixed32Extension, 309); + message.addExtension(repeatedSfixed64Extension, 310L); + message.addExtension(repeatedFloatExtension , 311F); + message.addExtension(repeatedDoubleExtension , 312D); + message.addExtension(repeatedBoolExtension , false); + message.addExtension(repeatedStringExtension , "315"); + message.addExtension(repeatedBytesExtension , toBytes("316")); + + message.addExtension(repeatedGroupExtension, + RepeatedGroup_extension.newBuilder().setA(317).build()); + message.addExtension(repeatedNestedMessageExtension, TestAllTypes.NestedMessage.newBuilder().setBb(318).build()); - message.addExtension(UnittestProto.repeatedForeignMessageExtension, + message.addExtension(repeatedForeignMessageExtension, ForeignMessage.newBuilder().setC(319).build()); - message.addExtension(UnittestProto.repeatedImportMessageExtension, + message.addExtension(repeatedImportMessageExtension, ImportMessage.newBuilder().setD(320).build()); - message.addExtension(UnittestProto.repeatedNestedEnumExtension, - TestAllTypes.NestedEnum.BAZ); - message.addExtension(UnittestProto.repeatedForeignEnumExtension, - ForeignEnum.FOREIGN_BAZ); - message.addExtension(UnittestProto.repeatedImportEnumExtension, - ImportEnum.IMPORT_BAZ); + message.addExtension(repeatedNestedEnumExtension, TestAllTypes.NestedEnum.BAZ); + message.addExtension(repeatedForeignEnumExtension, ForeignEnum.FOREIGN_BAZ); + message.addExtension(repeatedImportEnumExtension, ImportEnum.IMPORT_BAZ); - message.addExtension(UnittestProto.repeatedStringPieceExtension, "324"); - message.addExtension(UnittestProto.repeatedCordExtension, "325"); + message.addExtension(repeatedStringPieceExtension, "324"); + message.addExtension(repeatedCordExtension, "325"); // ----------------------------------------------------------------- - message.setExtension(UnittestProto.defaultInt32Extension , 401); - message.setExtension(UnittestProto.defaultInt64Extension , 402L); - message.setExtension(UnittestProto.defaultUint32Extension , 403); - message.setExtension(UnittestProto.defaultUint64Extension , 404L); - message.setExtension(UnittestProto.defaultSint32Extension , 405); - message.setExtension(UnittestProto.defaultSint64Extension , 406L); - message.setExtension(UnittestProto.defaultFixed32Extension , 407); - message.setExtension(UnittestProto.defaultFixed64Extension , 408L); - message.setExtension(UnittestProto.defaultSfixed32Extension, 409); - message.setExtension(UnittestProto.defaultSfixed64Extension, 410L); - message.setExtension(UnittestProto.defaultFloatExtension , 411F); - message.setExtension(UnittestProto.defaultDoubleExtension , 412D); - message.setExtension(UnittestProto.defaultBoolExtension , false); - message.setExtension(UnittestProto.defaultStringExtension , "415"); - message.setExtension(UnittestProto.defaultBytesExtension , toBytes("416")); - - message.setExtension(UnittestProto.defaultNestedEnumExtension, - TestAllTypes.NestedEnum.FOO); - message.setExtension(UnittestProto.defaultForeignEnumExtension, - ForeignEnum.FOREIGN_FOO); - message.setExtension(UnittestProto.defaultImportEnumExtension, - ImportEnum.IMPORT_FOO); - - message.setExtension(UnittestProto.defaultStringPieceExtension, "424"); - message.setExtension(UnittestProto.defaultCordExtension, "425"); + message.setExtension(defaultInt32Extension , 401); + message.setExtension(defaultInt64Extension , 402L); + message.setExtension(defaultUint32Extension , 403); + message.setExtension(defaultUint64Extension , 404L); + message.setExtension(defaultSint32Extension , 405); + message.setExtension(defaultSint64Extension , 406L); + message.setExtension(defaultFixed32Extension , 407); + message.setExtension(defaultFixed64Extension , 408L); + message.setExtension(defaultSfixed32Extension, 409); + message.setExtension(defaultSfixed64Extension, 410L); + message.setExtension(defaultFloatExtension , 411F); + message.setExtension(defaultDoubleExtension , 412D); + message.setExtension(defaultBoolExtension , false); + message.setExtension(defaultStringExtension , "415"); + message.setExtension(defaultBytesExtension , toBytes("416")); + + message.setExtension(defaultNestedEnumExtension, TestAllTypes.NestedEnum.FOO); + message.setExtension(defaultForeignEnumExtension, ForeignEnum.FOREIGN_FOO); + message.setExtension(defaultImportEnumExtension, ImportEnum.IMPORT_FOO); + + message.setExtension(defaultStringPieceExtension, "424"); + message.setExtension(defaultCordExtension, "425"); } // ------------------------------------------------------------------- @@ -915,40 +1003,37 @@ class TestUtil { */ public static void modifyRepeatedExtensions( TestAllExtensions.Builder message) { - message.setExtension(UnittestProto.repeatedInt32Extension , 1, 501); - message.setExtension(UnittestProto.repeatedInt64Extension , 1, 502L); - message.setExtension(UnittestProto.repeatedUint32Extension , 1, 503); - message.setExtension(UnittestProto.repeatedUint64Extension , 1, 504L); - message.setExtension(UnittestProto.repeatedSint32Extension , 1, 505); - message.setExtension(UnittestProto.repeatedSint64Extension , 1, 506L); - message.setExtension(UnittestProto.repeatedFixed32Extension , 1, 507); - message.setExtension(UnittestProto.repeatedFixed64Extension , 1, 508L); - message.setExtension(UnittestProto.repeatedSfixed32Extension, 1, 509); - message.setExtension(UnittestProto.repeatedSfixed64Extension, 1, 510L); - message.setExtension(UnittestProto.repeatedFloatExtension , 1, 511F); - message.setExtension(UnittestProto.repeatedDoubleExtension , 1, 512D); - message.setExtension(UnittestProto.repeatedBoolExtension , 1, true); - message.setExtension(UnittestProto.repeatedStringExtension , 1, "515"); - message.setExtension(UnittestProto.repeatedBytesExtension , 1, toBytes("516")); - - message.setExtension(UnittestProto.repeatedGroupExtension, 1, - UnittestProto.RepeatedGroup_extension.newBuilder().setA(517).build()); - message.setExtension(UnittestProto.repeatedNestedMessageExtension, 1, + message.setExtension(repeatedInt32Extension , 1, 501); + message.setExtension(repeatedInt64Extension , 1, 502L); + message.setExtension(repeatedUint32Extension , 1, 503); + message.setExtension(repeatedUint64Extension , 1, 504L); + message.setExtension(repeatedSint32Extension , 1, 505); + message.setExtension(repeatedSint64Extension , 1, 506L); + message.setExtension(repeatedFixed32Extension , 1, 507); + message.setExtension(repeatedFixed64Extension , 1, 508L); + message.setExtension(repeatedSfixed32Extension, 1, 509); + message.setExtension(repeatedSfixed64Extension, 1, 510L); + message.setExtension(repeatedFloatExtension , 1, 511F); + message.setExtension(repeatedDoubleExtension , 1, 512D); + message.setExtension(repeatedBoolExtension , 1, true); + message.setExtension(repeatedStringExtension , 1, "515"); + message.setExtension(repeatedBytesExtension , 1, toBytes("516")); + + message.setExtension(repeatedGroupExtension, 1, + RepeatedGroup_extension.newBuilder().setA(517).build()); + message.setExtension(repeatedNestedMessageExtension, 1, TestAllTypes.NestedMessage.newBuilder().setBb(518).build()); - message.setExtension(UnittestProto.repeatedForeignMessageExtension, 1, + message.setExtension(repeatedForeignMessageExtension, 1, ForeignMessage.newBuilder().setC(519).build()); - message.setExtension(UnittestProto.repeatedImportMessageExtension, 1, + message.setExtension(repeatedImportMessageExtension, 1, ImportMessage.newBuilder().setD(520).build()); - message.setExtension(UnittestProto.repeatedNestedEnumExtension , 1, - TestAllTypes.NestedEnum.FOO); - message.setExtension(UnittestProto.repeatedForeignEnumExtension, 1, - ForeignEnum.FOREIGN_FOO); - message.setExtension(UnittestProto.repeatedImportEnumExtension , 1, - ImportEnum.IMPORT_FOO); + message.setExtension(repeatedNestedEnumExtension , 1, TestAllTypes.NestedEnum.FOO); + message.setExtension(repeatedForeignEnumExtension, 1, ForeignEnum.FOREIGN_FOO); + message.setExtension(repeatedImportEnumExtension , 1, ImportEnum.IMPORT_FOO); - message.setExtension(UnittestProto.repeatedStringPieceExtension, 1, "524"); - message.setExtension(UnittestProto.repeatedCordExtension, 1, "525"); + message.setExtension(repeatedStringPieceExtension, 1, "524"); + message.setExtension(repeatedCordExtension, 1, "525"); } // ------------------------------------------------------------------- @@ -958,211 +1043,211 @@ class TestUtil { * {@code message} are set to the values assigned by {@code setAllExtensions}. */ public static void assertAllExtensionsSet(TestAllExtensions message) { - Assert.assertTrue(message.hasExtension(UnittestProto.optionalInt32Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalInt64Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalUint32Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalUint64Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalSint32Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalSint64Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalFixed32Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalFixed64Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalSfixed32Extension)); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalSfixed64Extension)); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalFloatExtension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalDoubleExtension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalBoolExtension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalStringExtension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalBytesExtension )); - - Assert.assertTrue(message.hasExtension(UnittestProto.optionalGroupExtension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalNestedMessageExtension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalForeignMessageExtension)); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalImportMessageExtension )); - - Assert.assertTrue(message.getExtension(UnittestProto.optionalGroupExtension ).hasA()); - Assert.assertTrue(message.getExtension(UnittestProto.optionalNestedMessageExtension ).hasBb()); - Assert.assertTrue(message.getExtension(UnittestProto.optionalForeignMessageExtension).hasC()); - Assert.assertTrue(message.getExtension(UnittestProto.optionalImportMessageExtension ).hasD()); - - Assert.assertTrue(message.hasExtension(UnittestProto.optionalNestedEnumExtension )); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalForeignEnumExtension)); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalImportEnumExtension )); - - Assert.assertTrue(message.hasExtension(UnittestProto.optionalStringPieceExtension)); - Assert.assertTrue(message.hasExtension(UnittestProto.optionalCordExtension)); - - assertEqualsExactType(101 , message.getExtension(UnittestProto.optionalInt32Extension )); - assertEqualsExactType(102L , message.getExtension(UnittestProto.optionalInt64Extension )); - assertEqualsExactType(103 , message.getExtension(UnittestProto.optionalUint32Extension )); - assertEqualsExactType(104L , message.getExtension(UnittestProto.optionalUint64Extension )); - assertEqualsExactType(105 , message.getExtension(UnittestProto.optionalSint32Extension )); - assertEqualsExactType(106L , message.getExtension(UnittestProto.optionalSint64Extension )); - assertEqualsExactType(107 , message.getExtension(UnittestProto.optionalFixed32Extension )); - assertEqualsExactType(108L , message.getExtension(UnittestProto.optionalFixed64Extension )); - assertEqualsExactType(109 , message.getExtension(UnittestProto.optionalSfixed32Extension)); - assertEqualsExactType(110L , message.getExtension(UnittestProto.optionalSfixed64Extension)); - assertEqualsExactType(111F , message.getExtension(UnittestProto.optionalFloatExtension )); - assertEqualsExactType(112D , message.getExtension(UnittestProto.optionalDoubleExtension )); - assertEqualsExactType(true , message.getExtension(UnittestProto.optionalBoolExtension )); - assertEqualsExactType("115", message.getExtension(UnittestProto.optionalStringExtension )); - assertEqualsExactType(toBytes("116"), message.getExtension(UnittestProto.optionalBytesExtension)); - - assertEqualsExactType(117, message.getExtension(UnittestProto.optionalGroupExtension ).getA()); - assertEqualsExactType(118, message.getExtension(UnittestProto.optionalNestedMessageExtension ).getBb()); - assertEqualsExactType(119, message.getExtension(UnittestProto.optionalForeignMessageExtension).getC()); - assertEqualsExactType(120, message.getExtension(UnittestProto.optionalImportMessageExtension ).getD()); + Assert.assertTrue(message.hasExtension(optionalInt32Extension )); + Assert.assertTrue(message.hasExtension(optionalInt64Extension )); + Assert.assertTrue(message.hasExtension(optionalUint32Extension )); + Assert.assertTrue(message.hasExtension(optionalUint64Extension )); + Assert.assertTrue(message.hasExtension(optionalSint32Extension )); + Assert.assertTrue(message.hasExtension(optionalSint64Extension )); + Assert.assertTrue(message.hasExtension(optionalFixed32Extension )); + Assert.assertTrue(message.hasExtension(optionalFixed64Extension )); + Assert.assertTrue(message.hasExtension(optionalSfixed32Extension)); + Assert.assertTrue(message.hasExtension(optionalSfixed64Extension)); + Assert.assertTrue(message.hasExtension(optionalFloatExtension )); + Assert.assertTrue(message.hasExtension(optionalDoubleExtension )); + Assert.assertTrue(message.hasExtension(optionalBoolExtension )); + Assert.assertTrue(message.hasExtension(optionalStringExtension )); + Assert.assertTrue(message.hasExtension(optionalBytesExtension )); + + Assert.assertTrue(message.hasExtension(optionalGroupExtension )); + Assert.assertTrue(message.hasExtension(optionalNestedMessageExtension )); + Assert.assertTrue(message.hasExtension(optionalForeignMessageExtension)); + Assert.assertTrue(message.hasExtension(optionalImportMessageExtension )); + + Assert.assertTrue(message.getExtension(optionalGroupExtension ).hasA()); + Assert.assertTrue(message.getExtension(optionalNestedMessageExtension ).hasBb()); + Assert.assertTrue(message.getExtension(optionalForeignMessageExtension).hasC()); + Assert.assertTrue(message.getExtension(optionalImportMessageExtension ).hasD()); + + Assert.assertTrue(message.hasExtension(optionalNestedEnumExtension )); + Assert.assertTrue(message.hasExtension(optionalForeignEnumExtension)); + Assert.assertTrue(message.hasExtension(optionalImportEnumExtension )); + + Assert.assertTrue(message.hasExtension(optionalStringPieceExtension)); + Assert.assertTrue(message.hasExtension(optionalCordExtension)); + + assertEqualsExactType(101 , message.getExtension(optionalInt32Extension )); + assertEqualsExactType(102L , message.getExtension(optionalInt64Extension )); + assertEqualsExactType(103 , message.getExtension(optionalUint32Extension )); + assertEqualsExactType(104L , message.getExtension(optionalUint64Extension )); + assertEqualsExactType(105 , message.getExtension(optionalSint32Extension )); + assertEqualsExactType(106L , message.getExtension(optionalSint64Extension )); + assertEqualsExactType(107 , message.getExtension(optionalFixed32Extension )); + assertEqualsExactType(108L , message.getExtension(optionalFixed64Extension )); + assertEqualsExactType(109 , message.getExtension(optionalSfixed32Extension)); + assertEqualsExactType(110L , message.getExtension(optionalSfixed64Extension)); + assertEqualsExactType(111F , message.getExtension(optionalFloatExtension )); + assertEqualsExactType(112D , message.getExtension(optionalDoubleExtension )); + assertEqualsExactType(true , message.getExtension(optionalBoolExtension )); + assertEqualsExactType("115", message.getExtension(optionalStringExtension )); + assertEqualsExactType(toBytes("116"), message.getExtension(optionalBytesExtension)); + + assertEqualsExactType(117, message.getExtension(optionalGroupExtension ).getA()); + assertEqualsExactType(118, message.getExtension(optionalNestedMessageExtension ).getBb()); + assertEqualsExactType(119, message.getExtension(optionalForeignMessageExtension).getC()); + assertEqualsExactType(120, message.getExtension(optionalImportMessageExtension ).getD()); assertEqualsExactType(TestAllTypes.NestedEnum.BAZ, - message.getExtension(UnittestProto.optionalNestedEnumExtension)); + message.getExtension(optionalNestedEnumExtension)); assertEqualsExactType(ForeignEnum.FOREIGN_BAZ, - message.getExtension(UnittestProto.optionalForeignEnumExtension)); + message.getExtension(optionalForeignEnumExtension)); assertEqualsExactType(ImportEnum.IMPORT_BAZ, - message.getExtension(UnittestProto.optionalImportEnumExtension)); + message.getExtension(optionalImportEnumExtension)); - assertEqualsExactType("124", message.getExtension(UnittestProto.optionalStringPieceExtension)); - assertEqualsExactType("125", message.getExtension(UnittestProto.optionalCordExtension)); + assertEqualsExactType("124", message.getExtension(optionalStringPieceExtension)); + assertEqualsExactType("125", message.getExtension(optionalCordExtension)); // ----------------------------------------------------------------- - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedInt32Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedInt64Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedUint32Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedUint64Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSint32Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSint64Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedFixed32Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedFixed64Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSfixed32Extension)); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSfixed64Extension)); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedFloatExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedDoubleExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedBoolExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedStringExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedBytesExtension )); - - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedGroupExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedNestedMessageExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedForeignMessageExtension)); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedImportMessageExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedNestedEnumExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedForeignEnumExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedImportEnumExtension )); - - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedStringPieceExtension)); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedCordExtension)); - - assertEqualsExactType(201 , message.getExtension(UnittestProto.repeatedInt32Extension , 0)); - assertEqualsExactType(202L , message.getExtension(UnittestProto.repeatedInt64Extension , 0)); - assertEqualsExactType(203 , message.getExtension(UnittestProto.repeatedUint32Extension , 0)); - assertEqualsExactType(204L , message.getExtension(UnittestProto.repeatedUint64Extension , 0)); - assertEqualsExactType(205 , message.getExtension(UnittestProto.repeatedSint32Extension , 0)); - assertEqualsExactType(206L , message.getExtension(UnittestProto.repeatedSint64Extension , 0)); - assertEqualsExactType(207 , message.getExtension(UnittestProto.repeatedFixed32Extension , 0)); - assertEqualsExactType(208L , message.getExtension(UnittestProto.repeatedFixed64Extension , 0)); - assertEqualsExactType(209 , message.getExtension(UnittestProto.repeatedSfixed32Extension, 0)); - assertEqualsExactType(210L , message.getExtension(UnittestProto.repeatedSfixed64Extension, 0)); - assertEqualsExactType(211F , message.getExtension(UnittestProto.repeatedFloatExtension , 0)); - assertEqualsExactType(212D , message.getExtension(UnittestProto.repeatedDoubleExtension , 0)); - assertEqualsExactType(true , message.getExtension(UnittestProto.repeatedBoolExtension , 0)); - assertEqualsExactType("215", message.getExtension(UnittestProto.repeatedStringExtension , 0)); - assertEqualsExactType(toBytes("216"), message.getExtension(UnittestProto.repeatedBytesExtension, 0)); - - assertEqualsExactType(217, message.getExtension(UnittestProto.repeatedGroupExtension , 0).getA()); - assertEqualsExactType(218, message.getExtension(UnittestProto.repeatedNestedMessageExtension , 0).getBb()); - assertEqualsExactType(219, message.getExtension(UnittestProto.repeatedForeignMessageExtension, 0).getC()); - assertEqualsExactType(220, message.getExtension(UnittestProto.repeatedImportMessageExtension , 0).getD()); + Assert.assertEquals(2, message.getExtensionCount(repeatedInt32Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedInt64Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedUint32Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedUint64Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedSint32Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedSint64Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32Extension)); + Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64Extension)); + Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtension )); + + Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtension)); + Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtension )); + + Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtension)); + Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtension)); + + assertEqualsExactType(201 , message.getExtension(repeatedInt32Extension , 0)); + assertEqualsExactType(202L , message.getExtension(repeatedInt64Extension , 0)); + assertEqualsExactType(203 , message.getExtension(repeatedUint32Extension , 0)); + assertEqualsExactType(204L , message.getExtension(repeatedUint64Extension , 0)); + assertEqualsExactType(205 , message.getExtension(repeatedSint32Extension , 0)); + assertEqualsExactType(206L , message.getExtension(repeatedSint64Extension , 0)); + assertEqualsExactType(207 , message.getExtension(repeatedFixed32Extension , 0)); + assertEqualsExactType(208L , message.getExtension(repeatedFixed64Extension , 0)); + assertEqualsExactType(209 , message.getExtension(repeatedSfixed32Extension, 0)); + assertEqualsExactType(210L , message.getExtension(repeatedSfixed64Extension, 0)); + assertEqualsExactType(211F , message.getExtension(repeatedFloatExtension , 0)); + assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtension , 0)); + assertEqualsExactType(true , message.getExtension(repeatedBoolExtension , 0)); + assertEqualsExactType("215", message.getExtension(repeatedStringExtension , 0)); + assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtension, 0)); + + assertEqualsExactType(217, message.getExtension(repeatedGroupExtension , 0).getA()); + assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtension , 0).getBb()); + assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtension, 0).getC()); + assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtension , 0).getD()); assertEqualsExactType(TestAllTypes.NestedEnum.BAR, - message.getExtension(UnittestProto.repeatedNestedEnumExtension, 0)); + message.getExtension(repeatedNestedEnumExtension, 0)); assertEqualsExactType(ForeignEnum.FOREIGN_BAR, - message.getExtension(UnittestProto.repeatedForeignEnumExtension, 0)); + message.getExtension(repeatedForeignEnumExtension, 0)); assertEqualsExactType(ImportEnum.IMPORT_BAR, - message.getExtension(UnittestProto.repeatedImportEnumExtension, 0)); - - assertEqualsExactType("224", message.getExtension(UnittestProto.repeatedStringPieceExtension, 0)); - assertEqualsExactType("225", message.getExtension(UnittestProto.repeatedCordExtension, 0)); - - assertEqualsExactType(301 , message.getExtension(UnittestProto.repeatedInt32Extension , 1)); - assertEqualsExactType(302L , message.getExtension(UnittestProto.repeatedInt64Extension , 1)); - assertEqualsExactType(303 , message.getExtension(UnittestProto.repeatedUint32Extension , 1)); - assertEqualsExactType(304L , message.getExtension(UnittestProto.repeatedUint64Extension , 1)); - assertEqualsExactType(305 , message.getExtension(UnittestProto.repeatedSint32Extension , 1)); - assertEqualsExactType(306L , message.getExtension(UnittestProto.repeatedSint64Extension , 1)); - assertEqualsExactType(307 , message.getExtension(UnittestProto.repeatedFixed32Extension , 1)); - assertEqualsExactType(308L , message.getExtension(UnittestProto.repeatedFixed64Extension , 1)); - assertEqualsExactType(309 , message.getExtension(UnittestProto.repeatedSfixed32Extension, 1)); - assertEqualsExactType(310L , message.getExtension(UnittestProto.repeatedSfixed64Extension, 1)); - assertEqualsExactType(311F , message.getExtension(UnittestProto.repeatedFloatExtension , 1)); - assertEqualsExactType(312D , message.getExtension(UnittestProto.repeatedDoubleExtension , 1)); - assertEqualsExactType(false, message.getExtension(UnittestProto.repeatedBoolExtension , 1)); - assertEqualsExactType("315", message.getExtension(UnittestProto.repeatedStringExtension , 1)); - assertEqualsExactType(toBytes("316"), message.getExtension(UnittestProto.repeatedBytesExtension, 1)); - - assertEqualsExactType(317, message.getExtension(UnittestProto.repeatedGroupExtension , 1).getA()); - assertEqualsExactType(318, message.getExtension(UnittestProto.repeatedNestedMessageExtension , 1).getBb()); - assertEqualsExactType(319, message.getExtension(UnittestProto.repeatedForeignMessageExtension, 1).getC()); - assertEqualsExactType(320, message.getExtension(UnittestProto.repeatedImportMessageExtension , 1).getD()); + message.getExtension(repeatedImportEnumExtension, 0)); + + assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtension, 0)); + assertEqualsExactType("225", message.getExtension(repeatedCordExtension, 0)); + + assertEqualsExactType(301 , message.getExtension(repeatedInt32Extension , 1)); + assertEqualsExactType(302L , message.getExtension(repeatedInt64Extension , 1)); + assertEqualsExactType(303 , message.getExtension(repeatedUint32Extension , 1)); + assertEqualsExactType(304L , message.getExtension(repeatedUint64Extension , 1)); + assertEqualsExactType(305 , message.getExtension(repeatedSint32Extension , 1)); + assertEqualsExactType(306L , message.getExtension(repeatedSint64Extension , 1)); + assertEqualsExactType(307 , message.getExtension(repeatedFixed32Extension , 1)); + assertEqualsExactType(308L , message.getExtension(repeatedFixed64Extension , 1)); + assertEqualsExactType(309 , message.getExtension(repeatedSfixed32Extension, 1)); + assertEqualsExactType(310L , message.getExtension(repeatedSfixed64Extension, 1)); + assertEqualsExactType(311F , message.getExtension(repeatedFloatExtension , 1)); + assertEqualsExactType(312D , message.getExtension(repeatedDoubleExtension , 1)); + assertEqualsExactType(false, message.getExtension(repeatedBoolExtension , 1)); + assertEqualsExactType("315", message.getExtension(repeatedStringExtension , 1)); + assertEqualsExactType(toBytes("316"), message.getExtension(repeatedBytesExtension, 1)); + + assertEqualsExactType(317, message.getExtension(repeatedGroupExtension , 1).getA()); + assertEqualsExactType(318, message.getExtension(repeatedNestedMessageExtension , 1).getBb()); + assertEqualsExactType(319, message.getExtension(repeatedForeignMessageExtension, 1).getC()); + assertEqualsExactType(320, message.getExtension(repeatedImportMessageExtension , 1).getD()); assertEqualsExactType(TestAllTypes.NestedEnum.BAZ, - message.getExtension(UnittestProto.repeatedNestedEnumExtension, 1)); + message.getExtension(repeatedNestedEnumExtension, 1)); assertEqualsExactType(ForeignEnum.FOREIGN_BAZ, - message.getExtension(UnittestProto.repeatedForeignEnumExtension, 1)); + message.getExtension(repeatedForeignEnumExtension, 1)); assertEqualsExactType(ImportEnum.IMPORT_BAZ, - message.getExtension(UnittestProto.repeatedImportEnumExtension, 1)); + message.getExtension(repeatedImportEnumExtension, 1)); - assertEqualsExactType("324", message.getExtension(UnittestProto.repeatedStringPieceExtension, 1)); - assertEqualsExactType("325", message.getExtension(UnittestProto.repeatedCordExtension, 1)); + assertEqualsExactType("324", message.getExtension(repeatedStringPieceExtension, 1)); + assertEqualsExactType("325", message.getExtension(repeatedCordExtension, 1)); // ----------------------------------------------------------------- - Assert.assertTrue(message.hasExtension(UnittestProto.defaultInt32Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultInt64Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultUint32Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultUint64Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultSint32Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultSint64Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultFixed32Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultFixed64Extension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultSfixed32Extension)); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultSfixed64Extension)); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultFloatExtension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultDoubleExtension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultBoolExtension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultStringExtension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultBytesExtension )); - - Assert.assertTrue(message.hasExtension(UnittestProto.defaultNestedEnumExtension )); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultForeignEnumExtension)); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultImportEnumExtension )); - - Assert.assertTrue(message.hasExtension(UnittestProto.defaultStringPieceExtension)); - Assert.assertTrue(message.hasExtension(UnittestProto.defaultCordExtension)); - - assertEqualsExactType(401 , message.getExtension(UnittestProto.defaultInt32Extension )); - assertEqualsExactType(402L , message.getExtension(UnittestProto.defaultInt64Extension )); - assertEqualsExactType(403 , message.getExtension(UnittestProto.defaultUint32Extension )); - assertEqualsExactType(404L , message.getExtension(UnittestProto.defaultUint64Extension )); - assertEqualsExactType(405 , message.getExtension(UnittestProto.defaultSint32Extension )); - assertEqualsExactType(406L , message.getExtension(UnittestProto.defaultSint64Extension )); - assertEqualsExactType(407 , message.getExtension(UnittestProto.defaultFixed32Extension )); - assertEqualsExactType(408L , message.getExtension(UnittestProto.defaultFixed64Extension )); - assertEqualsExactType(409 , message.getExtension(UnittestProto.defaultSfixed32Extension)); - assertEqualsExactType(410L , message.getExtension(UnittestProto.defaultSfixed64Extension)); - assertEqualsExactType(411F , message.getExtension(UnittestProto.defaultFloatExtension )); - assertEqualsExactType(412D , message.getExtension(UnittestProto.defaultDoubleExtension )); - assertEqualsExactType(false, message.getExtension(UnittestProto.defaultBoolExtension )); - assertEqualsExactType("415", message.getExtension(UnittestProto.defaultStringExtension )); - assertEqualsExactType(toBytes("416"), message.getExtension(UnittestProto.defaultBytesExtension)); + Assert.assertTrue(message.hasExtension(defaultInt32Extension )); + Assert.assertTrue(message.hasExtension(defaultInt64Extension )); + Assert.assertTrue(message.hasExtension(defaultUint32Extension )); + Assert.assertTrue(message.hasExtension(defaultUint64Extension )); + Assert.assertTrue(message.hasExtension(defaultSint32Extension )); + Assert.assertTrue(message.hasExtension(defaultSint64Extension )); + Assert.assertTrue(message.hasExtension(defaultFixed32Extension )); + Assert.assertTrue(message.hasExtension(defaultFixed64Extension )); + Assert.assertTrue(message.hasExtension(defaultSfixed32Extension)); + Assert.assertTrue(message.hasExtension(defaultSfixed64Extension)); + Assert.assertTrue(message.hasExtension(defaultFloatExtension )); + Assert.assertTrue(message.hasExtension(defaultDoubleExtension )); + Assert.assertTrue(message.hasExtension(defaultBoolExtension )); + Assert.assertTrue(message.hasExtension(defaultStringExtension )); + Assert.assertTrue(message.hasExtension(defaultBytesExtension )); + + Assert.assertTrue(message.hasExtension(defaultNestedEnumExtension )); + Assert.assertTrue(message.hasExtension(defaultForeignEnumExtension)); + Assert.assertTrue(message.hasExtension(defaultImportEnumExtension )); + + Assert.assertTrue(message.hasExtension(defaultStringPieceExtension)); + Assert.assertTrue(message.hasExtension(defaultCordExtension)); + + assertEqualsExactType(401 , message.getExtension(defaultInt32Extension )); + assertEqualsExactType(402L , message.getExtension(defaultInt64Extension )); + assertEqualsExactType(403 , message.getExtension(defaultUint32Extension )); + assertEqualsExactType(404L , message.getExtension(defaultUint64Extension )); + assertEqualsExactType(405 , message.getExtension(defaultSint32Extension )); + assertEqualsExactType(406L , message.getExtension(defaultSint64Extension )); + assertEqualsExactType(407 , message.getExtension(defaultFixed32Extension )); + assertEqualsExactType(408L , message.getExtension(defaultFixed64Extension )); + assertEqualsExactType(409 , message.getExtension(defaultSfixed32Extension)); + assertEqualsExactType(410L , message.getExtension(defaultSfixed64Extension)); + assertEqualsExactType(411F , message.getExtension(defaultFloatExtension )); + assertEqualsExactType(412D , message.getExtension(defaultDoubleExtension )); + assertEqualsExactType(false, message.getExtension(defaultBoolExtension )); + assertEqualsExactType("415", message.getExtension(defaultStringExtension )); + assertEqualsExactType(toBytes("416"), message.getExtension(defaultBytesExtension)); assertEqualsExactType(TestAllTypes.NestedEnum.FOO, - message.getExtension(UnittestProto.defaultNestedEnumExtension )); + message.getExtension(defaultNestedEnumExtension )); assertEqualsExactType(ForeignEnum.FOREIGN_FOO, - message.getExtension(UnittestProto.defaultForeignEnumExtension)); + message.getExtension(defaultForeignEnumExtension)); assertEqualsExactType(ImportEnum.IMPORT_FOO, - message.getExtension(UnittestProto.defaultImportEnumExtension)); + message.getExtension(defaultImportEnumExtension)); - assertEqualsExactType("424", message.getExtension(UnittestProto.defaultStringPieceExtension)); - assertEqualsExactType("425", message.getExtension(UnittestProto.defaultCordExtension)); + assertEqualsExactType("424", message.getExtension(defaultStringPieceExtension)); + assertEqualsExactType("425", message.getExtension(defaultCordExtension)); } // ------------------------------------------------------------------- @@ -1174,151 +1259,151 @@ class TestUtil { */ public static void assertExtensionsClear(TestAllExtensions message) { // hasBlah() should initially be false for all optional fields. - Assert.assertFalse(message.hasExtension(UnittestProto.optionalInt32Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalInt64Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalUint32Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalUint64Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalSint32Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalSint64Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalFixed32Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalFixed64Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalSfixed32Extension)); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalSfixed64Extension)); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalFloatExtension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalDoubleExtension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalBoolExtension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalStringExtension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalBytesExtension )); - - Assert.assertFalse(message.hasExtension(UnittestProto.optionalGroupExtension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalNestedMessageExtension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalForeignMessageExtension)); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalImportMessageExtension )); - - Assert.assertFalse(message.hasExtension(UnittestProto.optionalNestedEnumExtension )); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalForeignEnumExtension)); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalImportEnumExtension )); - - Assert.assertFalse(message.hasExtension(UnittestProto.optionalStringPieceExtension)); - Assert.assertFalse(message.hasExtension(UnittestProto.optionalCordExtension)); + Assert.assertFalse(message.hasExtension(optionalInt32Extension )); + Assert.assertFalse(message.hasExtension(optionalInt64Extension )); + Assert.assertFalse(message.hasExtension(optionalUint32Extension )); + Assert.assertFalse(message.hasExtension(optionalUint64Extension )); + Assert.assertFalse(message.hasExtension(optionalSint32Extension )); + Assert.assertFalse(message.hasExtension(optionalSint64Extension )); + Assert.assertFalse(message.hasExtension(optionalFixed32Extension )); + Assert.assertFalse(message.hasExtension(optionalFixed64Extension )); + Assert.assertFalse(message.hasExtension(optionalSfixed32Extension)); + Assert.assertFalse(message.hasExtension(optionalSfixed64Extension)); + Assert.assertFalse(message.hasExtension(optionalFloatExtension )); + Assert.assertFalse(message.hasExtension(optionalDoubleExtension )); + Assert.assertFalse(message.hasExtension(optionalBoolExtension )); + Assert.assertFalse(message.hasExtension(optionalStringExtension )); + Assert.assertFalse(message.hasExtension(optionalBytesExtension )); + + Assert.assertFalse(message.hasExtension(optionalGroupExtension )); + Assert.assertFalse(message.hasExtension(optionalNestedMessageExtension )); + Assert.assertFalse(message.hasExtension(optionalForeignMessageExtension)); + Assert.assertFalse(message.hasExtension(optionalImportMessageExtension )); + + Assert.assertFalse(message.hasExtension(optionalNestedEnumExtension )); + Assert.assertFalse(message.hasExtension(optionalForeignEnumExtension)); + Assert.assertFalse(message.hasExtension(optionalImportEnumExtension )); + + Assert.assertFalse(message.hasExtension(optionalStringPieceExtension)); + Assert.assertFalse(message.hasExtension(optionalCordExtension)); // Optional fields without defaults are set to zero or something like it. - assertEqualsExactType(0 , message.getExtension(UnittestProto.optionalInt32Extension )); - assertEqualsExactType(0L , message.getExtension(UnittestProto.optionalInt64Extension )); - assertEqualsExactType(0 , message.getExtension(UnittestProto.optionalUint32Extension )); - assertEqualsExactType(0L , message.getExtension(UnittestProto.optionalUint64Extension )); - assertEqualsExactType(0 , message.getExtension(UnittestProto.optionalSint32Extension )); - assertEqualsExactType(0L , message.getExtension(UnittestProto.optionalSint64Extension )); - assertEqualsExactType(0 , message.getExtension(UnittestProto.optionalFixed32Extension )); - assertEqualsExactType(0L , message.getExtension(UnittestProto.optionalFixed64Extension )); - assertEqualsExactType(0 , message.getExtension(UnittestProto.optionalSfixed32Extension)); - assertEqualsExactType(0L , message.getExtension(UnittestProto.optionalSfixed64Extension)); - assertEqualsExactType(0F , message.getExtension(UnittestProto.optionalFloatExtension )); - assertEqualsExactType(0D , message.getExtension(UnittestProto.optionalDoubleExtension )); - assertEqualsExactType(false, message.getExtension(UnittestProto.optionalBoolExtension )); - assertEqualsExactType("" , message.getExtension(UnittestProto.optionalStringExtension )); - assertEqualsExactType(ByteString.EMPTY, message.getExtension(UnittestProto.optionalBytesExtension)); + assertEqualsExactType(0 , message.getExtension(optionalInt32Extension )); + assertEqualsExactType(0L , message.getExtension(optionalInt64Extension )); + assertEqualsExactType(0 , message.getExtension(optionalUint32Extension )); + assertEqualsExactType(0L , message.getExtension(optionalUint64Extension )); + assertEqualsExactType(0 , message.getExtension(optionalSint32Extension )); + assertEqualsExactType(0L , message.getExtension(optionalSint64Extension )); + assertEqualsExactType(0 , message.getExtension(optionalFixed32Extension )); + assertEqualsExactType(0L , message.getExtension(optionalFixed64Extension )); + assertEqualsExactType(0 , message.getExtension(optionalSfixed32Extension)); + assertEqualsExactType(0L , message.getExtension(optionalSfixed64Extension)); + assertEqualsExactType(0F , message.getExtension(optionalFloatExtension )); + assertEqualsExactType(0D , message.getExtension(optionalDoubleExtension )); + assertEqualsExactType(false, message.getExtension(optionalBoolExtension )); + assertEqualsExactType("" , message.getExtension(optionalStringExtension )); + assertEqualsExactType(ByteString.EMPTY, message.getExtension(optionalBytesExtension)); // Embedded messages should also be clear. - Assert.assertFalse(message.getExtension(UnittestProto.optionalGroupExtension ).hasA()); - Assert.assertFalse(message.getExtension(UnittestProto.optionalNestedMessageExtension ).hasBb()); - Assert.assertFalse(message.getExtension(UnittestProto.optionalForeignMessageExtension).hasC()); - Assert.assertFalse(message.getExtension(UnittestProto.optionalImportMessageExtension ).hasD()); + Assert.assertFalse(message.getExtension(optionalGroupExtension ).hasA()); + Assert.assertFalse(message.getExtension(optionalNestedMessageExtension ).hasBb()); + Assert.assertFalse(message.getExtension(optionalForeignMessageExtension).hasC()); + Assert.assertFalse(message.getExtension(optionalImportMessageExtension ).hasD()); - assertEqualsExactType(0, message.getExtension(UnittestProto.optionalGroupExtension ).getA()); - assertEqualsExactType(0, message.getExtension(UnittestProto.optionalNestedMessageExtension ).getBb()); - assertEqualsExactType(0, message.getExtension(UnittestProto.optionalForeignMessageExtension).getC()); - assertEqualsExactType(0, message.getExtension(UnittestProto.optionalImportMessageExtension ).getD()); + assertEqualsExactType(0, message.getExtension(optionalGroupExtension ).getA()); + assertEqualsExactType(0, message.getExtension(optionalNestedMessageExtension ).getBb()); + assertEqualsExactType(0, message.getExtension(optionalForeignMessageExtension).getC()); + assertEqualsExactType(0, message.getExtension(optionalImportMessageExtension ).getD()); // Enums without defaults are set to the first value in the enum. assertEqualsExactType(TestAllTypes.NestedEnum.FOO, - message.getExtension(UnittestProto.optionalNestedEnumExtension )); + message.getExtension(optionalNestedEnumExtension )); assertEqualsExactType(ForeignEnum.FOREIGN_FOO, - message.getExtension(UnittestProto.optionalForeignEnumExtension)); + message.getExtension(optionalForeignEnumExtension)); assertEqualsExactType(ImportEnum.IMPORT_FOO, - message.getExtension(UnittestProto.optionalImportEnumExtension)); + message.getExtension(optionalImportEnumExtension)); - assertEqualsExactType("", message.getExtension(UnittestProto.optionalStringPieceExtension)); - assertEqualsExactType("", message.getExtension(UnittestProto.optionalCordExtension)); + assertEqualsExactType("", message.getExtension(optionalStringPieceExtension)); + assertEqualsExactType("", message.getExtension(optionalCordExtension)); // Repeated fields are empty. - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedInt32Extension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedInt64Extension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedUint32Extension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedUint64Extension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedSint32Extension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedSint64Extension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedFixed32Extension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedFixed64Extension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedSfixed32Extension)); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedSfixed64Extension)); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedFloatExtension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedDoubleExtension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedBoolExtension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedStringExtension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedBytesExtension )); - - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedGroupExtension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedNestedMessageExtension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedForeignMessageExtension)); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedImportMessageExtension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedNestedEnumExtension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedForeignEnumExtension )); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedImportEnumExtension )); - - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedStringPieceExtension)); - Assert.assertEquals(0, message.getExtensionCount(UnittestProto.repeatedCordExtension)); + Assert.assertEquals(0, message.getExtensionCount(repeatedInt32Extension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedInt64Extension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedUint32Extension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedUint64Extension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedSint32Extension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedSint64Extension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedFixed32Extension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedFixed64Extension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed32Extension)); + Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed64Extension)); + Assert.assertEquals(0, message.getExtensionCount(repeatedFloatExtension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedDoubleExtension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedBoolExtension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedStringExtension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedBytesExtension )); + + Assert.assertEquals(0, message.getExtensionCount(repeatedGroupExtension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedNestedMessageExtension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedForeignMessageExtension)); + Assert.assertEquals(0, message.getExtensionCount(repeatedImportMessageExtension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedNestedEnumExtension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedForeignEnumExtension )); + Assert.assertEquals(0, message.getExtensionCount(repeatedImportEnumExtension )); + + Assert.assertEquals(0, message.getExtensionCount(repeatedStringPieceExtension)); + Assert.assertEquals(0, message.getExtensionCount(repeatedCordExtension)); // hasBlah() should also be false for all default fields. - Assert.assertFalse(message.hasExtension(UnittestProto.defaultInt32Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultInt64Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultUint32Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultUint64Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultSint32Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultSint64Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultFixed32Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultFixed64Extension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultSfixed32Extension)); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultSfixed64Extension)); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultFloatExtension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultDoubleExtension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultBoolExtension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultStringExtension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultBytesExtension )); - - Assert.assertFalse(message.hasExtension(UnittestProto.defaultNestedEnumExtension )); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultForeignEnumExtension)); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultImportEnumExtension )); - - Assert.assertFalse(message.hasExtension(UnittestProto.defaultStringPieceExtension)); - Assert.assertFalse(message.hasExtension(UnittestProto.defaultCordExtension)); + Assert.assertFalse(message.hasExtension(defaultInt32Extension )); + Assert.assertFalse(message.hasExtension(defaultInt64Extension )); + Assert.assertFalse(message.hasExtension(defaultUint32Extension )); + Assert.assertFalse(message.hasExtension(defaultUint64Extension )); + Assert.assertFalse(message.hasExtension(defaultSint32Extension )); + Assert.assertFalse(message.hasExtension(defaultSint64Extension )); + Assert.assertFalse(message.hasExtension(defaultFixed32Extension )); + Assert.assertFalse(message.hasExtension(defaultFixed64Extension )); + Assert.assertFalse(message.hasExtension(defaultSfixed32Extension)); + Assert.assertFalse(message.hasExtension(defaultSfixed64Extension)); + Assert.assertFalse(message.hasExtension(defaultFloatExtension )); + Assert.assertFalse(message.hasExtension(defaultDoubleExtension )); + Assert.assertFalse(message.hasExtension(defaultBoolExtension )); + Assert.assertFalse(message.hasExtension(defaultStringExtension )); + Assert.assertFalse(message.hasExtension(defaultBytesExtension )); + + Assert.assertFalse(message.hasExtension(defaultNestedEnumExtension )); + Assert.assertFalse(message.hasExtension(defaultForeignEnumExtension)); + Assert.assertFalse(message.hasExtension(defaultImportEnumExtension )); + + Assert.assertFalse(message.hasExtension(defaultStringPieceExtension)); + Assert.assertFalse(message.hasExtension(defaultCordExtension)); // Fields with defaults have their default values (duh). - assertEqualsExactType( 41 , message.getExtension(UnittestProto.defaultInt32Extension )); - assertEqualsExactType( 42L , message.getExtension(UnittestProto.defaultInt64Extension )); - assertEqualsExactType( 43 , message.getExtension(UnittestProto.defaultUint32Extension )); - assertEqualsExactType( 44L , message.getExtension(UnittestProto.defaultUint64Extension )); - assertEqualsExactType(-45 , message.getExtension(UnittestProto.defaultSint32Extension )); - assertEqualsExactType( 46L , message.getExtension(UnittestProto.defaultSint64Extension )); - assertEqualsExactType( 47 , message.getExtension(UnittestProto.defaultFixed32Extension )); - assertEqualsExactType( 48L , message.getExtension(UnittestProto.defaultFixed64Extension )); - assertEqualsExactType( 49 , message.getExtension(UnittestProto.defaultSfixed32Extension)); - assertEqualsExactType(-50L , message.getExtension(UnittestProto.defaultSfixed64Extension)); - assertEqualsExactType( 51.5F , message.getExtension(UnittestProto.defaultFloatExtension )); - assertEqualsExactType( 52e3D , message.getExtension(UnittestProto.defaultDoubleExtension )); - assertEqualsExactType(true , message.getExtension(UnittestProto.defaultBoolExtension )); - assertEqualsExactType("hello", message.getExtension(UnittestProto.defaultStringExtension )); - assertEqualsExactType(toBytes("world"), message.getExtension(UnittestProto.defaultBytesExtension)); + assertEqualsExactType( 41 , message.getExtension(defaultInt32Extension )); + assertEqualsExactType( 42L , message.getExtension(defaultInt64Extension )); + assertEqualsExactType( 43 , message.getExtension(defaultUint32Extension )); + assertEqualsExactType( 44L , message.getExtension(defaultUint64Extension )); + assertEqualsExactType(-45 , message.getExtension(defaultSint32Extension )); + assertEqualsExactType( 46L , message.getExtension(defaultSint64Extension )); + assertEqualsExactType( 47 , message.getExtension(defaultFixed32Extension )); + assertEqualsExactType( 48L , message.getExtension(defaultFixed64Extension )); + assertEqualsExactType( 49 , message.getExtension(defaultSfixed32Extension)); + assertEqualsExactType(-50L , message.getExtension(defaultSfixed64Extension)); + assertEqualsExactType( 51.5F , message.getExtension(defaultFloatExtension )); + assertEqualsExactType( 52e3D , message.getExtension(defaultDoubleExtension )); + assertEqualsExactType(true , message.getExtension(defaultBoolExtension )); + assertEqualsExactType("hello", message.getExtension(defaultStringExtension )); + assertEqualsExactType(toBytes("world"), message.getExtension(defaultBytesExtension)); assertEqualsExactType(TestAllTypes.NestedEnum.BAR, - message.getExtension(UnittestProto.defaultNestedEnumExtension )); + message.getExtension(defaultNestedEnumExtension )); assertEqualsExactType(ForeignEnum.FOREIGN_BAR, - message.getExtension(UnittestProto.defaultForeignEnumExtension)); + message.getExtension(defaultForeignEnumExtension)); assertEqualsExactType(ImportEnum.IMPORT_BAR, - message.getExtension(UnittestProto.defaultImportEnumExtension)); + message.getExtension(defaultImportEnumExtension)); - assertEqualsExactType("abc", message.getExtension(UnittestProto.defaultStringPieceExtension)); - assertEqualsExactType("123", message.getExtension(UnittestProto.defaultCordExtension)); + assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtension)); + assertEqualsExactType("123", message.getExtension(defaultCordExtension)); } // ------------------------------------------------------------------- @@ -1333,97 +1418,261 @@ class TestUtil { // ModifyRepeatedFields only sets the second repeated element of each // field. In addition to verifying this, we also verify that the first // element and size were *not* modified. - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedInt32Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedInt64Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedUint32Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedUint64Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSint32Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSint64Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedFixed32Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedFixed64Extension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSfixed32Extension)); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedSfixed64Extension)); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedFloatExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedDoubleExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedBoolExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedStringExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedBytesExtension )); - - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedGroupExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedNestedMessageExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedForeignMessageExtension)); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedImportMessageExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedNestedEnumExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedForeignEnumExtension )); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedImportEnumExtension )); - - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedStringPieceExtension)); - Assert.assertEquals(2, message.getExtensionCount(UnittestProto.repeatedCordExtension)); - - assertEqualsExactType(201 , message.getExtension(UnittestProto.repeatedInt32Extension , 0)); - assertEqualsExactType(202L , message.getExtension(UnittestProto.repeatedInt64Extension , 0)); - assertEqualsExactType(203 , message.getExtension(UnittestProto.repeatedUint32Extension , 0)); - assertEqualsExactType(204L , message.getExtension(UnittestProto.repeatedUint64Extension , 0)); - assertEqualsExactType(205 , message.getExtension(UnittestProto.repeatedSint32Extension , 0)); - assertEqualsExactType(206L , message.getExtension(UnittestProto.repeatedSint64Extension , 0)); - assertEqualsExactType(207 , message.getExtension(UnittestProto.repeatedFixed32Extension , 0)); - assertEqualsExactType(208L , message.getExtension(UnittestProto.repeatedFixed64Extension , 0)); - assertEqualsExactType(209 , message.getExtension(UnittestProto.repeatedSfixed32Extension, 0)); - assertEqualsExactType(210L , message.getExtension(UnittestProto.repeatedSfixed64Extension, 0)); - assertEqualsExactType(211F , message.getExtension(UnittestProto.repeatedFloatExtension , 0)); - assertEqualsExactType(212D , message.getExtension(UnittestProto.repeatedDoubleExtension , 0)); - assertEqualsExactType(true , message.getExtension(UnittestProto.repeatedBoolExtension , 0)); - assertEqualsExactType("215", message.getExtension(UnittestProto.repeatedStringExtension , 0)); - assertEqualsExactType(toBytes("216"), message.getExtension(UnittestProto.repeatedBytesExtension, 0)); - - assertEqualsExactType(217, message.getExtension(UnittestProto.repeatedGroupExtension , 0).getA()); - assertEqualsExactType(218, message.getExtension(UnittestProto.repeatedNestedMessageExtension , 0).getBb()); - assertEqualsExactType(219, message.getExtension(UnittestProto.repeatedForeignMessageExtension, 0).getC()); - assertEqualsExactType(220, message.getExtension(UnittestProto.repeatedImportMessageExtension , 0).getD()); + Assert.assertEquals(2, message.getExtensionCount(repeatedInt32Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedInt64Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedUint32Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedUint64Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedSint32Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedSint64Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64Extension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32Extension)); + Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64Extension)); + Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtension )); + + Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtension)); + Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtension )); + Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtension )); + + Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtension)); + Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtension)); + + assertEqualsExactType(201 , message.getExtension(repeatedInt32Extension , 0)); + assertEqualsExactType(202L , message.getExtension(repeatedInt64Extension , 0)); + assertEqualsExactType(203 , message.getExtension(repeatedUint32Extension , 0)); + assertEqualsExactType(204L , message.getExtension(repeatedUint64Extension , 0)); + assertEqualsExactType(205 , message.getExtension(repeatedSint32Extension , 0)); + assertEqualsExactType(206L , message.getExtension(repeatedSint64Extension , 0)); + assertEqualsExactType(207 , message.getExtension(repeatedFixed32Extension , 0)); + assertEqualsExactType(208L , message.getExtension(repeatedFixed64Extension , 0)); + assertEqualsExactType(209 , message.getExtension(repeatedSfixed32Extension, 0)); + assertEqualsExactType(210L , message.getExtension(repeatedSfixed64Extension, 0)); + assertEqualsExactType(211F , message.getExtension(repeatedFloatExtension , 0)); + assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtension , 0)); + assertEqualsExactType(true , message.getExtension(repeatedBoolExtension , 0)); + assertEqualsExactType("215", message.getExtension(repeatedStringExtension , 0)); + assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtension, 0)); + + assertEqualsExactType(217, message.getExtension(repeatedGroupExtension , 0).getA()); + assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtension , 0).getBb()); + assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtension, 0).getC()); + assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtension , 0).getD()); assertEqualsExactType(TestAllTypes.NestedEnum.BAR, - message.getExtension(UnittestProto.repeatedNestedEnumExtension, 0)); + message.getExtension(repeatedNestedEnumExtension, 0)); assertEqualsExactType(ForeignEnum.FOREIGN_BAR, - message.getExtension(UnittestProto.repeatedForeignEnumExtension, 0)); + message.getExtension(repeatedForeignEnumExtension, 0)); assertEqualsExactType(ImportEnum.IMPORT_BAR, - message.getExtension(UnittestProto.repeatedImportEnumExtension, 0)); + message.getExtension(repeatedImportEnumExtension, 0)); - assertEqualsExactType("224", message.getExtension(UnittestProto.repeatedStringPieceExtension, 0)); - assertEqualsExactType("225", message.getExtension(UnittestProto.repeatedCordExtension, 0)); + assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtension, 0)); + assertEqualsExactType("225", message.getExtension(repeatedCordExtension, 0)); // Actually verify the second (modified) elements now. - assertEqualsExactType(501 , message.getExtension(UnittestProto.repeatedInt32Extension , 1)); - assertEqualsExactType(502L , message.getExtension(UnittestProto.repeatedInt64Extension , 1)); - assertEqualsExactType(503 , message.getExtension(UnittestProto.repeatedUint32Extension , 1)); - assertEqualsExactType(504L , message.getExtension(UnittestProto.repeatedUint64Extension , 1)); - assertEqualsExactType(505 , message.getExtension(UnittestProto.repeatedSint32Extension , 1)); - assertEqualsExactType(506L , message.getExtension(UnittestProto.repeatedSint64Extension , 1)); - assertEqualsExactType(507 , message.getExtension(UnittestProto.repeatedFixed32Extension , 1)); - assertEqualsExactType(508L , message.getExtension(UnittestProto.repeatedFixed64Extension , 1)); - assertEqualsExactType(509 , message.getExtension(UnittestProto.repeatedSfixed32Extension, 1)); - assertEqualsExactType(510L , message.getExtension(UnittestProto.repeatedSfixed64Extension, 1)); - assertEqualsExactType(511F , message.getExtension(UnittestProto.repeatedFloatExtension , 1)); - assertEqualsExactType(512D , message.getExtension(UnittestProto.repeatedDoubleExtension , 1)); - assertEqualsExactType(true , message.getExtension(UnittestProto.repeatedBoolExtension , 1)); - assertEqualsExactType("515", message.getExtension(UnittestProto.repeatedStringExtension , 1)); - assertEqualsExactType(toBytes("516"), message.getExtension(UnittestProto.repeatedBytesExtension, 1)); - - assertEqualsExactType(517, message.getExtension(UnittestProto.repeatedGroupExtension , 1).getA()); - assertEqualsExactType(518, message.getExtension(UnittestProto.repeatedNestedMessageExtension , 1).getBb()); - assertEqualsExactType(519, message.getExtension(UnittestProto.repeatedForeignMessageExtension, 1).getC()); - assertEqualsExactType(520, message.getExtension(UnittestProto.repeatedImportMessageExtension , 1).getD()); + assertEqualsExactType(501 , message.getExtension(repeatedInt32Extension , 1)); + assertEqualsExactType(502L , message.getExtension(repeatedInt64Extension , 1)); + assertEqualsExactType(503 , message.getExtension(repeatedUint32Extension , 1)); + assertEqualsExactType(504L , message.getExtension(repeatedUint64Extension , 1)); + assertEqualsExactType(505 , message.getExtension(repeatedSint32Extension , 1)); + assertEqualsExactType(506L , message.getExtension(repeatedSint64Extension , 1)); + assertEqualsExactType(507 , message.getExtension(repeatedFixed32Extension , 1)); + assertEqualsExactType(508L , message.getExtension(repeatedFixed64Extension , 1)); + assertEqualsExactType(509 , message.getExtension(repeatedSfixed32Extension, 1)); + assertEqualsExactType(510L , message.getExtension(repeatedSfixed64Extension, 1)); + assertEqualsExactType(511F , message.getExtension(repeatedFloatExtension , 1)); + assertEqualsExactType(512D , message.getExtension(repeatedDoubleExtension , 1)); + assertEqualsExactType(true , message.getExtension(repeatedBoolExtension , 1)); + assertEqualsExactType("515", message.getExtension(repeatedStringExtension , 1)); + assertEqualsExactType(toBytes("516"), message.getExtension(repeatedBytesExtension, 1)); + + assertEqualsExactType(517, message.getExtension(repeatedGroupExtension , 1).getA()); + assertEqualsExactType(518, message.getExtension(repeatedNestedMessageExtension , 1).getBb()); + assertEqualsExactType(519, message.getExtension(repeatedForeignMessageExtension, 1).getC()); + assertEqualsExactType(520, message.getExtension(repeatedImportMessageExtension , 1).getD()); assertEqualsExactType(TestAllTypes.NestedEnum.FOO, - message.getExtension(UnittestProto.repeatedNestedEnumExtension, 1)); + message.getExtension(repeatedNestedEnumExtension, 1)); assertEqualsExactType(ForeignEnum.FOREIGN_FOO, - message.getExtension(UnittestProto.repeatedForeignEnumExtension, 1)); + message.getExtension(repeatedForeignEnumExtension, 1)); assertEqualsExactType(ImportEnum.IMPORT_FOO, - message.getExtension(UnittestProto.repeatedImportEnumExtension, 1)); + message.getExtension(repeatedImportEnumExtension, 1)); + + assertEqualsExactType("524", message.getExtension(repeatedStringPieceExtension, 1)); + assertEqualsExactType("525", message.getExtension(repeatedCordExtension, 1)); + } - assertEqualsExactType("524", message.getExtension(UnittestProto.repeatedStringPieceExtension, 1)); - assertEqualsExactType("525", message.getExtension(UnittestProto.repeatedCordExtension, 1)); + /** + * Set every field of {@code message} to a unique value. + */ + public static void setPackedFields(TestPackedTypes.Builder message) { + message.addPackedInt32 (601); + message.addPackedInt64 (602); + message.addPackedUint32 (603); + message.addPackedUint64 (604); + message.addPackedSint32 (605); + message.addPackedSint64 (606); + message.addPackedFixed32 (607); + message.addPackedFixed64 (608); + message.addPackedSfixed32(609); + message.addPackedSfixed64(610); + message.addPackedFloat (611); + message.addPackedDouble (612); + message.addPackedBool (true); + message.addPackedEnum (ForeignEnum.FOREIGN_BAR); + // Add a second one of each field. + message.addPackedInt32 (701); + message.addPackedInt64 (702); + message.addPackedUint32 (703); + message.addPackedUint64 (704); + message.addPackedSint32 (705); + message.addPackedSint64 (706); + message.addPackedFixed32 (707); + message.addPackedFixed64 (708); + message.addPackedSfixed32(709); + message.addPackedSfixed64(710); + message.addPackedFloat (711); + message.addPackedDouble (712); + message.addPackedBool (false); + message.addPackedEnum (ForeignEnum.FOREIGN_BAZ); } + /** + * Assert (using {@code junit.framework.Assert}} that all fields of + * {@code message} are set to the values assigned by {@code setPackedFields}. + */ + public static void assertPackedFieldsSet(TestPackedTypes message) { + Assert.assertEquals(2, message.getPackedInt32Count ()); + Assert.assertEquals(2, message.getPackedInt64Count ()); + Assert.assertEquals(2, message.getPackedUint32Count ()); + Assert.assertEquals(2, message.getPackedUint64Count ()); + Assert.assertEquals(2, message.getPackedSint32Count ()); + Assert.assertEquals(2, message.getPackedSint64Count ()); + Assert.assertEquals(2, message.getPackedFixed32Count ()); + Assert.assertEquals(2, message.getPackedFixed64Count ()); + Assert.assertEquals(2, message.getPackedSfixed32Count()); + Assert.assertEquals(2, message.getPackedSfixed64Count()); + Assert.assertEquals(2, message.getPackedFloatCount ()); + Assert.assertEquals(2, message.getPackedDoubleCount ()); + Assert.assertEquals(2, message.getPackedBoolCount ()); + Assert.assertEquals(2, message.getPackedEnumCount ()); + Assert.assertEquals(601 , message.getPackedInt32 (0)); + Assert.assertEquals(602 , message.getPackedInt64 (0)); + Assert.assertEquals(603 , message.getPackedUint32 (0)); + Assert.assertEquals(604 , message.getPackedUint64 (0)); + Assert.assertEquals(605 , message.getPackedSint32 (0)); + Assert.assertEquals(606 , message.getPackedSint64 (0)); + Assert.assertEquals(607 , message.getPackedFixed32 (0)); + Assert.assertEquals(608 , message.getPackedFixed64 (0)); + Assert.assertEquals(609 , message.getPackedSfixed32(0)); + Assert.assertEquals(610 , message.getPackedSfixed64(0)); + Assert.assertEquals(611 , message.getPackedFloat (0), 0.0); + Assert.assertEquals(612 , message.getPackedDouble (0), 0.0); + Assert.assertEquals(true , message.getPackedBool (0)); + Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getPackedEnum(0)); + Assert.assertEquals(701 , message.getPackedInt32 (1)); + Assert.assertEquals(702 , message.getPackedInt64 (1)); + Assert.assertEquals(703 , message.getPackedUint32 (1)); + Assert.assertEquals(704 , message.getPackedUint64 (1)); + Assert.assertEquals(705 , message.getPackedSint32 (1)); + Assert.assertEquals(706 , message.getPackedSint64 (1)); + Assert.assertEquals(707 , message.getPackedFixed32 (1)); + Assert.assertEquals(708 , message.getPackedFixed64 (1)); + Assert.assertEquals(709 , message.getPackedSfixed32(1)); + Assert.assertEquals(710 , message.getPackedSfixed64(1)); + Assert.assertEquals(711 , message.getPackedFloat (1), 0.0); + Assert.assertEquals(712 , message.getPackedDouble (1), 0.0); + Assert.assertEquals(false, message.getPackedBool (1)); + Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getPackedEnum(1)); + } + + public static void setPackedExtensions(TestPackedExtensions.Builder message) { + message.addExtension(packedInt32Extension , 601); + message.addExtension(packedInt64Extension , 602L); + message.addExtension(packedUint32Extension , 603); + message.addExtension(packedUint64Extension , 604L); + message.addExtension(packedSint32Extension , 605); + message.addExtension(packedSint64Extension , 606L); + message.addExtension(packedFixed32Extension , 607); + message.addExtension(packedFixed64Extension , 608L); + message.addExtension(packedSfixed32Extension, 609); + message.addExtension(packedSfixed64Extension, 610L); + message.addExtension(packedFloatExtension , 611F); + message.addExtension(packedDoubleExtension , 612D); + message.addExtension(packedBoolExtension , true); + message.addExtension(packedEnumExtension, ForeignEnum.FOREIGN_BAR); + // Add a second one of each field. + message.addExtension(packedInt32Extension , 701); + message.addExtension(packedInt64Extension , 702L); + message.addExtension(packedUint32Extension , 703); + message.addExtension(packedUint64Extension , 704L); + message.addExtension(packedSint32Extension , 705); + message.addExtension(packedSint64Extension , 706L); + message.addExtension(packedFixed32Extension , 707); + message.addExtension(packedFixed64Extension , 708L); + message.addExtension(packedSfixed32Extension, 709); + message.addExtension(packedSfixed64Extension, 710L); + message.addExtension(packedFloatExtension , 711F); + message.addExtension(packedDoubleExtension , 712D); + message.addExtension(packedBoolExtension , false); + message.addExtension(packedEnumExtension, ForeignEnum.FOREIGN_BAZ); + } + + public static void assertPackedExtensionsSet(TestPackedExtensions message) { + Assert.assertEquals(2, message.getExtensionCount(packedInt32Extension )); + Assert.assertEquals(2, message.getExtensionCount(packedInt64Extension )); + Assert.assertEquals(2, message.getExtensionCount(packedUint32Extension )); + Assert.assertEquals(2, message.getExtensionCount(packedUint64Extension )); + Assert.assertEquals(2, message.getExtensionCount(packedSint32Extension )); + Assert.assertEquals(2, message.getExtensionCount(packedSint64Extension )); + Assert.assertEquals(2, message.getExtensionCount(packedFixed32Extension )); + Assert.assertEquals(2, message.getExtensionCount(packedFixed64Extension )); + Assert.assertEquals(2, message.getExtensionCount(packedSfixed32Extension)); + Assert.assertEquals(2, message.getExtensionCount(packedSfixed64Extension)); + Assert.assertEquals(2, message.getExtensionCount(packedFloatExtension )); + Assert.assertEquals(2, message.getExtensionCount(packedDoubleExtension )); + Assert.assertEquals(2, message.getExtensionCount(packedBoolExtension )); + Assert.assertEquals(2, message.getExtensionCount(packedEnumExtension)); + assertEqualsExactType(601 , message.getExtension(packedInt32Extension , 0)); + assertEqualsExactType(602L , message.getExtension(packedInt64Extension , 0)); + assertEqualsExactType(603 , message.getExtension(packedUint32Extension , 0)); + assertEqualsExactType(604L , message.getExtension(packedUint64Extension , 0)); + assertEqualsExactType(605 , message.getExtension(packedSint32Extension , 0)); + assertEqualsExactType(606L , message.getExtension(packedSint64Extension , 0)); + assertEqualsExactType(607 , message.getExtension(packedFixed32Extension , 0)); + assertEqualsExactType(608L , message.getExtension(packedFixed64Extension , 0)); + assertEqualsExactType(609 , message.getExtension(packedSfixed32Extension, 0)); + assertEqualsExactType(610L , message.getExtension(packedSfixed64Extension, 0)); + assertEqualsExactType(611F , message.getExtension(packedFloatExtension , 0)); + assertEqualsExactType(612D , message.getExtension(packedDoubleExtension , 0)); + assertEqualsExactType(true , message.getExtension(packedBoolExtension , 0)); + assertEqualsExactType(ForeignEnum.FOREIGN_BAR, + message.getExtension(packedEnumExtension, 0)); + assertEqualsExactType(701 , message.getExtension(packedInt32Extension , 1)); + assertEqualsExactType(702L , message.getExtension(packedInt64Extension , 1)); + assertEqualsExactType(703 , message.getExtension(packedUint32Extension , 1)); + assertEqualsExactType(704L , message.getExtension(packedUint64Extension , 1)); + assertEqualsExactType(705 , message.getExtension(packedSint32Extension , 1)); + assertEqualsExactType(706L , message.getExtension(packedSint64Extension , 1)); + assertEqualsExactType(707 , message.getExtension(packedFixed32Extension , 1)); + assertEqualsExactType(708L , message.getExtension(packedFixed64Extension , 1)); + assertEqualsExactType(709 , message.getExtension(packedSfixed32Extension, 1)); + assertEqualsExactType(710L , message.getExtension(packedSfixed64Extension, 1)); + assertEqualsExactType(711F , message.getExtension(packedFloatExtension , 1)); + assertEqualsExactType(712D , message.getExtension(packedDoubleExtension , 1)); + assertEqualsExactType(false, message.getExtension(packedBoolExtension , 1)); + assertEqualsExactType(ForeignEnum.FOREIGN_BAZ, + message.getExtension(packedEnumExtension, 1)); + } + + // =================================================================== /** @@ -1487,7 +1736,7 @@ class TestUtil { this.importFile = file.getDependencies().get(0); Descriptors.Descriptor testAllTypes; - if (extensionRegistry == null) { + if (baseDescriptor.getName() == "TestAllTypes") { testAllTypes = baseDescriptor; } else { testAllTypes = file.findMessageTypeByName("TestAllTypes"); @@ -1495,10 +1744,13 @@ class TestUtil { } if (extensionRegistry == null) { + // Use testAllTypes, rather than baseDescriptor, to allow + // initialization using TestPackedTypes descriptors. These objects + // won't be used by the methods for packed fields. this.optionalGroup = - baseDescriptor.findNestedTypeByName("OptionalGroup"); + testAllTypes.findNestedTypeByName("OptionalGroup"); this.repeatedGroup = - baseDescriptor.findNestedTypeByName("RepeatedGroup"); + testAllTypes.findNestedTypeByName("RepeatedGroup"); } else { this.optionalGroup = file.findMessageTypeByName("OptionalGroup_extension"); @@ -2279,6 +2531,191 @@ class TestUtil { Assert.assertEquals("524", message.getRepeatedField(f("repeated_string_piece"), 1)); Assert.assertEquals("525", message.getRepeatedField(f("repeated_cord"), 1)); } + + public void setPackedFieldsViaReflection(Message.Builder message) { + message.addRepeatedField(f("packed_int32" ), 601 ); + message.addRepeatedField(f("packed_int64" ), 602L); + message.addRepeatedField(f("packed_uint32" ), 603 ); + message.addRepeatedField(f("packed_uint64" ), 604L); + message.addRepeatedField(f("packed_sint32" ), 605 ); + message.addRepeatedField(f("packed_sint64" ), 606L); + message.addRepeatedField(f("packed_fixed32" ), 607 ); + message.addRepeatedField(f("packed_fixed64" ), 608L); + message.addRepeatedField(f("packed_sfixed32"), 609 ); + message.addRepeatedField(f("packed_sfixed64"), 610L); + message.addRepeatedField(f("packed_float" ), 611F); + message.addRepeatedField(f("packed_double" ), 612D); + message.addRepeatedField(f("packed_bool" ), true); + message.addRepeatedField(f("packed_enum" ), foreignBar); + // Add a second one of each field. + message.addRepeatedField(f("packed_int32" ), 701 ); + message.addRepeatedField(f("packed_int64" ), 702L); + message.addRepeatedField(f("packed_uint32" ), 703 ); + message.addRepeatedField(f("packed_uint64" ), 704L); + message.addRepeatedField(f("packed_sint32" ), 705 ); + message.addRepeatedField(f("packed_sint64" ), 706L); + message.addRepeatedField(f("packed_fixed32" ), 707 ); + message.addRepeatedField(f("packed_fixed64" ), 708L); + message.addRepeatedField(f("packed_sfixed32"), 709 ); + message.addRepeatedField(f("packed_sfixed64"), 710L); + message.addRepeatedField(f("packed_float" ), 711F); + message.addRepeatedField(f("packed_double" ), 712D); + message.addRepeatedField(f("packed_bool" ), false); + message.addRepeatedField(f("packed_enum" ), foreignBaz); + } + + public void assertPackedFieldsSetViaReflection(Message message) { + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_int32" ))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_int64" ))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_uint32" ))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_uint64" ))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sint32" ))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sint64" ))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_fixed32" ))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_fixed64" ))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sfixed32"))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sfixed64"))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_float" ))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_double" ))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_bool" ))); + Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_enum" ))); + Assert.assertEquals(601 , message.getRepeatedField(f("packed_int32" ), 0)); + Assert.assertEquals(602L , message.getRepeatedField(f("packed_int64" ), 0)); + Assert.assertEquals(603 , message.getRepeatedField(f("packed_uint32" ), 0)); + Assert.assertEquals(604L , message.getRepeatedField(f("packed_uint64" ), 0)); + Assert.assertEquals(605 , message.getRepeatedField(f("packed_sint32" ), 0)); + Assert.assertEquals(606L , message.getRepeatedField(f("packed_sint64" ), 0)); + Assert.assertEquals(607 , message.getRepeatedField(f("packed_fixed32" ), 0)); + Assert.assertEquals(608L , message.getRepeatedField(f("packed_fixed64" ), 0)); + Assert.assertEquals(609 , message.getRepeatedField(f("packed_sfixed32"), 0)); + Assert.assertEquals(610L , message.getRepeatedField(f("packed_sfixed64"), 0)); + Assert.assertEquals(611F , message.getRepeatedField(f("packed_float" ), 0)); + Assert.assertEquals(612D , message.getRepeatedField(f("packed_double" ), 0)); + Assert.assertEquals(true , message.getRepeatedField(f("packed_bool" ), 0)); + Assert.assertEquals(foreignBar, message.getRepeatedField(f("packed_enum" ),0)); + Assert.assertEquals(701 , message.getRepeatedField(f("packed_int32" ), 1)); + Assert.assertEquals(702L , message.getRepeatedField(f("packed_int64" ), 1)); + Assert.assertEquals(703 , message.getRepeatedField(f("packed_uint32" ), 1)); + Assert.assertEquals(704L , message.getRepeatedField(f("packed_uint64" ), 1)); + Assert.assertEquals(705 , message.getRepeatedField(f("packed_sint32" ), 1)); + Assert.assertEquals(706L , message.getRepeatedField(f("packed_sint64" ), 1)); + Assert.assertEquals(707 , message.getRepeatedField(f("packed_fixed32" ), 1)); + Assert.assertEquals(708L , message.getRepeatedField(f("packed_fixed64" ), 1)); + Assert.assertEquals(709 , message.getRepeatedField(f("packed_sfixed32"), 1)); + Assert.assertEquals(710L , message.getRepeatedField(f("packed_sfixed64"), 1)); + Assert.assertEquals(711F , message.getRepeatedField(f("packed_float" ), 1)); + Assert.assertEquals(712D , message.getRepeatedField(f("packed_double" ), 1)); + Assert.assertEquals(false, message.getRepeatedField(f("packed_bool" ), 1)); + Assert.assertEquals(foreignBaz, message.getRepeatedField(f("packed_enum" ),1)); + } + + /** + * Verifies that the reflection setters for the given.Builder object throw a + * NullPointerException if they are passed a null value. Uses Assert to throw an + * appropriate assertion failure, if the condition is not verified. + */ + public void assertReflectionSettersRejectNull(Message.Builder builder) + throws Exception { + try { + builder.setField(f("optional_string"), null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.setField(f("optional_bytes"), null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.setField(f("optional_nested_enum"), null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.setField(f("optional_nested_message"), + (TestAllTypes.NestedMessage) null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.setField(f("optional_nested_message"), + (TestAllTypes.NestedMessage.Builder) null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + + try { + builder.addRepeatedField(f("repeated_string"), null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.addRepeatedField(f("repeated_bytes"), null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.addRepeatedField(f("repeated_nested_enum"), null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + try { + builder.addRepeatedField(f("repeated_nested_message"), null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + } + + /** + * Verifies that the reflection repeated setters for the given Builder object throw a + * NullPointerException if they are passed a null value. Uses Assert to throw an appropriate + * assertion failure, if the condition is not verified. + */ + public void assertReflectionRepeatedSettersRejectNull(Message.Builder builder) + throws Exception { + builder.addRepeatedField(f("repeated_string"), "one"); + try { + builder.setRepeatedField(f("repeated_string"), 0, null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + + builder.addRepeatedField(f("repeated_bytes"), toBytes("one")); + try { + builder.setRepeatedField(f("repeated_bytes"), 0, null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + + builder.addRepeatedField(f("repeated_nested_enum"), nestedBaz); + try { + builder.setRepeatedField(f("repeated_nested_enum"), 0, null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + + builder.addRepeatedField( + f("repeated_nested_message"), + TestAllTypes.NestedMessage.newBuilder().setBb(218).build()); + try { + builder.setRepeatedField(f("repeated_nested_message"), 0, null); + Assert.fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + } } /** @@ -2344,4 +2781,21 @@ class TestUtil { return goldenMessage; } private static ByteString goldenMessage = null; + + /** + * Get the bytes of the "golden packed fields message". This is a serialized + * TestPackedTypes with all fields set as they would be by + * {@link setPackedFields(TestPackedTypes.Builder)}, but it is loaded from a + * file on disk rather than generated dynamically. The file is actually + * generated by C++ code, so testing against it verifies compatibility with + * C++. + */ + public static ByteString getGoldenPackedFieldsMessage() { + if (goldenPackedFieldsMessage == null) { + goldenPackedFieldsMessage = + readBytesFromFile("golden_packed_fields_message"); + } + return goldenPackedFieldsMessage; + } + private static ByteString goldenPackedFieldsMessage = null; } diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java index 9557bdf6..ec4910a3 100644 --- a/java/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java @@ -586,4 +586,32 @@ public class TextFormatTest extends TestCase { // success } } + + public void testParseLongString() throws Exception { + String longText = + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890"; + + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + TextFormat.merge("optional_string: \"" + longText + "\"", builder); + assertEquals(longText, builder.getOptionalString()); + } } diff --git a/java/src/test/java/com/google/protobuf/WireFormatTest.java b/java/src/test/java/com/google/protobuf/WireFormatTest.java index 3fb54fcf..48453faf 100644 --- a/java/src/test/java/com/google/protobuf/WireFormatTest.java +++ b/java/src/test/java/com/google/protobuf/WireFormatTest.java @@ -32,9 +32,11 @@ package com.google.protobuf; import junit.framework.TestCase; import protobuf_unittest.UnittestProto; -import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllExtensions; +import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestFieldOrderings; +import protobuf_unittest.UnittestProto.TestPackedExtensions; +import protobuf_unittest.UnittestProto.TestPackedTypes; import protobuf_unittest.UnittestMset.TestMessageSet; import protobuf_unittest.UnittestMset.RawMessageSet; import protobuf_unittest.UnittestMset.TestMessageSetExtension1; @@ -57,9 +59,20 @@ public class WireFormatTest extends TestCase { TestUtil.assertAllFieldsSet(message2); } + public void testSerializationPacked() throws Exception { + TestPackedTypes message = TestUtil.getPackedSet(); + + ByteString rawBytes = message.toByteString(); + assertEquals(rawBytes.size(), message.getSerializedSize()); + + TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes); + + TestUtil.assertPackedFieldsSet(message2); + } + public void testSerializeExtensions() throws Exception { // TestAllTypes and TestAllExtensions should have compatible wire formats, - // so if we serealize a TestAllExtensions then parse it as TestAllTypes + // so if we serialize a TestAllExtensions then parse it as TestAllTypes // it should work. TestAllExtensions message = TestUtil.getAllExtensionsSet(); @@ -71,17 +84,27 @@ public class WireFormatTest extends TestCase { TestUtil.assertAllFieldsSet(message2); } + public void testSerializePackedExtensions() throws Exception { + // TestPackedTypes and TestPackedExtensions should have compatible wire + // formats; check that they serialize to the same string. + TestPackedExtensions message = TestUtil.getPackedExtensionsSet(); + ByteString rawBytes = message.toByteString(); + + TestPackedTypes message2 = TestUtil.getPackedSet(); + ByteString rawBytes2 = message2.toByteString(); + + assertEquals(rawBytes, rawBytes2); + } + public void testParseExtensions() throws Exception { // TestAllTypes and TestAllExtensions should have compatible wire formats, - // so if we serealize a TestAllTypes then parse it as TestAllExtensions + // so if we serialize a TestAllTypes then parse it as TestAllExtensions // it should work. TestAllTypes message = TestUtil.getAllSet(); ByteString rawBytes = message.toByteString(); - ExtensionRegistry registry = ExtensionRegistry.newInstance(); - TestUtil.registerAllExtensions(registry); - registry = registry.getUnmodifiable(); + ExtensionRegistry registry = TestUtil.getExtensionRegistry(); TestAllExtensions message2 = TestAllExtensions.parseFrom(rawBytes, registry); @@ -89,6 +112,19 @@ public class WireFormatTest extends TestCase { TestUtil.assertAllExtensionsSet(message2); } + public void testParsePackedExtensions() throws Exception { + // Ensure that packed extensions can be properly parsed. + TestPackedExtensions message = TestUtil.getPackedExtensionsSet(); + ByteString rawBytes = message.toByteString(); + + ExtensionRegistry registry = TestUtil.getExtensionRegistry(); + + TestPackedExtensions message2 = + TestPackedExtensions.parseFrom(rawBytes, registry); + + TestUtil.assertPackedExtensionsSet(message2); + } + public void testExtensionsSerializedSize() throws Exception { assertEquals(TestUtil.getAllSet().getSerializedSize(), TestUtil.getAllExtensionsSet().getSerializedSize()); @@ -279,4 +315,3 @@ public class WireFormatTest extends TestCase { assertEquals("bar", field.getLengthDelimitedList().get(0).toStringUtf8()); } } - diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py index 14fe863e..fa1e3402 100755 --- a/python/google/protobuf/internal/containers.py +++ b/python/google/protobuf/internal/containers.py @@ -106,6 +106,19 @@ class RepeatedScalarFieldContainer(BaseContainer): if len(self._values) == 1: self._message_listener.TransitionToNonempty() + def extend(self, elem_seq): + """Extends by appending the given sequence. Similar to list.extend().""" + if not elem_seq: + return + + orig_empty = len(self._values) == 0 + for elem in elem_seq: + self._type_checker.CheckValue(elem) + self._values.extend(elem_seq) + self._message_listener.ByteSizeDirty() + if orig_empty: + self._message_listener.TransitionToNonempty() + def remove(self, elem): """Removes an item from the list. Similar to list.remove().""" self._values.remove(elem) diff --git a/python/google/protobuf/internal/decoder_test.py b/python/google/protobuf/internal/decoder_test.py index abcc07fc..e186e14d 100755 --- a/python/google/protobuf/internal/decoder_test.py +++ b/python/google/protobuf/internal/decoder_test.py @@ -57,7 +57,7 @@ class DecoderTest(unittest.TestCase): for expected_field_number in (1, 15, 16, 2047, 2048): for expected_wire_type in range(6): # Highest-numbered wiretype is 5. e = encoder.Encoder() - e._AppendTag(expected_field_number, expected_wire_type) + e.AppendTag(expected_field_number, expected_wire_type) s = e.ToString() d = decoder.Decoder(s) field_number, wire_type = d.ReadFieldNumberAndWireType() diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py index 7071241c..eed8c8bd 100755 --- a/python/google/protobuf/internal/encoder.py +++ b/python/google/protobuf/internal/encoder.py @@ -58,89 +58,161 @@ class Encoder(object): """Returns all values encoded in this object as a string.""" return self._stream.ToString() - # All the Append*() methods below first append a tag+type pair to the buffer - # before appending the specified value. - - def AppendInt32(self, field_number, value): + # Append*NoTag methods. These are necessary for serializing packed + # repeated fields. The Append*() methods call these methods to do + # the actual serialization. + def AppendInt32NoTag(self, value): """Appends a 32-bit integer to our buffer, varint-encoded.""" - self._AppendTag(field_number, wire_format.WIRETYPE_VARINT) self._stream.AppendVarint32(value) - def AppendInt64(self, field_number, value): + def AppendInt64NoTag(self, value): """Appends a 64-bit integer to our buffer, varint-encoded.""" - self._AppendTag(field_number, wire_format.WIRETYPE_VARINT) self._stream.AppendVarint64(value) - def AppendUInt32(self, field_number, unsigned_value): + def AppendUInt32NoTag(self, unsigned_value): """Appends an unsigned 32-bit integer to our buffer, varint-encoded.""" - self._AppendTag(field_number, wire_format.WIRETYPE_VARINT) self._stream.AppendVarUInt32(unsigned_value) - def AppendUInt64(self, field_number, unsigned_value): + def AppendUInt64NoTag(self, unsigned_value): """Appends an unsigned 64-bit integer to our buffer, varint-encoded.""" - self._AppendTag(field_number, wire_format.WIRETYPE_VARINT) self._stream.AppendVarUInt64(unsigned_value) - def AppendSInt32(self, field_number, value): + def AppendSInt32NoTag(self, value): """Appends a 32-bit integer to our buffer, zigzag-encoded and then varint-encoded. """ - self._AppendTag(field_number, wire_format.WIRETYPE_VARINT) zigzag_value = wire_format.ZigZagEncode(value) self._stream.AppendVarUInt32(zigzag_value) - def AppendSInt64(self, field_number, value): + def AppendSInt64NoTag(self, value): """Appends a 64-bit integer to our buffer, zigzag-encoded and then varint-encoded. """ - self._AppendTag(field_number, wire_format.WIRETYPE_VARINT) zigzag_value = wire_format.ZigZagEncode(value) self._stream.AppendVarUInt64(zigzag_value) - def AppendFixed32(self, field_number, unsigned_value): + def AppendFixed32NoTag(self, unsigned_value): """Appends an unsigned 32-bit integer to our buffer, in little-endian byte-order. """ - self._AppendTag(field_number, wire_format.WIRETYPE_FIXED32) self._stream.AppendLittleEndian32(unsigned_value) - def AppendFixed64(self, field_number, unsigned_value): + def AppendFixed64NoTag(self, unsigned_value): """Appends an unsigned 64-bit integer to our buffer, in little-endian byte-order. """ - self._AppendTag(field_number, wire_format.WIRETYPE_FIXED64) self._stream.AppendLittleEndian64(unsigned_value) - def AppendSFixed32(self, field_number, value): + def AppendSFixed32NoTag(self, value): """Appends a signed 32-bit integer to our buffer, in little-endian byte-order. """ sign = (value & 0x80000000) and -1 or 0 if value >> 32 != sign: raise message.EncodeError('SFixed32 out of range: %d' % value) - self._AppendTag(field_number, wire_format.WIRETYPE_FIXED32) self._stream.AppendLittleEndian32(value & 0xffffffff) - def AppendSFixed64(self, field_number, value): + def AppendSFixed64NoTag(self, value): """Appends a signed 64-bit integer to our buffer, in little-endian byte-order. """ sign = (value & 0x8000000000000000) and -1 or 0 if value >> 64 != sign: raise message.EncodeError('SFixed64 out of range: %d' % value) - self._AppendTag(field_number, wire_format.WIRETYPE_FIXED64) self._stream.AppendLittleEndian64(value & 0xffffffffffffffff) - def AppendFloat(self, field_number, value): + def AppendFloatNoTag(self, value): """Appends a floating-point number to our buffer.""" - self._AppendTag(field_number, wire_format.WIRETYPE_FIXED32) self._stream.AppendRawBytes(struct.pack('f', value)) - def AppendDouble(self, field_number, value): + def AppendDoubleNoTag(self, value): """Appends a double-precision floating-point number to our buffer.""" - self._AppendTag(field_number, wire_format.WIRETYPE_FIXED64) self._stream.AppendRawBytes(struct.pack('d', value)) + def AppendBoolNoTag(self, value): + """Appends a boolean to our buffer.""" + self.AppendInt32NoTag(value) + + def AppendEnumNoTag(self, value): + """Appends an enum value to our buffer.""" + self.AppendInt32NoTag(value) + + + # All the Append*() methods below first append a tag+type pair to the buffer + # before appending the specified value. + + def AppendInt32(self, field_number, value): + """Appends a 32-bit integer to our buffer, varint-encoded.""" + self.AppendTag(field_number, wire_format.WIRETYPE_VARINT) + self.AppendInt32NoTag(value) + + def AppendInt64(self, field_number, value): + """Appends a 64-bit integer to our buffer, varint-encoded.""" + self.AppendTag(field_number, wire_format.WIRETYPE_VARINT) + self.AppendInt64NoTag(value) + + def AppendUInt32(self, field_number, unsigned_value): + """Appends an unsigned 32-bit integer to our buffer, varint-encoded.""" + self.AppendTag(field_number, wire_format.WIRETYPE_VARINT) + self.AppendUInt32NoTag(unsigned_value) + + def AppendUInt64(self, field_number, unsigned_value): + """Appends an unsigned 64-bit integer to our buffer, varint-encoded.""" + self.AppendTag(field_number, wire_format.WIRETYPE_VARINT) + self.AppendUInt64NoTag(unsigned_value) + + def AppendSInt32(self, field_number, value): + """Appends a 32-bit integer to our buffer, zigzag-encoded and then + varint-encoded. + """ + self.AppendTag(field_number, wire_format.WIRETYPE_VARINT) + self.AppendSInt32NoTag(value) + + def AppendSInt64(self, field_number, value): + """Appends a 64-bit integer to our buffer, zigzag-encoded and then + varint-encoded. + """ + self.AppendTag(field_number, wire_format.WIRETYPE_VARINT) + self.AppendSInt64NoTag(value) + + def AppendFixed32(self, field_number, unsigned_value): + """Appends an unsigned 32-bit integer to our buffer, in little-endian + byte-order. + """ + self.AppendTag(field_number, wire_format.WIRETYPE_FIXED32) + self.AppendFixed32NoTag(unsigned_value) + + def AppendFixed64(self, field_number, unsigned_value): + """Appends an unsigned 64-bit integer to our buffer, in little-endian + byte-order. + """ + self.AppendTag(field_number, wire_format.WIRETYPE_FIXED64) + self.AppendFixed64NoTag(unsigned_value) + + def AppendSFixed32(self, field_number, value): + """Appends a signed 32-bit integer to our buffer, in little-endian + byte-order. + """ + self.AppendTag(field_number, wire_format.WIRETYPE_FIXED32) + self.AppendSFixed32NoTag(value) + + def AppendSFixed64(self, field_number, value): + """Appends a signed 64-bit integer to our buffer, in little-endian + byte-order. + """ + self.AppendTag(field_number, wire_format.WIRETYPE_FIXED64) + self.AppendSFixed64NoTag(value) + + def AppendFloat(self, field_number, value): + """Appends a floating-point number to our buffer.""" + self.AppendTag(field_number, wire_format.WIRETYPE_FIXED32) + self.AppendFloatNoTag(value) + + def AppendDouble(self, field_number, value): + """Appends a double-precision floating-point number to our buffer.""" + self.AppendTag(field_number, wire_format.WIRETYPE_FIXED64) + self.AppendDoubleNoTag(value) + def AppendBool(self, field_number, value): """Appends a boolean to our buffer.""" self.AppendInt32(field_number, value) @@ -159,7 +231,7 @@ class Encoder(object): """Appends a length-prefixed sequence of bytes to our buffer, with the length varint-encoded. """ - self._AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) + self.AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) self._stream.AppendVarUInt32(len(value)) self._stream.AppendRawBytes(value) @@ -174,14 +246,14 @@ class Encoder(object): def AppendGroup(self, field_number, group): """Appends a group to our buffer. """ - self._AppendTag(field_number, wire_format.WIRETYPE_START_GROUP) + self.AppendTag(field_number, wire_format.WIRETYPE_START_GROUP) self._stream.AppendRawBytes(group.SerializeToString()) - self._AppendTag(field_number, wire_format.WIRETYPE_END_GROUP) + self.AppendTag(field_number, wire_format.WIRETYPE_END_GROUP) def AppendMessage(self, field_number, msg): """Appends a nested message to our buffer. """ - self._AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) + self.AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) self._stream.AppendVarUInt32(msg.ByteSize()) self._stream.AppendRawBytes(msg.SerializeToString()) @@ -196,11 +268,11 @@ class Encoder(object): } } """ - self._AppendTag(1, wire_format.WIRETYPE_START_GROUP) + self.AppendTag(1, wire_format.WIRETYPE_START_GROUP) self.AppendInt32(2, field_number) self.AppendMessage(3, msg) - self._AppendTag(1, wire_format.WIRETYPE_END_GROUP) + self.AppendTag(1, wire_format.WIRETYPE_END_GROUP) - def _AppendTag(self, field_number, wire_type): + def AppendTag(self, field_number, wire_type): """Appends a tag containing field number and wire type information.""" self._stream.AppendVarUInt32(wire_format.PackTag(field_number, wire_type)) diff --git a/python/google/protobuf/internal/encoder_test.py b/python/google/protobuf/internal/encoder_test.py index 61668223..83a21c39 100755 --- a/python/google/protobuf/internal/encoder_test.py +++ b/python/google/protobuf/internal/encoder_test.py @@ -59,7 +59,8 @@ class EncoderTest(unittest.TestCase): def AppendScalarTestHelper(self, test_name, encoder_method, expected_stream_method_name, wire_type, field_value, - expected_value=None, expected_length=None): + expected_value=None, expected_length=None, + is_tag_test=True): """Helper for testAppendScalars. Calls one of the Encoder methods, and ensures that the Encoder @@ -67,9 +68,10 @@ class EncoderTest(unittest.TestCase): Args: test_name: Name of this test, used only for logging. - encoder_method: Callable on self.encoder, which should - accept |field_value| as an argument. This is the Encoder - method we're testing. + encoder_method: Callable on self.encoder. This is the Encoder + method we're testing. If is_tag_test=True, the encoder method + accepts a field_number and field_value. if is_tag_test=False, + the encoder method accepts a field_value. expected_stream_method_name: (string) Name of the OutputStream method we expect Encoder to call to actually put the value on the wire. @@ -83,6 +85,9 @@ class EncoderTest(unittest.TestCase): expected_length: The length we expect Encoder to pass to the AppendVarUInt32 method. If None we expect the length of the field_value. + is_tag_test: A Boolean. If True (the default), we append the + the packed field number and wire_type to the stream before + the field value. """ if expected_value is None: expected_value = field_value @@ -93,14 +98,16 @@ class EncoderTest(unittest.TestCase): test_name, encoder_method, field_value, expected_stream_method_name, expected_value)) - field_number = 10 - # Should first append the field number and type information. - self.mock_stream.AppendVarUInt32(self.PackTag(field_number, wire_type)) - # If we're length-delimited, we should then append the length. - if wire_type == wire_format.WIRETYPE_LENGTH_DELIMITED: - if expected_length is None: - expected_length = len(field_value) - self.mock_stream.AppendVarUInt32(expected_length) + if is_tag_test: + field_number = 10 + # Should first append the field number and type information. + self.mock_stream.AppendVarUInt32(self.PackTag(field_number, wire_type)) + # If we're length-delimited, we should then append the length. + if wire_type == wire_format.WIRETYPE_LENGTH_DELIMITED: + if expected_length is None: + expected_length = len(field_value) + self.mock_stream.AppendVarUInt32(expected_length) + # Should then append the value itself. # We have to use names instead of methods to work around some # mox weirdness. (ResetAll() is overzealous). @@ -109,7 +116,10 @@ class EncoderTest(unittest.TestCase): expected_stream_method(expected_value) self.mox.ReplayAll() - encoder_method(field_number, field_value) + if is_tag_test: + encoder_method(field_number, field_value) + else: + encoder_method(field_value) self.mox.VerifyAll() self.mox.ResetAll() @@ -160,6 +170,40 @@ class EncoderTest(unittest.TestCase): for args in scalar_tests: self.AppendScalarTestHelper(*args) + def testAppendScalarsWithoutTags(self): + scalar_no_tag_tests = [ + ['int32', self.encoder.AppendInt32NoTag, 'AppendVarint32', None, 0], + ['int64', self.encoder.AppendInt64NoTag, 'AppendVarint64', None, 0], + ['uint32', self.encoder.AppendUInt32NoTag, 'AppendVarUInt32', None, 0], + ['uint64', self.encoder.AppendUInt64NoTag, 'AppendVarUInt64', None, 0], + ['fixed32', self.encoder.AppendFixed32NoTag, + 'AppendLittleEndian32', None, 0], + ['fixed64', self.encoder.AppendFixed64NoTag, + 'AppendLittleEndian64', None, 0], + ['sfixed32', self.encoder.AppendSFixed32NoTag, + 'AppendLittleEndian32', None, 0], + ['sfixed64', self.encoder.AppendSFixed64NoTag, + 'AppendLittleEndian64', None, 0], + ['float', self.encoder.AppendFloatNoTag, + 'AppendRawBytes', None, 0.0, struct.pack('f', 0.0)], + ['double', self.encoder.AppendDoubleNoTag, + 'AppendRawBytes', None, 0.0, struct.pack('d', 0.0)], + ['bool', self.encoder.AppendBoolNoTag, 'AppendVarint32', None, 0], + ['enum', self.encoder.AppendEnumNoTag, 'AppendVarint32', None, 0], + ['sint32', self.encoder.AppendSInt32NoTag, + 'AppendVarUInt32', None, -1, 1], + ['sint64', self.encoder.AppendSInt64NoTag, + 'AppendVarUInt64', None, -1, 1], + ] + + self.assertEqual(len(scalar_no_tag_tests), + len(set(t[0] for t in scalar_no_tag_tests))) + self.assert_(len(scalar_no_tag_tests) >= + len(set(t[1] for t in scalar_no_tag_tests))) + for args in scalar_no_tag_tests: + # For no tag tests, the wire_type is not used, so we put in None. + self.AppendScalarTestHelper(is_tag_test=False, *args) + def testAppendGroup(self): field_number = 23 # Should first append the start-group marker. diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py index 14062762..e405f60b 100755 --- a/python/google/protobuf/internal/reflection_test.py +++ b/python/google/protobuf/internal/reflection_test.py @@ -229,8 +229,8 @@ class ReflectionTest(unittest.TestCase): proto.repeated_fixed32.append(1) proto.repeated_int32.append(5) proto.repeated_int32.append(11) - proto.repeated_string.append('foo') - proto.repeated_string.append('bar') + proto.repeated_string.extend(['foo', 'bar']) + proto.repeated_string.extend([]) proto.repeated_string.append('baz') proto.optional_int32 = 21 self.assertEqual( @@ -757,6 +757,16 @@ class ReflectionTest(unittest.TestCase): self.assertRaises(KeyError, extendee_proto.HasExtension, unittest_pb2.repeated_string_extension) + def testStaticParseFrom(self): + proto1 = unittest_pb2.TestAllTypes() + test_util.SetAllFields(proto1) + + string1 = proto1.SerializeToString() + proto2 = unittest_pb2.TestAllTypes.FromString(string1) + + # Messages should be equal. + self.assertEqual(proto2, proto1) + def testMergeFromSingularField(self): # Test merge with just a singular field. proto1 = unittest_pb2.TestAllTypes() @@ -1209,6 +1219,8 @@ class ByteSizeTest(unittest.TestCase): def setUp(self): self.proto = unittest_pb2.TestAllTypes() self.extended_proto = more_extensions_pb2.ExtendedMessage() + self.packed_proto = unittest_pb2.TestPackedTypes() + self.packed_extended_proto = unittest_pb2.TestPackedExtensions() def Size(self): return self.proto.ByteSize() @@ -1291,6 +1303,11 @@ class ByteSizeTest(unittest.TestCase): # Also need 2 bytes for each entry for tag. self.assertEqual(1 + 2 + 2*2, self.Size()) + def testRepeatedScalarsExtend(self): + self.proto.repeated_int32.extend([10, 128]) # 3 bytes. + # Also need 2 bytes for each entry for tag. + self.assertEqual(1 + 2 + 2*2, self.Size()) + def testRepeatedScalarsRemove(self): self.proto.repeated_int32.append(10) # 1 byte. self.proto.repeated_int32.append(128) # 2 bytes. @@ -1443,6 +1460,33 @@ class ByteSizeTest(unittest.TestCase): self.extended_proto.ClearExtension(extension) self.assertEqual(0, self.extended_proto.ByteSize()) + def testPackedRepeatedScalars(self): + self.assertEqual(0, self.packed_proto.ByteSize()) + + self.packed_proto.packed_int32.append(10) # 1 byte. + self.packed_proto.packed_int32.append(128) # 2 bytes. + # The tag is 2 bytes (the field number is 90), and the varint + # storing the length is 1 byte. + int_size = 1 + 2 + 3 + self.assertEqual(int_size, self.packed_proto.ByteSize()) + + self.packed_proto.packed_double.append(4.2) # 8 bytes + self.packed_proto.packed_double.append(3.25) # 8 bytes + # 2 more tag bytes, 1 more length byte. + double_size = 8 + 8 + 3 + self.assertEqual(int_size+double_size, self.packed_proto.ByteSize()) + + self.packed_proto.ClearField('packed_int32') + self.assertEqual(double_size, self.packed_proto.ByteSize()) + + def testPackedExtensions(self): + self.assertEqual(0, self.packed_extended_proto.ByteSize()) + extension = self.packed_extended_proto.Extensions[ + unittest_pb2.packed_fixed32_extension] + extension.extend([1, 2, 3, 4]) # 16 bytes + # Tag is 3 bytes. + self.assertEqual(19, self.packed_extended_proto.ByteSize()) + # TODO(robinson): We need cross-language serialization consistency tests. # Issues to be sure to cover include: @@ -1686,6 +1730,63 @@ class SerializationTest(unittest.TestCase): self.assertEqual(2, proto2.b) self.assertEqual(3, proto2.c) + def testSerializedAllPackedFields(self): + first_proto = unittest_pb2.TestPackedTypes() + second_proto = unittest_pb2.TestPackedTypes() + test_util.SetAllPackedFields(first_proto) + serialized = first_proto.SerializeToString() + self.assertEqual(first_proto.ByteSize(), len(serialized)) + second_proto.MergeFromString(serialized) + self.assertEqual(first_proto, second_proto) + + def testSerializeAllPackedExtensions(self): + first_proto = unittest_pb2.TestPackedExtensions() + second_proto = unittest_pb2.TestPackedExtensions() + test_util.SetAllPackedExtensions(first_proto) + serialized = first_proto.SerializeToString() + second_proto.MergeFromString(serialized) + self.assertEqual(first_proto, second_proto) + + def testMergePackedFromStringWhenSomeFieldsAlreadySet(self): + first_proto = unittest_pb2.TestPackedTypes() + first_proto.packed_int32.extend([1, 2]) + first_proto.packed_double.append(3.0) + serialized = first_proto.SerializeToString() + + second_proto = unittest_pb2.TestPackedTypes() + second_proto.packed_int32.append(3) + second_proto.packed_double.extend([1.0, 2.0]) + second_proto.packed_sint32.append(4) + + second_proto.MergeFromString(serialized) + self.assertEqual([3, 1, 2], second_proto.packed_int32) + self.assertEqual([1.0, 2.0, 3.0], second_proto.packed_double) + self.assertEqual([4], second_proto.packed_sint32) + + def testPackedFieldsWireFormat(self): + proto = unittest_pb2.TestPackedTypes() + proto.packed_int32.extend([1, 2, 150, 3]) # 1 + 1 + 2 + 1 bytes + proto.packed_double.extend([1.0, 1000.0]) # 8 + 8 bytes + proto.packed_float.append(2.0) # 4 bytes, will be before double + serialized = proto.SerializeToString() + self.assertEqual(proto.ByteSize(), len(serialized)) + d = decoder.Decoder(serialized) + ReadTag = d.ReadFieldNumberAndWireType + self.assertEqual((90, wire_format.WIRETYPE_LENGTH_DELIMITED), ReadTag()) + self.assertEqual(1+1+1+2, d.ReadInt32()) + self.assertEqual(1, d.ReadInt32()) + self.assertEqual(2, d.ReadInt32()) + self.assertEqual(150, d.ReadInt32()) + self.assertEqual(3, d.ReadInt32()) + self.assertEqual((100, wire_format.WIRETYPE_LENGTH_DELIMITED), ReadTag()) + self.assertEqual(4, d.ReadInt32()) + self.assertEqual(2.0, d.ReadFloat()) + self.assertEqual((101, wire_format.WIRETYPE_LENGTH_DELIMITED), ReadTag()) + self.assertEqual(8+8, d.ReadInt32()) + self.assertEqual(1.0, d.ReadDouble()) + self.assertEqual(1000.0, d.ReadDouble()) + self.assertTrue(d.EndOfStream()) + class OptionsTest(unittest.TestCase): @@ -1697,6 +1798,21 @@ class OptionsTest(unittest.TestCase): self.assertEqual(False, proto.DESCRIPTOR.GetOptions().message_set_wire_format) + def testPackedOptions(self): + proto = unittest_pb2.TestAllTypes() + proto.optional_int32 = 1 + proto.optional_double = 3.0 + for field_descriptor, _ in proto.ListFields(): + self.assertEqual(False, field_descriptor.GetOptions().packed) + + proto = unittest_pb2.TestPackedTypes() + proto.packed_int32.append(1) + proto.packed_double.append(3.0) + for field_descriptor, _ in proto.ListFields(): + self.assertEqual(True, field_descriptor.GetOptions().packed) + self.assertEqual(reflection._FieldDescriptor.LABEL_REPEATED, + field_descriptor.label) + class UtilityTest(unittest.TestCase): diff --git a/python/google/protobuf/internal/service_reflection_test.py b/python/google/protobuf/internal/service_reflection_test.py index 29492e16..e04f8252 100755 --- a/python/google/protobuf/internal/service_reflection_test.py +++ b/python/google/protobuf/internal/service_reflection_test.py @@ -74,7 +74,7 @@ class FooUnitTest(unittest.TestCase): rpc_controller.failure_message = None - service_descriptor = unittest_pb2.TestService.DESCRIPTOR + service_descriptor = unittest_pb2.TestService.GetDescriptor() srvc.CallMethod(service_descriptor.methods[1], rpc_controller, unittest_pb2.BarRequest(), MyCallback) self.assertEqual('Method Bar not implemented.', @@ -118,6 +118,10 @@ class FooUnitTest(unittest.TestCase): rpc_controller = 'controller' request = 'request' + # GetDescriptor now static, still works as instance method for compatability + self.assertEqual(unittest_pb2.TestService_Stub.GetDescriptor(), + stub.GetDescriptor()) + # Invoke method. stub.Foo(rpc_controller, request, MyCallback) diff --git a/python/google/protobuf/internal/test_util.py b/python/google/protobuf/internal/test_util.py index 14dfbc51..2d50bc4a 100755 --- a/python/google/protobuf/internal/test_util.py +++ b/python/google/protobuf/internal/test_util.py @@ -366,3 +366,51 @@ def GoldenFile(filename): 'Could not find golden files. This test must be run from within the ' 'protobuf source package so that it can read test data files from the ' 'C++ source tree.') + + +def SetAllPackedFields(message): + """Sets every field in the message to a unique value. + + Args: + message: A unittest_pb2.TestPackedTypes instance. + """ + message.packed_int32.extend([101, 102]) + message.packed_int64.extend([103, 104]) + message.packed_uint32.extend([105, 106]) + message.packed_uint64.extend([107, 108]) + message.packed_sint32.extend([109, 110]) + message.packed_sint64.extend([111, 112]) + message.packed_fixed32.extend([113, 114]) + message.packed_fixed64.extend([115, 116]) + message.packed_sfixed32.extend([117, 118]) + message.packed_sfixed64.extend([119, 120]) + message.packed_float.extend([121.0, 122.0]) + message.packed_double.extend([122.0, 123.0]) + message.packed_bool.extend([True, False]) + message.packed_enum.extend([unittest_pb2.FOREIGN_FOO, + unittest_pb2.FOREIGN_BAR]) + + +def SetAllPackedExtensions(message): + """Sets every extension in the message to a unique value. + + Args: + message: A unittest_pb2.TestPackedExtensions instance. + """ + extensions = message.Extensions + pb2 = unittest_pb2 + + extensions[pb2.packed_int32_extension].append(101) + extensions[pb2.packed_int64_extension].append(102) + extensions[pb2.packed_uint32_extension].append(103) + extensions[pb2.packed_uint64_extension].append(104) + extensions[pb2.packed_sint32_extension].append(105) + extensions[pb2.packed_sint64_extension].append(106) + extensions[pb2.packed_fixed32_extension].append(107) + extensions[pb2.packed_fixed64_extension].append(108) + extensions[pb2.packed_sfixed32_extension].append(109) + extensions[pb2.packed_sfixed64_extension].append(110) + extensions[pb2.packed_float_extension].append(111.0) + extensions[pb2.packed_double_extension].append(112.0) + extensions[pb2.packed_bool_extension].append(True) + extensions[pb2.packed_enum_extension].append(pb2.FOREIGN_BAZ) diff --git a/python/google/protobuf/internal/type_checkers.py b/python/google/protobuf/internal/type_checkers.py index ba470cf2..c009627f 100755 --- a/python/google/protobuf/internal/type_checkers.py +++ b/python/google/protobuf/internal/type_checkers.py @@ -216,6 +216,23 @@ TYPE_TO_SERIALIZE_METHOD = { } +TYPE_TO_NOTAG_SERIALIZE_METHOD = { + _FieldDescriptor.TYPE_DOUBLE: _Encoder.AppendDoubleNoTag, + _FieldDescriptor.TYPE_FLOAT: _Encoder.AppendFloatNoTag, + _FieldDescriptor.TYPE_INT64: _Encoder.AppendInt64NoTag, + _FieldDescriptor.TYPE_UINT64: _Encoder.AppendUInt64NoTag, + _FieldDescriptor.TYPE_INT32: _Encoder.AppendInt32NoTag, + _FieldDescriptor.TYPE_FIXED64: _Encoder.AppendFixed64NoTag, + _FieldDescriptor.TYPE_FIXED32: _Encoder.AppendFixed32NoTag, + _FieldDescriptor.TYPE_BOOL: _Encoder.AppendBoolNoTag, + _FieldDescriptor.TYPE_UINT32: _Encoder.AppendUInt32NoTag, + _FieldDescriptor.TYPE_ENUM: _Encoder.AppendEnumNoTag, + _FieldDescriptor.TYPE_SFIXED32: _Encoder.AppendSFixed32NoTag, + _FieldDescriptor.TYPE_SFIXED64: _Encoder.AppendSFixed64NoTag, + _FieldDescriptor.TYPE_SINT32: _Encoder.AppendSInt32NoTag, + _FieldDescriptor.TYPE_SINT64: _Encoder.AppendSInt64NoTag, + } + # Maps from field type to expected wiretype. FIELD_TYPE_TO_WIRE_TYPE = { _FieldDescriptor.TYPE_DOUBLE: wire_format.WIRETYPE_FIXED64, diff --git a/python/google/protobuf/internal/wire_format.py b/python/google/protobuf/internal/wire_format.py index 5f0af11e..531c9b85 100755 --- a/python/google/protobuf/internal/wire_format.py +++ b/python/google/protobuf/internal/wire_format.py @@ -120,6 +120,10 @@ def Int32ByteSize(field_number, int32): return Int64ByteSize(field_number, int32) +def Int32ByteSizeNoTag(int32): + return _VarUInt64ByteSizeNoTag(0xffffffffffffffff & int32) + + def Int64ByteSize(field_number, int64): # Have to convert to uint before calling UInt64ByteSize(). return UInt64ByteSize(field_number, 0xffffffffffffffff & int64) @@ -130,7 +134,7 @@ def UInt32ByteSize(field_number, uint32): def UInt64ByteSize(field_number, uint64): - return _TagByteSize(field_number) + _VarUInt64ByteSizeNoTag(uint64) + return TagByteSize(field_number) + _VarUInt64ByteSizeNoTag(uint64) def SInt32ByteSize(field_number, int32): @@ -142,31 +146,31 @@ def SInt64ByteSize(field_number, int64): def Fixed32ByteSize(field_number, fixed32): - return _TagByteSize(field_number) + 4 + return TagByteSize(field_number) + 4 def Fixed64ByteSize(field_number, fixed64): - return _TagByteSize(field_number) + 8 + return TagByteSize(field_number) + 8 def SFixed32ByteSize(field_number, sfixed32): - return _TagByteSize(field_number) + 4 + return TagByteSize(field_number) + 4 def SFixed64ByteSize(field_number, sfixed64): - return _TagByteSize(field_number) + 8 + return TagByteSize(field_number) + 8 def FloatByteSize(field_number, flt): - return _TagByteSize(field_number) + 4 + return TagByteSize(field_number) + 4 def DoubleByteSize(field_number, double): - return _TagByteSize(field_number) + 8 + return TagByteSize(field_number) + 8 def BoolByteSize(field_number, b): - return _TagByteSize(field_number) + 1 + return TagByteSize(field_number) + 1 def EnumByteSize(field_number, enum): @@ -178,18 +182,18 @@ def StringByteSize(field_number, string): def BytesByteSize(field_number, b): - return (_TagByteSize(field_number) + return (TagByteSize(field_number) + _VarUInt64ByteSizeNoTag(len(b)) + len(b)) def GroupByteSize(field_number, message): - return (2 * _TagByteSize(field_number) # START and END group. + return (2 * TagByteSize(field_number) # START and END group. + message.ByteSize()) def MessageByteSize(field_number, message): - return (_TagByteSize(field_number) + return (TagByteSize(field_number) + _VarUInt64ByteSizeNoTag(message.ByteSize()) + message.ByteSize()) @@ -199,7 +203,7 @@ def MessageSetItemByteSize(field_number, msg): # There are 2 tags for the beginning and ending of the repeated group, that # is field number 1, one with field number 2 (type_id) and one with field # number 3 (message). - total_size = (2 * _TagByteSize(1) + _TagByteSize(2) + _TagByteSize(3)) + total_size = (2 * TagByteSize(1) + TagByteSize(2) + TagByteSize(3)) # Add the number of bytes for type_id. total_size += _VarUInt64ByteSizeNoTag(field_number) @@ -214,15 +218,14 @@ def MessageSetItemByteSize(field_number, msg): return total_size -# Private helper functions for the *ByteSize() functions above. - - -def _TagByteSize(field_number): +def TagByteSize(field_number): """Returns the bytes required to serialize a tag with this field number.""" # Just pass in type 0, since the type won't affect the tag+type size. return _VarUInt64ByteSizeNoTag(PackTag(field_number, 0)) +# Private helper function for the *ByteSize() functions above. + def _VarUInt64ByteSizeNoTag(uint64): """Returns the bytes required to serialize a single varint. uint64 must be unsigned. diff --git a/python/google/protobuf/reflection.py b/python/google/protobuf/reflection.py index 9ba752e4..0d5191be 100755 --- a/python/google/protobuf/reflection.py +++ b/python/google/protobuf/reflection.py @@ -462,6 +462,12 @@ def _AddStaticMethods(cls): cls._known_extensions.append(extension_handle) cls.RegisterExtension = staticmethod(RegisterExtension) + def FromString(s): + message = cls() + message.MergeFromString(s) + return message + cls.FromString = staticmethod(FromString) + def _AddListFieldsMethod(message_descriptor, cls): """Helper for _AddMessageMethods().""" @@ -665,9 +671,36 @@ def _AddByteSizeMethod(message_descriptor, cls): else: elements = [value] - size = sum(_BytesForNonRepeatedElement(element, field_number, field_type) - for element in elements) - return size + if field.GetOptions().packed: + content_size = _ContentBytesForPackedField(message, field, elements) + if content_size: + tag_size = wire_format.TagByteSize(field_number) + length_size = wire_format.Int32ByteSizeNoTag(content_size) + return tag_size + length_size + content_size + else: + return 0 + else: + return sum(_BytesForNonRepeatedElement(element, field_number, field_type) + for element in elements) + + def _ContentBytesForPackedField(self, field, value): + """Returns the number of bytes required to serialize the actual + content of a packed field (not including the tag or the encoding + of the length. + + Args: + self: The Message instance containing a field of the given type. + field: A FieldDescriptor describing the field of interest. + value: The value whose byte size we're interested in. + + Returns: The number of bytes required to serialize the current value + of the packed "field" in "message", excluding space for tags and the + length encoding. + """ + size = sum(_BytesForNonRepeatedElement(element, field.number, field.type) + for element in value) + # In the packed case, there are no per element tags. + return size - wire_format.TagByteSize(field.number) * len(value) fields = message_descriptor.fields has_field_names = (_HasFieldName(f.name) for f in fields) @@ -691,6 +724,8 @@ def _AddByteSizeMethod(message_descriptor, cls): self._cached_byte_size = size self._cached_byte_size_dirty = False return size + + cls._ContentBytesForPackedField = _ContentBytesForPackedField cls.ByteSize = ByteSize @@ -788,10 +823,29 @@ def _AddSerializePartialToStringMethod(message_descriptor, cls): repeated_value = field_value else: repeated_value = [field_value] - for element in repeated_value: - _SerializeValueToEncoder(element, field_descriptor.number, - field_descriptor, encoder) + if field_descriptor.GetOptions().packed: + # First, write the field number and WIRETYPE_LENGTH_DELIMITED. + field_number = field_descriptor.number + encoder.AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) + # Next, write the number of bytes. + content_bytes = self._ContentBytesForPackedField( + field_descriptor, field_value) + encoder.AppendInt32NoTag(content_bytes) + # Finally, write the actual values. + try: + method = type_checkers.TYPE_TO_NOTAG_SERIALIZE_METHOD[ + field_descriptor.type] + for value in repeated_value: + method(encoder, value) + except KeyError: + raise message_mod.EncodeError('Unrecognized field type: %d' % + field_descriptor.type) + else: + for element in repeated_value: + _SerializeValueToEncoder(element, field_descriptor.number, + field_descriptor, encoder) return encoder.ToString() + cls.SerializePartialToString = SerializePartialToString @@ -803,6 +857,14 @@ def _WireTypeForFieldType(field_type): raise message_mod.DecodeError('Unknown field type: %d' % field_type) +def _WireTypeForField(field_descriptor): + """Given a field descriptor, returns the expected wire type.""" + if field_descriptor.GetOptions().packed: + return wire_format.WIRETYPE_LENGTH_DELIMITED + else: + return _WireTypeForFieldType(field_descriptor.type) + + def _RecursivelyMerge(field_number, field_type, decoder, message): """Decodes a message from decoder into message. message is either a group or a nested message within some containing @@ -918,9 +980,11 @@ def _DeserializeMessageSetItem(message, decoder): def _DeserializeOneEntity(message_descriptor, message, decoder): """Deserializes the next wire entity from decoder into message. - The next wire entity is either a scalar or a nested message, - and may also be an element in a repeated field (the wire encoding - is the same). + + The next wire entity is either a scalar or a nested message, an + element in a repeated field (the wire encoding in this case is the + same), or a packed repeated field (in this case, the entire repeated + field is read by a single call to _DeserializeOneEntity). Args: message_descriptor: A Descriptor instance describing all fields @@ -973,14 +1037,14 @@ def _DeserializeOneEntity(message_descriptor, message, decoder): # if this field is a nonrepeated scalar. field_number = field_descriptor.number - field_type = field_descriptor.type - expected_wire_type = _WireTypeForFieldType(field_type) + expected_wire_type = _WireTypeForField(field_descriptor) if wire_type != expected_wire_type: # Need to fill in uninterpreted_bytes. Work for the next CL. raise RuntimeError('TODO(robinson): Wiretype mismatches not handled.') property_name = _PropertyName(field_descriptor.name) label = field_descriptor.label + field_type = field_descriptor.type cpp_type = field_descriptor.cpp_type # Nonrepeated scalar. Just set the field directly. @@ -1000,8 +1064,17 @@ def _DeserializeOneEntity(message_descriptor, message, decoder): if cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE: # Repeated scalar. - element_list.append(_DeserializeScalarFromDecoder(field_type, decoder)) - return decoder.Position() - initial_position + if not field_descriptor.GetOptions().packed: + element_list.append(_DeserializeScalarFromDecoder(field_type, decoder)) + return decoder.Position() - initial_position + else: + # Packed repeated field. + length = _DeserializeScalarFromDecoder( + _FieldDescriptor.TYPE_INT32, decoder) + content_start = decoder.Position() + while decoder.Position() - content_start < length: + element_list.append(_DeserializeScalarFromDecoder(field_type, decoder)) + return decoder.Position() - content_start else: # Repeated composite. composite = element_list.add() diff --git a/python/google/protobuf/service.py b/python/google/protobuf/service.py index 3989216a..9ec42fe3 100755 --- a/python/google/protobuf/service.py +++ b/python/google/protobuf/service.py @@ -31,7 +31,7 @@ """Declares the RPC service interfaces. This module declares the abstract interfaces underlying proto2 RPC -services. These are intented to be independent of any particular RPC +services. These are intended to be independent of any particular RPC implementation, so that proto2 services can be used on top of a variety of implementations. """ @@ -39,6 +39,11 @@ of implementations. __author__ = 'petar@google.com (Petar Petrov)' +class RpcException(Exception): + """Exception raised on failed blocking RPC method call.""" + pass + + class Service(object): """Abstract base interface for protocol-buffer-based RPC services. @@ -49,7 +54,7 @@ class Service(object): its exact type at compile time (analogous to the Message interface). """ - def GetDescriptor(self): + def GetDescriptor(): """Retrieves this service's descriptor.""" raise NotImplementedError @@ -57,6 +62,14 @@ class Service(object): request, done): """Calls a method of the service specified by method_descriptor. + If "done" is None then the call is blocking and the response + message will be returned directly. Otherwise the call is asynchronous + and "done" will later be called with the response value. + + In the blocking case, RpcException will be raised on error. + Asynchronous calls must check status via the Failed method of the + RpcController. + Preconditions: * method_descriptor.service == GetDescriptor * request is of the exact same classes as returned by diff --git a/python/google/protobuf/service_reflection.py b/python/google/protobuf/service_reflection.py index bdd6bad5..851e83e7 100755 --- a/python/google/protobuf/service_reflection.py +++ b/python/google/protobuf/service_reflection.py @@ -142,24 +142,17 @@ class _ServiceBuilder(object): # instance to the method that does the real CallMethod work. def _WrapCallMethod(srvc, method_descriptor, rpc_controller, request, callback): - self._CallMethod(srvc, method_descriptor, + return self._CallMethod(srvc, method_descriptor, rpc_controller, request, callback) self.cls = cls cls.CallMethod = _WrapCallMethod - cls.GetDescriptor = self._GetDescriptor + cls.GetDescriptor = staticmethod(lambda: self.descriptor) + cls.GetDescriptor.__doc__ = "Returns the service descriptor." cls.GetRequestClass = self._GetRequestClass cls.GetResponseClass = self._GetResponseClass for method in self.descriptor.methods: setattr(cls, method.name, self._GenerateNonImplementedMethod(method)) - def _GetDescriptor(self): - """Retrieves the service descriptor. - - Returns: - The descriptor of the service (of type ServiceDescriptor). - """ - return self.descriptor - def _CallMethod(self, srvc, method_descriptor, rpc_controller, request, callback): """Calls the method described by a given method descriptor. @@ -175,7 +168,7 @@ class _ServiceBuilder(object): raise RuntimeError( 'CallMethod() given method descriptor for wrong service type.') method = getattr(srvc, method_descriptor.name) - method(rpc_controller, request, callback) + return method(rpc_controller, request, callback) def _GetRequestClass(self, method_descriptor): """Returns the class of the request protocol message. @@ -270,8 +263,8 @@ class _ServiceStubBuilder(object): setattr(cls, method.name, self._GenerateStubMethod(method)) def _GenerateStubMethod(self, method): - return lambda inst, rpc_controller, request, callback: self._StubMethod( - inst, method, rpc_controller, request, callback) + return (lambda inst, rpc_controller, request, callback=None: + self._StubMethod(inst, method, rpc_controller, request, callback)) def _StubMethod(self, stub, method_descriptor, rpc_controller, request, callback): @@ -283,7 +276,9 @@ class _ServiceStubBuilder(object): rpc_controller: Rpc controller to execute the method. request: Request protocol message. callback: A callback to execute when the method finishes. + Returns: + Response message (in case of blocking call). """ - stub.rpc_channel.CallMethod( + return stub.rpc_channel.CallMethod( method_descriptor, rpc_controller, request, method_descriptor.output_type._concrete_class, callback) diff --git a/src/Makefile.am b/src/Makefile.am index c13a723e..18167482 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -160,6 +160,7 @@ EXTRA_DIST = \ $(protoc_inputs) \ solaris/libstdc++.la \ google/protobuf/testdata/golden_message \ + google/protobuf/testdata/golden_packed_fields_message \ google/protobuf/testdata/text_format_unittest_data.txt \ google/protobuf/testdata/text_format_unittest_extensions_data.txt \ google/protobuf/package_info.h \ diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 089844f4..09473ec7 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -751,7 +751,8 @@ bool CommandLineInterface::GenerateOutput( if (!output_directive.generator->Generate( parsed_file, output_directive.parameter, &output_directory, &error)) { // Generator returned an error. - cerr << output_directive.name << ": " << error << endl; + cerr << parsed_file->name() << ": " << output_directive.name << ": " + << error << endl; return false; } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index c998f20b..19779a8a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -158,7 +158,13 @@ RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} void RepeatedEnumFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { - printer->Print(variables_, "::google::protobuf::RepeatedField<int> $name$_;\n"); + printer->Print(variables_, + "::google::protobuf::RepeatedField<int> $name$_;\n"); + if (descriptor_->options().packed() && + descriptor_->file()->options().optimize_for() == FileOptions::SPEED) { + printer->Print(variables_, + "mutable int _$name$_cached_byte_size_;\n"); + } } void RepeatedEnumFieldGenerator:: @@ -217,31 +223,84 @@ GenerateInitializer(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - printer->Print(variables_, - "int value;\n" - "DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n" - "if ($type$_IsValid(value)) {\n" - " add_$name$(static_cast< $type$ >(value));\n" - "} else {\n" - " mutable_unknown_fields()->AddField($number$)->add_varint(value);\n" - "}\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + "::google::protobuf::uint32 length;\n" + "DO_(input->ReadVarint32(&length));\n" + "::google::protobuf::io::CodedInputStream::Limit limit = " + "input->PushLimit(length);\n" + "while (input->BytesUntilLimit() > 0) {\n" + " int value;\n" + " DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n" + " if ($type$_IsValid(value)) {\n" + " add_$name$(static_cast< $type$ >(value));\n" + " }\n" + "}\n" + "input->PopLimit(limit);\n"); + } else { + printer->Print(variables_, + "int value;\n" + "DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n" + "if ($type$_IsValid(value)) {\n" + " add_$name$(static_cast< $type$ >(value));\n" + "} else {\n" + " mutable_unknown_fields()->AddField($number$)->add_varint(value);\n" + "}\n"); + } } void RepeatedEnumFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { + if (descriptor_->options().packed()) { + // Write the tag and the size. + printer->Print(variables_, + "if (this->$name$_size() > 0) {\n" + " DO_(::google::protobuf::internal::WireFormat::WriteTag(" + "$number$, ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED," + "output));\n" + " DO_(output->WriteVarint32(_$name$_cached_byte_size_));\n" + "}\n"); + } printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormat::WriteEnum(" - "$number$, this->$name$(i), output));\n"); + "for (int i = 0; i < this->$name$_size(); i++) {\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + " DO_(::google::protobuf::internal::WireFormat::WriteEnumNoTag(" + "this->$name$(i), output));\n"); + } else { + printer->Print(variables_, + " DO_(::google::protobuf::internal::WireFormat::WriteEnum(" + "$number$, this->$name$(i), output));\n"); + } + printer->Print("}\n"); } void RepeatedEnumFieldGenerator:: GenerateByteSize(io::Printer* printer) const { printer->Print(variables_, - "total_size += $tag_size$ * $name$_size();\n" - "for (int i = 0; i < $name$_size(); i++) {\n" - " total_size += ::google::protobuf::internal::WireFormat::EnumSize(\n" - " this->$name$(i));\n" - "}\n"); + "{\n" + " int data_size = 0;\n"); + printer->Indent(); + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " data_size += ::google::protobuf::internal::WireFormat::EnumSize(\n" + " this->$name$(i));\n" + "}\n"); + + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (data_size > 0) {\n" + " total_size += $tag_size$ + " + "::google::protobuf::internal::WireFormat::Int32Size(data_size);\n" + "}\n" + "_$name$_cached_byte_size_ = data_size;\n" + "total_size += data_size;\n"); + } else { + printer->Print(variables_, + "total_size += $tag_size$ * this->$name$_size() + data_size;\n"); + } + printer->Outdent(); + printer->Print("}\n"); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index eacceeaf..c6843e93 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -41,7 +41,7 @@ #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/wire_format.h> +#include <google/protobuf/wire_format_inl.h> #include <google/protobuf/descriptor.pb.h> namespace google { @@ -1169,10 +1169,9 @@ GenerateMergeFromCodedStream(io::Printer* printer) { " goto handle_uninterpreted;\n" " }\n", "number", SimpleItoa(field->number()), - "wiretype", kWireTypeNames[ - WireFormat::WireTypeForFieldType(field->type())]); + "wiretype", kWireTypeNames[WireFormat::WireTypeForField(field)]); - if (i > 0 || field->is_repeated()) { + if (i > 0 || (field->is_repeated() && !field->options().packed())) { printer->Print( " parse_$name$:\n", "name", field->name()); @@ -1184,7 +1183,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // switch() is slow since it can't be predicted well. Insert some if()s // here that attempt to predict the next tag. - if (field->is_repeated()) { + if (field->is_repeated() && !field->options().packed()) { // Expect repeats of this field. printer->Print( "if (input->ExpectTag($tag$)) goto parse_$name$;\n", @@ -1283,22 +1282,20 @@ void MessageGenerator::GenerateSerializeOneField( io::Printer* printer, const FieldDescriptor* field) { PrintFieldComment(printer, field); - if (field->is_repeated()) { - printer->Print( - "for (int i = 0; i < $name$_.size(); i++) {\n", - "name", FieldName(field)); - } else { + if (!field->is_repeated()) { printer->Print( "if (_has_bit($index$)) {\n", "index", SimpleItoa(field->index())); + printer->Indent(); } - printer->Indent(); - field_generators_.get(field).GenerateSerializeWithCachedSizes(printer); - printer->Outdent(); - printer->Print("}\n\n"); + if (!field->is_repeated()) { + printer->Outdent(); + printer->Print("}\n"); + } + printer->Print("\n"); } void MessageGenerator::GenerateSerializeOneExtensionRange( diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index d1c31067..7d57a6df 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -232,15 +232,17 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual(" - "$number$, this->$name$(i), output));\n"); + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual(" + "$number$, this->$name$(i), output));\n" + "}\n"); } void RepeatedMessageFieldGenerator:: GenerateByteSize(io::Printer* printer) const { printer->Print(variables_, - "total_size += $tag_size$ * $name$_size();\n" - "for (int i = 0; i < $name$_size(); i++) {\n" + "total_size += $tag_size$ * this->$name$_size();\n" + "for (int i = 0; i < this->$name$_size(); i++) {\n" " total_size +=\n" " ::google::protobuf::internal::WireFormat::$declared_type$SizeNoVirtual(\n" " this->$name$(i));\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index ef4072f0..768d30cc 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -227,6 +227,11 @@ void RepeatedPrimitiveFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, "::google::protobuf::RepeatedField< $type$ > $name$_;\n"); + if (descriptor_->options().packed() && + descriptor_->file()->options().optimize_for() == FileOptions::SPEED) { + printer->Print(variables_, + "mutable int _$name$_cached_byte_size_;\n"); + } } void RepeatedPrimitiveFieldGenerator:: @@ -283,33 +288,90 @@ GenerateInitializer(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - printer->Print(variables_, - "$type$ value;\n" - "DO_(::google::protobuf::internal::WireFormat::Read$declared_type$(input, &value));\n" - "add_$name$(value);\n"); + if (descriptor_->options().packed()) { + printer->Print("{\n"); + printer->Indent(); + printer->Print(variables_, + "::google::protobuf::uint32 length;\n" + "DO_(input->ReadVarint32(&length));\n" + "::google::protobuf::io::CodedInputStream::Limit limit = " + "input->PushLimit(length);\n" + "while (input->BytesUntilLimit() > 0) {\n" + " $type$ value;\n" + " DO_(::google::protobuf::internal::WireFormat::Read$declared_type$(" + "input, &value));\n" + " add_$name$(value);\n" + "}\n" + "input->PopLimit(limit);\n"); + printer->Outdent(); + printer->Print("}\n"); + } else { + printer->Print(variables_, + "$type$ value;\n" + "DO_(::google::protobuf::internal::WireFormat::Read$declared_type$(" + "input, &value));\n" + "add_$name$(value);\n"); + } } void RepeatedPrimitiveFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { + if (descriptor_->options().packed()) { + // Write the tag and the size. + printer->Print(variables_, + "if (this->$name$_size() > 0) {\n" + " DO_(::google::protobuf::internal::WireFormat::WriteTag(" + "$number$, ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED," + "output));\n" + " DO_(output->WriteVarint32(_$name$_cached_byte_size_));\n" + "}\n"); + } printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$(" - "$number$, this->$name$(i), output));\n"); + "for (int i = 0; i < this->$name$_size(); i++) {\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoTag(" + "this->$name$(i), output));\n"); + } else { + printer->Print(variables_, + " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$(" + "$number$, this->$name$(i), output));\n"); + } + printer->Print("}\n"); } void RepeatedPrimitiveFieldGenerator:: GenerateByteSize(io::Printer* printer) const { + printer->Print(variables_, + "{\n" + " int data_size = 0;\n"); + printer->Indent(); int fixed_size = FixedSize(descriptor_->type()); if (fixed_size == -1) { printer->Print(variables_, - "total_size += $tag_size$ * $name$_size();\n" - "for (int i = 0; i < $name$_size(); i++) {\n" - " total_size += ::google::protobuf::internal::WireFormat::$declared_type$Size(\n" + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " data_size += ::google::protobuf::internal::WireFormat::$declared_type$Size(\n" " this->$name$(i));\n" "}\n"); } else { printer->Print(variables_, - "total_size += ($tag_size$ + $fixed_size$) * $name$_size();\n"); + "data_size = $fixed_size$ * this->$name$_size();\n"); + } + + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (data_size > 0) {\n" + " total_size += $tag_size$ + " + "::google::protobuf::internal::WireFormat::Int32Size(data_size);\n" + "}\n" + "_$name$_cached_byte_size_ = data_size;\n" + "total_size += data_size;\n"); + } else { + printer->Print(variables_, + "total_size += $tag_size$ * this->$name$_size() + data_size;\n"); } + printer->Outdent(); + printer->Print("}\n"); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 3e694ab7..200e3d68 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -374,15 +374,17 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$(" - "$number$, this->$name$(i), output));\n"); + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$(" + "$number$, this->$name$(i), output));\n" + "}\n"); } void RepeatedStringFieldGenerator:: GenerateByteSize(io::Printer* printer) const { printer->Print(variables_, - "total_size += $tag_size$ * $name$_size();\n" - "for (int i = 0; i < $name$_size(); i++) {\n" + "total_size += $tag_size$ * this->$name$_size();\n" + "for (int i = 0; i < this->$name$_size(); i++) {\n" " total_size += ::google::protobuf::internal::WireFormat::$declared_type$Size(\n" " this->$name$(i));\n" "}\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto index a4d96ac5..79971a95 100644 --- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto +++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto @@ -54,6 +54,14 @@ message TestConflictingSymbolNames { optional int32 total_size = 6; optional int32 tag = 7; + enum TestEnum { FOO = 1; } + message Data1 { repeated int32 data = 1; } + message Data2 { repeated TestEnum data = 1; } + message Data3 { repeated string data = 1; } + message Data4 { repeated Data4 data = 1; } + message Data5 { repeated string data = 1 [ctype=STRING_PIECE]; } + message Data6 { repeated string data = 1 [ctype=CORD]; } + optional int32 source = 8; optional int32 value = 9; optional int32 file = 10; diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index 393c923b..c7e4ee3d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -225,7 +225,6 @@ TEST(GeneratedMessageTest, ClearOneField) { TEST(GeneratedMessageTest, CopyFrom) { unittest::TestAllTypes message1, message2; - string data; TestUtil::SetAllFields(&message1); message2.CopyFrom(message1); @@ -413,6 +412,13 @@ TEST(GeneratedMessageTest, Serialization) { EXPECT_TRUE(message2.ParseFromString(data)); TestUtil::ExpectAllFieldsSet(message2); + + unittest::TestPackedTypes packed_message1, packed_message2; + string packed_data; + TestUtil::SetPackedFields(&packed_message1); + packed_message1.SerializeToString(&packed_data); + EXPECT_TRUE(packed_message2.ParseFromString(packed_data)); + TestUtil::ExpectPackedFieldsSet(packed_message2); } diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index b1484763..4aac6493 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -71,7 +71,8 @@ void EnumGenerator::Generate(io::Printer* printer) { descriptor_->containing_type() == NULL && descriptor_->file()->options().java_multiple_files(); printer->Print( - "public $static$ enum $classname$ {\n", + "public $static$ enum $classname$\n" + " implements com.google.protobuf.ProtocolMessageEnum {\n", "static", is_own_file ? "" : "static", "classname", descriptor_->name()); printer->Indent(); diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index e95fdab4..2153042d 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -39,6 +39,7 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_helpers.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format_inl.h> #include <google/protobuf/stubs/strutil.h> namespace google { @@ -64,6 +65,9 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["number"] = SimpleItoa(descriptor->number()); (*variables)["type"] = type; (*variables)["default"] = type + "." + default_value->name(); + (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); + (*variables)["tag_size"] = SimpleItoa( + internal::WireFormat::TagSize(descriptor->number(), descriptor->type())); } } // namespace @@ -97,6 +101,9 @@ GenerateBuilderMembers(io::Printer* printer) const { " return result.get$capitalized_name$();\n" "}\n" "public Builder set$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" " result.has$capitalized_name$ = true;\n" " result.$name$_ = value;\n" " return this;\n" @@ -176,6 +183,12 @@ GenerateMembers(io::Printer* printer) const { "public $type$ get$capitalized_name$(int index) {\n" " return $name$_.get(index);\n" "}\n"); + + if (descriptor_->options().packed() && + descriptor_->file()->options().optimize_for() == FileOptions::SPEED) { + printer->Print(variables_, + "private int $name$MemoizedSerializedSize;\n"); + } } void RepeatedEnumFieldGenerator:: @@ -195,10 +208,16 @@ GenerateBuilderMembers(io::Printer* printer) const { " return result.get$capitalized_name$(index);\n" "}\n" "public Builder set$capitalized_name$(int index, $type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" " result.$name$_.set(index, value);\n" " return this;\n" "}\n" "public Builder add$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" " if (result.$name$_.isEmpty()) {\n" " result.$name$_ = new java.util.ArrayList<$type$>();\n" " }\n" @@ -241,6 +260,16 @@ GenerateBuildingCode(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { + // If packed, set up the while loop + if (descriptor_->options().packed()) { + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int oldLimit = input.pushLimit(length);\n" + "while(input.getBytesUntilLimit() > 0) {\n"); + printer->Indent(); + } + + // Read and store the enum printer->Print(variables_, "int rawValue = input.readEnum();\n" "$type$ value = $type$.valueOf(rawValue);\n" @@ -249,23 +278,68 @@ GenerateParsingCode(io::Printer* printer) const { "} else {\n" " add$capitalized_name$(value);\n" "}\n"); + + if (descriptor_->options().packed()) { + printer->Outdent(); + printer->Print(variables_, + "}\n" + "input.popLimit(oldLimit);\n"); + } } void RepeatedEnumFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { - printer->Print(variables_, - "for ($type$ element : get$capitalized_name$List()) {\n" - " output.writeEnum($number$, element.getNumber());\n" - "}\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (get$capitalized_name$List().size() > 0) {\n" + " output.writeRawVarint32($tag$);\n" + " output.writeRawVarint32($name$MemoizedSerializedSize);\n" + "}\n" + "for ($type$ element : get$capitalized_name$List()) {\n" + " output.writeEnumNoTag(element.getNumber());\n" + "}\n"); + } else { + printer->Print(variables_, + "for ($type$ element : get$capitalized_name$List()) {\n" + " output.writeEnum($number$, element.getNumber());\n" + "}\n"); + } } void RepeatedEnumFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, + "{\n" + " int dataSize = 0;\n"); + printer->Indent(); + + printer->Print(variables_, "for ($type$ element : get$capitalized_name$List()) {\n" - " size += com.google.protobuf.CodedOutputStream\n" - " .computeEnumSize($number$, element.getNumber());\n" + " dataSize += com.google.protobuf.CodedOutputStream\n" + " .computeEnumSizeNoTag(element.getNumber());\n" "}\n"); + printer->Print( + "size += dataSize;\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (!get$capitalized_name$List().isEmpty()) {" + " size += $tag_size$;\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeRawVarint32Size(dataSize);\n" + "}"); + } else { + printer->Print(variables_, + "size += $tag_size$ * get$capitalized_name$List().size();\n"); + } + + // cache the data size for packed fields. + if (descriptor_->options().packed()) { + printer->Print(variables_, + "$name$MemoizedSerializedSize = dataSize;\n"); + } + + printer->Outdent(); + printer->Print("}\n"); } string RepeatedEnumFieldGenerator::GetBoxedType() const { diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 3fdd1d57..9a4b2f79 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -41,7 +41,7 @@ #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/wire_format.h> +#include <google/protobuf/wire_format_inl.h> #include <google/protobuf/descriptor.pb.h> namespace google { @@ -500,6 +500,7 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) { "public static Builder newBuilder($classname$ prototype) {\n" " return new Builder().mergeFrom(prototype);\n" "}\n" + "public Builder toBuilder() { return newBuilder(this); }\n" "\n", "classname", ClassName(descriptor_)); @@ -634,6 +635,13 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { } printer->Outdent(); + + // if message type has extensions + if (descriptor_->extension_range_count() > 0) { + printer->Print( + " this.mergeExtensionFields(other);\n"); + } + printer->Print( " this.mergeUnknownFields(other.getUnknownFields());\n" " return this;\n" @@ -692,7 +700,7 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = sorted_fields[i]; uint32 tag = WireFormat::MakeTag(field->number(), - WireFormat::WireTypeForFieldType(field->type())); + WireFormat::WireTypeForField(field)); printer->Print( "case $tag$: {\n", diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index c85a1598..bbddddde 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -94,6 +94,9 @@ GenerateBuilderMembers(io::Printer* printer) const { " return result.get$capitalized_name$();\n" "}\n" "public Builder set$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" " result.has$capitalized_name$ = true;\n" " result.$name$_ = value;\n" " return this;\n" @@ -216,6 +219,9 @@ GenerateBuilderMembers(io::Printer* printer) const { " return result.get$capitalized_name$(index);\n" "}\n" "public Builder set$capitalized_name$(int index, $type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" " result.$name$_.set(index, value);\n" " return this;\n" "}\n" @@ -225,6 +231,9 @@ GenerateBuilderMembers(io::Printer* printer) const { " return this;\n" "}\n" "public Builder add$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" " if (result.$name$_.isEmpty()) {\n" " result.$name$_ = new java.util.ArrayList<$type$>();\n" " }\n" diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index fb4e650f..798e8608 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -39,6 +39,7 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_helpers.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format_inl.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> @@ -47,6 +48,8 @@ namespace protobuf { namespace compiler { namespace java { +using internal::WireFormat; + namespace { const char* PrimitiveTypeName(JavaType type) { @@ -69,6 +72,26 @@ const char* PrimitiveTypeName(JavaType type) { return NULL; } +bool IsReferenceType(JavaType type) { + switch (type) { + case JAVATYPE_INT : return false; + case JAVATYPE_LONG : return false; + case JAVATYPE_FLOAT : return false; + case JAVATYPE_DOUBLE : return false; + case JAVATYPE_BOOLEAN: return false; + case JAVATYPE_STRING : return true; + case JAVATYPE_BYTES : return true; + case JAVATYPE_ENUM : return true; + case JAVATYPE_MESSAGE: return true; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + const char* GetCapitalizedType(const FieldDescriptor* field) { switch (field->type()) { case FieldDescriptor::TYPE_INT32 : return "Int32" ; @@ -108,6 +131,38 @@ bool AllPrintableAscii(const string& text) { return true; } +// For encodings with fixed sizes, returns that size in bytes. Otherwise +// returns -1. +int FixedSize(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32 : return -1; + case FieldDescriptor::TYPE_INT64 : return -1; + case FieldDescriptor::TYPE_UINT32 : return -1; + case FieldDescriptor::TYPE_UINT64 : return -1; + case FieldDescriptor::TYPE_SINT32 : return -1; + case FieldDescriptor::TYPE_SINT64 : return -1; + case FieldDescriptor::TYPE_FIXED32 : return WireFormat::kFixed32Size; + case FieldDescriptor::TYPE_FIXED64 : return WireFormat::kFixed64Size; + case FieldDescriptor::TYPE_SFIXED32: return WireFormat::kSFixed32Size; + case FieldDescriptor::TYPE_SFIXED64: return WireFormat::kSFixed64Size; + case FieldDescriptor::TYPE_FLOAT : return WireFormat::kFloatSize; + case FieldDescriptor::TYPE_DOUBLE : return WireFormat::kDoubleSize; + + case FieldDescriptor::TYPE_BOOL : return WireFormat::kBoolSize; + case FieldDescriptor::TYPE_ENUM : return -1; + + case FieldDescriptor::TYPE_STRING : return -1; + case FieldDescriptor::TYPE_BYTES : return -1; + case FieldDescriptor::TYPE_GROUP : return -1; + case FieldDescriptor::TYPE_MESSAGE : return -1; + + // No default because we want the compiler to complain if any new + // types are added. + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return -1; +} + string DefaultValue(const FieldDescriptor* field) { // Switch on cpp_type since we need to know which default_value_* method // of FieldDescriptor to call. @@ -177,8 +232,22 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor)); (*variables)["default"] = DefaultValue(descriptor); (*variables)["capitalized_type"] = GetCapitalizedType(descriptor); + (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); + (*variables)["tag_size"] = SimpleItoa( + WireFormat::TagSize(descriptor->number(), descriptor->type())); + if (IsReferenceType(GetJavaType(descriptor))) { + (*variables)["null_check"] = + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n"; + } else { + (*variables)["null_check"] = ""; + } + int fixed_size = FixedSize(descriptor->type()); + if (fixed_size != -1) { + (*variables)["fixed_size"] = SimpleItoa(fixed_size); + } } - } // namespace // =================================================================== @@ -210,6 +279,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " return result.get$capitalized_name$();\n" "}\n" "public Builder set$capitalized_name$($type$ value) {\n" + "$null_check$" " result.has$capitalized_name$ = true;\n" " result.$name$_ = value;\n" " return this;\n" @@ -283,6 +353,12 @@ GenerateMembers(io::Printer* printer) const { "public $type$ get$capitalized_name$(int index) {\n" " return $name$_.get(index);\n" "}\n"); + + if (descriptor_->options().packed() && + descriptor_->file()->options().optimize_for() == FileOptions::SPEED) { + printer->Print(variables_, + "private int $name$MemoizedSerializedSize;\n"); + } } void RepeatedPrimitiveFieldGenerator:: @@ -302,10 +378,12 @@ GenerateBuilderMembers(io::Printer* printer) const { " return result.get$capitalized_name$(index);\n" "}\n" "public Builder set$capitalized_name$(int index, $type$ value) {\n" + "$null_check$" " result.$name$_.set(index, value);\n" " return this;\n" "}\n" "public Builder add$capitalized_name$($type$ value) {\n" + "$null_check$" " if (result.$name$_.isEmpty()) {\n" " result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n" " }\n" @@ -348,25 +426,80 @@ GenerateBuildingCode(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { - printer->Print(variables_, - "add$capitalized_name$(input.read$capitalized_type$());\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int limit = input.pushLimit(length);\n" + "while (input.getBytesUntilLimit() > 0) {\n" + " add$capitalized_name$(input.read$capitalized_type$());\n" + "}\n" + "input.popLimit(limit);\n"); + } else { + printer->Print(variables_, + "add$capitalized_name$(input.read$capitalized_type$());\n"); + } } void RepeatedPrimitiveFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { - printer->Print(variables_, - "for ($type$ element : get$capitalized_name$List()) {\n" - " output.write$capitalized_type$($number$, element);\n" - "}\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (get$capitalized_name$List().size() > 0) {\n" + " output.writeRawVarint32($tag$);\n" + " output.writeRawVarint32($name$MemoizedSerializedSize);\n" + "}\n" + "for ($type$ element : get$capitalized_name$List()) {\n" + " output.write$capitalized_type$NoTag(element);\n" + "}\n"); + } else { + printer->Print(variables_, + "for ($type$ element : get$capitalized_name$List()) {\n" + " output.write$capitalized_type$($number$, element);\n" + "}\n"); + } } void RepeatedPrimitiveFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, - "for ($type$ element : get$capitalized_name$List()) {\n" - " size += com.google.protobuf.CodedOutputStream\n" - " .compute$capitalized_type$Size($number$, element);\n" - "}\n"); + "{\n" + " int dataSize = 0;\n"); + printer->Indent(); + + if (FixedSize(descriptor_->type()) == -1) { + printer->Print(variables_, + "for ($type$ element : get$capitalized_name$List()) {\n" + " dataSize += com.google.protobuf.CodedOutputStream\n" + " .compute$capitalized_type$SizeNoTag(element);\n" + "}\n"); + } else { + printer->Print(variables_, + "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n"); + } + + printer->Print( + "size += dataSize;\n"); + + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (!get$capitalized_name$List().isEmpty()) {\n" + " size += $tag_size$;\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeInt32SizeNoTag(dataSize);\n" + "}\n"); + } else { + printer->Print(variables_, + "size += $tag_size$ * get$capitalized_name$List().size();\n"); + } + + // cache the data size for packed fields. + if (descriptor_->options().packed()) { + printer->Print(variables_, + "$name$MemoizedSerializedSize = dataSize;\n"); + } + + printer->Outdent(); + printer->Print("}\n"); } string RepeatedPrimitiveFieldGenerator::GetBoxedType() const { diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index 754dcbda..ca69fd4c 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -111,7 +111,6 @@ void PrintTopBoilerplate( io::Printer* printer, const FileDescriptor* file, bool descriptor_proto) { // TODO(robinson): Allow parameterization of Python version? printer->Print( - "#!/usr/bin/python2.4\n" "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" "\n" "from google.protobuf import descriptor\n" diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 21c709fb..eb5b5937 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -122,6 +122,35 @@ namespace { const string kEmptyString; +string ToCamelCase(const string& input) { + bool capitalize_next = false; + string result; + result.reserve(input.size()); + + for (int i = 0; i < input.size(); i++) { + if (input[i] == '_') { + capitalize_next = true; + } else if (capitalize_next) { + // Note: I distrust ctype.h due to locales. + if ('a' <= input[i] && input[i] <= 'z') { + result.push_back(input[i] - 'a' + 'A'); + } else { + result.push_back(input[i]); + } + capitalize_next = false; + } else { + result.push_back(input[i]); + } + } + + // Lower-case the first letter. + if (!result.empty() && 'A' <= result[0] && result[0] <= 'Z') { + result[0] = result[0] - 'A' + 'a'; + } + + return result; +} + // A DescriptorPool contains a bunch of hash_maps to implement the // various Find*By*() methods. Since hashtable lookups are O(1), it's // most efficient to construct a fixed set of large hash_maps used by @@ -253,6 +282,9 @@ typedef hash_map<PointerStringPair, Symbol, typedef hash_map<const char*, const FileDescriptor*, hash<const char*>, CStringEqual> FilesByNameMap; +typedef hash_map<PointerStringPair, const FieldDescriptor*, + PointerStringPairHash, PointerStringPairEqual> + FieldsByNameMap; typedef hash_map<DescriptorIntPair, const FieldDescriptor*, PointerIntegerPairHash<DescriptorIntPair> > FieldsByNumberMap; @@ -296,21 +328,29 @@ class DescriptorPool::Tables { // Finding items. // Find symbols. These return a null Symbol (symbol.IsNull() is true) - // if not found. FindSymbolOfType() additionally returns null if the - // symbol is not of the given type. + // if not found. inline Symbol FindSymbol(const string& key) const; - inline Symbol FindSymbolOfType(const string& key, - const Symbol::Type type) const; inline Symbol FindNestedSymbol(const void* parent, const string& name) const; inline Symbol FindNestedSymbolOfType(const void* parent, const string& name, const Symbol::Type type) const; + // This implements the body of DescriptorPool::Find*ByName(). It should + // really be a private method of DescriptorPool, but that would require + // declaring Symbol in descriptor.h, which would drag all kinds of other + // stuff into the header. Yay C++. + Symbol FindByNameHelper( + const DescriptorPool* pool, const string& name) const; + // These return NULL if not found. inline const FileDescriptor* FindFile(const string& key) const; inline const FieldDescriptor* FindFieldByNumber( const Descriptor* parent, int number) const; + inline const FieldDescriptor* FindFieldByLowercaseName( + const void* parent, const string& lowercase_name) const; + inline const FieldDescriptor* FindFieldByCamelcaseName( + const void* parent, const string& camelcase_name) const; inline const EnumValueDescriptor* FindEnumValueByNumber( const EnumDescriptor* parent, int number) const; @@ -330,6 +370,10 @@ class DescriptorPool::Tables { bool AddFieldByNumber(const FieldDescriptor* field); bool AddEnumValueByNumber(const EnumValueDescriptor* value); + // Adds the field to the lowercase_name and camelcase_name maps. Never + // fails because we allow duplicates; the first field by the name wins. + void AddFieldByStylizedNames(const FieldDescriptor* field); + // Like AddSymbol(), but only adds to symbols_by_parent_, not // symbols_by_name_. Used for enum values, which need to be registered // under multiple parents (their type and its parent). @@ -364,6 +408,8 @@ class DescriptorPool::Tables { SymbolsByNameMap symbols_by_name_; SymbolsByParentMap symbols_by_parent_; FilesByNameMap files_by_name_; + FieldsByNameMap fields_by_lowercase_name_; + FieldsByNameMap fields_by_camelcase_name_; FieldsByNumberMap fields_by_number_; // Includes extensions. EnumValuesByNumberMap enum_values_by_number_; @@ -373,6 +419,8 @@ class DescriptorPool::Tables { vector<const char* > symbols_after_checkpoint_; vector<PointerStringPair> symbols_by_parent_after_checkpoint_; vector<const char* > files_after_checkpoint_; + vector<PointerStringPair> field_lowercase_names_after_checkpoint_; + vector<PointerStringPair> field_camelcase_names_after_checkpoint_; vector<DescriptorIntPair> field_numbers_after_checkpoint_; vector<EnumIntPair > enum_numbers_after_checkpoint_; @@ -404,6 +452,8 @@ void DescriptorPool::Tables::Checkpoint() { symbols_after_checkpoint_.clear(); symbols_by_parent_after_checkpoint_.clear(); files_after_checkpoint_.clear(); + field_lowercase_names_after_checkpoint_.clear(); + field_camelcase_names_after_checkpoint_.clear(); field_numbers_after_checkpoint_.clear(); enum_numbers_after_checkpoint_.clear(); } @@ -418,6 +468,12 @@ void DescriptorPool::Tables::Rollback() { for (int i = 0; i < files_after_checkpoint_.size(); i++) { files_by_name_.erase(files_after_checkpoint_[i]); } + for (int i = 0; i < field_lowercase_names_after_checkpoint_.size(); i++) { + fields_by_lowercase_name_.erase(field_lowercase_names_after_checkpoint_[i]); + } + for (int i = 0; i < field_camelcase_names_after_checkpoint_.size(); i++) { + fields_by_camelcase_name_.erase(field_camelcase_names_after_checkpoint_[i]); + } for (int i = 0; i < field_numbers_after_checkpoint_.size(); i++) { fields_by_number_.erase(field_numbers_after_checkpoint_[i]); } @@ -428,6 +484,8 @@ void DescriptorPool::Tables::Rollback() { symbols_after_checkpoint_.clear(); symbols_by_parent_after_checkpoint_.clear(); files_after_checkpoint_.clear(); + field_lowercase_names_after_checkpoint_.clear(); + field_camelcase_names_after_checkpoint_.clear(); field_numbers_after_checkpoint_.clear(); enum_numbers_after_checkpoint_.clear(); @@ -455,13 +513,6 @@ inline Symbol DescriptorPool::Tables::FindSymbol(const string& key) const { } } -inline Symbol DescriptorPool::Tables::FindSymbolOfType( - const string& key, const Symbol::Type type) const { - Symbol result = FindSymbol(key); - if (result.type != type) return kNullSymbol; - return result; -} - inline Symbol DescriptorPool::Tables::FindNestedSymbol( const void* parent, const string& name) const { const Symbol* result = @@ -480,6 +531,27 @@ inline Symbol DescriptorPool::Tables::FindNestedSymbolOfType( return result; } +Symbol DescriptorPool::Tables::FindByNameHelper( + const DescriptorPool* pool, const string& name) const { + MutexLockMaybe lock(pool->mutex_); + Symbol result = FindSymbol(name); + + if (result.IsNull() && pool->underlay_ != NULL) { + // Symbol not found; check the underlay. + result = + pool->underlay_->tables_->FindByNameHelper(pool->underlay_, name); + } + + if (result.IsNull()) { + // Symbol still not found, so check fallback database. + if (pool->TryFindSymbolInFallbackDatabase(name)) { + result = FindSymbol(name); + } + } + + return result; +} + inline const FileDescriptor* DescriptorPool::Tables::FindFile( const string& key) const { return FindPtrOrNull(files_by_name_, key.c_str()); @@ -490,6 +562,18 @@ inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByNumber( return FindPtrOrNull(fields_by_number_, make_pair(parent, number)); } +inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByLowercaseName( + const void* parent, const string& lowercase_name) const { + return FindPtrOrNull(fields_by_lowercase_name_, + PointerStringPair(parent, lowercase_name.c_str())); +} + +inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByCamelcaseName( + const void* parent, const string& camelcase_name) const { + return FindPtrOrNull(fields_by_camelcase_name_, + PointerStringPair(parent, camelcase_name.c_str())); +} + inline const EnumValueDescriptor* DescriptorPool::Tables::FindEnumValueByNumber( const EnumDescriptor* parent, int number) const { return FindPtrOrNull(enum_values_by_number_, make_pair(parent, number)); @@ -537,6 +621,30 @@ bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) { } } +void DescriptorPool::Tables::AddFieldByStylizedNames( + const FieldDescriptor* field) { + const void* parent; + if (field->is_extension()) { + if (field->extension_scope() == NULL) { + parent = field->file(); + } else { + parent = field->extension_scope(); + } + } else { + parent = field->containing_type(); + } + + PointerStringPair lowercase_key(parent, field->lowercase_name().c_str()); + if (InsertIfNotPresent(&fields_by_lowercase_name_, lowercase_key, field)) { + field_lowercase_names_after_checkpoint_.push_back(lowercase_key); + } + + PointerStringPair camelcase_key(parent, field->camelcase_name().c_str()); + if (InsertIfNotPresent(&fields_by_camelcase_name_, camelcase_key, field)) { + field_camelcase_names_after_checkpoint_.push_back(camelcase_key); + } +} + bool DescriptorPool::Tables::AddFieldByNumber(const FieldDescriptor* field) { DescriptorIntPair key(field->containing_type(), field->number()); if (InsertIfNotPresent(&fields_by_number_, key, field)) { @@ -689,122 +797,55 @@ const FileDescriptor* DescriptorPool::FindFileContainingSymbol( const Descriptor* DescriptorPool::FindMessageTypeByName( const string& name) const { - MutexLockMaybe lock(mutex_); - Symbol result = tables_->FindSymbolOfType(name, Symbol::MESSAGE); - if (!result.IsNull()) return result.descriptor; - if (underlay_ != NULL) { - const Descriptor* result = underlay_->FindMessageTypeByName(name); - if (result != NULL) return result; - } - if (TryFindSymbolInFallbackDatabase(name)) { - Symbol result = tables_->FindSymbolOfType(name, Symbol::MESSAGE); - if (!result.IsNull()) return result.descriptor; - } - return NULL; + Symbol result = tables_->FindByNameHelper(this, name); + return (result.type == Symbol::MESSAGE) ? result.descriptor : NULL; } const FieldDescriptor* DescriptorPool::FindFieldByName( const string& name) const { - MutexLockMaybe lock(mutex_); - Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD); - if (!result.IsNull() && !result.field_descriptor->is_extension()) { + Symbol result = tables_->FindByNameHelper(this, name); + if (result.type == Symbol::FIELD && + !result.field_descriptor->is_extension()) { return result.field_descriptor; + } else { + return NULL; } - if (underlay_ != NULL) { - const FieldDescriptor* result = underlay_->FindFieldByName(name); - if (result != NULL) return result; - } - if (TryFindSymbolInFallbackDatabase(name)) { - Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD); - if (!result.IsNull() && !result.field_descriptor->is_extension()) { - return result.field_descriptor; - } - } - return NULL; } const FieldDescriptor* DescriptorPool::FindExtensionByName( const string& name) const { - MutexLockMaybe lock(mutex_); - Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD); - if (!result.IsNull() && result.field_descriptor->is_extension()) { + Symbol result = tables_->FindByNameHelper(this, name); + if (result.type == Symbol::FIELD && + result.field_descriptor->is_extension()) { return result.field_descriptor; + } else { + return NULL; } - if (underlay_ != NULL) { - const FieldDescriptor* result = underlay_->FindExtensionByName(name); - if (result != NULL) return result; - } - if (TryFindSymbolInFallbackDatabase(name)) { - Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD); - if (!result.IsNull() && result.field_descriptor->is_extension()) { - return result.field_descriptor; - } - } - return NULL; } const EnumDescriptor* DescriptorPool::FindEnumTypeByName( const string& name) const { - MutexLockMaybe lock(mutex_); - Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM); - if (!result.IsNull()) return result.enum_descriptor; - if (underlay_ != NULL) { - const EnumDescriptor* result = underlay_->FindEnumTypeByName(name); - if (result != NULL) return result; - } - if (TryFindSymbolInFallbackDatabase(name)) { - Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM); - if (!result.IsNull()) return result.enum_descriptor; - } - return NULL; + Symbol result = tables_->FindByNameHelper(this, name); + return (result.type == Symbol::ENUM) ? result.enum_descriptor : NULL; } const EnumValueDescriptor* DescriptorPool::FindEnumValueByName( const string& name) const { - MutexLockMaybe lock(mutex_); - Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM_VALUE); - if (!result.IsNull()) return result.enum_value_descriptor; - if (underlay_ != NULL) { - const EnumValueDescriptor* result = underlay_->FindEnumValueByName(name); - if (result != NULL) return result; - } - if (TryFindSymbolInFallbackDatabase(name)) { - Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM_VALUE); - if (!result.IsNull()) return result.enum_value_descriptor; - } - return NULL; + Symbol result = tables_->FindByNameHelper(this, name); + return (result.type == Symbol::ENUM_VALUE) ? + result.enum_value_descriptor : NULL; } const ServiceDescriptor* DescriptorPool::FindServiceByName( const string& name) const { - MutexLockMaybe lock(mutex_); - Symbol result = tables_->FindSymbolOfType(name, Symbol::SERVICE); - if (!result.IsNull()) return result.service_descriptor; - if (underlay_ != NULL) { - const ServiceDescriptor* result = underlay_->FindServiceByName(name); - if (result != NULL) return result; - } - if (TryFindSymbolInFallbackDatabase(name)) { - Symbol result = tables_->FindSymbolOfType(name, Symbol::SERVICE); - if (!result.IsNull()) return result.service_descriptor; - } - return NULL; + Symbol result = tables_->FindByNameHelper(this, name); + return (result.type == Symbol::SERVICE) ? result.service_descriptor : NULL; } const MethodDescriptor* DescriptorPool::FindMethodByName( const string& name) const { - MutexLockMaybe lock(mutex_); - Symbol result = tables_->FindSymbolOfType(name, Symbol::METHOD); - if (!result.IsNull()) return result.method_descriptor; - if (underlay_ != NULL) { - const MethodDescriptor* result = underlay_->FindMethodByName(name); - if (result != NULL) return result; - } - if (TryFindSymbolInFallbackDatabase(name)) { - Symbol result = tables_->FindSymbolOfType(name, Symbol::METHOD); - if (!result.IsNull()) return result.method_descriptor; - } - return NULL; + Symbol result = tables_->FindByNameHelper(this, name); + return (result.type == Symbol::METHOD) ? result.method_descriptor : NULL; } const FieldDescriptor* DescriptorPool::FindExtensionByNumber( @@ -844,6 +885,30 @@ Descriptor::FindFieldByNumber(int key) const { } const FieldDescriptor* +Descriptor::FindFieldByLowercaseName(const string& key) const { + MutexLockMaybe lock(file()->pool()->mutex_); + const FieldDescriptor* result = + file()->pool()->tables_->FindFieldByLowercaseName(this, key); + if (result == NULL || result->is_extension()) { + return NULL; + } else { + return result; + } +} + +const FieldDescriptor* +Descriptor::FindFieldByCamelcaseName(const string& key) const { + MutexLockMaybe lock(file()->pool()->mutex_); + const FieldDescriptor* result = + file()->pool()->tables_->FindFieldByCamelcaseName(this, key); + if (result == NULL || result->is_extension()) { + return NULL; + } else { + return result; + } +} + +const FieldDescriptor* Descriptor::FindFieldByName(const string& key) const { MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = @@ -867,6 +932,30 @@ Descriptor::FindExtensionByName(const string& key) const { } } +const FieldDescriptor* +Descriptor::FindExtensionByLowercaseName(const string& key) const { + MutexLockMaybe lock(file()->pool()->mutex_); + const FieldDescriptor* result = + file()->pool()->tables_->FindFieldByLowercaseName(this, key); + if (result == NULL || !result->is_extension()) { + return NULL; + } else { + return result; + } +} + +const FieldDescriptor* +Descriptor::FindExtensionByCamelcaseName(const string& key) const { + MutexLockMaybe lock(file()->pool()->mutex_); + const FieldDescriptor* result = + file()->pool()->tables_->FindFieldByCamelcaseName(this, key); + if (result == NULL || !result->is_extension()) { + return NULL; + } else { + return result; + } +} + const Descriptor* Descriptor::FindNestedTypeByName(const string& key) const { MutexLockMaybe lock(file()->pool()->mutex_); @@ -995,6 +1084,30 @@ FileDescriptor::FindExtensionByName(const string& key) const { } } +const FieldDescriptor* +FileDescriptor::FindExtensionByLowercaseName(const string& key) const { + MutexLockMaybe lock(pool()->mutex_); + const FieldDescriptor* result = + pool()->tables_->FindFieldByLowercaseName(this, key); + if (result == NULL || !result->is_extension()) { + return NULL; + } else { + return result; + } +} + +const FieldDescriptor* +FileDescriptor::FindExtensionByCamelcaseName(const string& key) const { + MutexLockMaybe lock(pool()->mutex_); + const FieldDescriptor* result = + pool()->tables_->FindFieldByCamelcaseName(this, key); + if (result == NULL || !result->is_extension()) { + return NULL; + } else { + return result; + } +} + bool Descriptor::IsExtensionNumber(int number) const { // Linear search should be fine because we don't expect a message to have // more than a couple extension ranges. @@ -2504,6 +2617,22 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, result->number_ = proto.number(); result->is_extension_ = is_extension; + // If .proto files follow the style guide then the name should already be + // lower-cased. If that's the case we can just reuse the string we already + // allocated rather than allocate a new one. + string lowercase_name(proto.name()); + LowerString(&lowercase_name); + if (lowercase_name == proto.name()) { + result->lowercase_name_ = result->name_; + } else { + result->lowercase_name_ = tables_->AllocateString(lowercase_name); + } + + // Don't bother with the above optimization for camel-case names since + // .proto files that follow the guide shouldn't be using names in this + // format, so the optimization wouldn't help much. + result->camelcase_name_ = tables_->AllocateString(ToCamelCase(proto.name())); + // Some compilers do not allow static_cast directly between two enum types, // so we must cast to int first. result->type_ = static_cast<FieldDescriptor::Type>( @@ -3042,6 +3171,9 @@ void DescriptorBuilder::CrossLinkField( conflicting_field->name())); } } + + // Add the field to the lowercase-name and camelcase-name tables. + tables_->AddFieldByStylizedNames(field); } void DescriptorBuilder::CrossLinkEnum( @@ -3136,6 +3268,20 @@ void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field, ValidateMapKey(field, proto); } + // Only repeated primitive fields may be packed. + if (field->options().packed()) { + if (!field->is_repeated() || + field->type() == FieldDescriptor::TYPE_STRING || + field->type() == FieldDescriptor::TYPE_GROUP || + field->type() == FieldDescriptor::TYPE_MESSAGE || + field->type() == FieldDescriptor::TYPE_BYTES) { + AddError( + field->full_name(), proto, + DescriptorPool::ErrorCollector::TYPE, + "[packed = true] can only be specified for repeated primitive fields."); + } + } + // Note: Default instance may not yet be initialized here, so we have to // avoid reading from it. if (field->containing_type_ != NULL && diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 6d496e99..918aafbc 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -156,6 +156,19 @@ class LIBPROTOBUF_EXPORT Descriptor { // Looks up a field by name. Returns NULL if no such field exists. const FieldDescriptor* FindFieldByName(const string& name) const; + // Looks up a field by lowercased name (as returned by lowercase_name()). + // This lookup may be ambiguous if multiple field names differ only by case, + // in which case the field returned is chosen arbitrarily from the matches. + const FieldDescriptor* FindFieldByLowercaseName( + const string& lowercase_name) const; + + // Looks up a field by camel-case name (as returned by camelcase_name()). + // This lookup may be ambiguous if multiple field names differ in a way that + // leads them to have identical camel-case names, in which case the field + // returned is chosen arbitrarily from the matches. + const FieldDescriptor* FindFieldByCamelcaseName( + const string& camelcase_name) const; + // Nested type stuff ----------------------------------------------- // The number of nested types in this message type. @@ -213,6 +226,14 @@ class LIBPROTOBUF_EXPORT Descriptor { // defined within this message type's scope. const FieldDescriptor* FindExtensionByName(const string& name) const; + // Similar to FindFieldByLowercaseName(), but finds extensions defined within + // this message type's scope. + const FieldDescriptor* FindExtensionByLowercaseName(const string& name) const; + + // Similar to FindFieldByCamelcaseName(), but finds extensions defined within + // this message type's scope. + const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const; + private: typedef MessageOptions OptionsType; @@ -336,6 +357,25 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { bool is_extension() const; // Is this an extension field? int number() const; // Declared tag number. + // Same as name() except converted to lower-case. This (and especially the + // FindFieldByLowercaseName() method) can be useful when parsing formats + // which prefer to use lowercase naming style. (Although, technically + // field names should be lowercased anyway according to the protobuf style + // guide, so this only makes a difference when dealing with old .proto files + // which do not follow the guide.) + const string& lowercase_name() const; + + // Same as name() except converted to camel-case. In this conversion, any + // time an underscore appears in the name, it is removed and the next + // letter is capitalized. Furthermore, the first letter of the name is + // lower-cased. Examples: + // FooBar -> fooBar + // foo_bar -> fooBar + // fooBar -> fooBar + // This (and especially the FindFieldByCamelcaseName() method) can be useful + // when parsing formats which prefer to use camel-case naming style. + const string& camelcase_name() const; + Type type() const; // Declared type of this field. CppType cpp_type() const; // C++ type of this field. Label label() const; // optional/required/repeated @@ -431,6 +471,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { const string* name_; const string* full_name_; + const string* lowercase_name_; + const string* camelcase_name_; const FileDescriptor* file_; int number_; Type type_; @@ -773,6 +815,12 @@ class LIBPROTOBUF_EXPORT FileDescriptor { const ServiceDescriptor* FindServiceByName(const string& name) const; // Find a top-level extension definition by name. Returns NULL if not found. const FieldDescriptor* FindExtensionByName(const string& name) const; + // Similar to FindExtensionByName(), but searches by lowercased-name. See + // Descriptor::FindFieldByLowercaseName(). + const FieldDescriptor* FindExtensionByLowercaseName(const string& name) const; + // Similar to FindExtensionByName(), but searches by camelcased-name. See + // Descriptor::FindFieldByCamelcaseName(). + const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const; // See Descriptor::CopyTo(). void CopyTo(FileDescriptorProto* proto) const; @@ -1084,6 +1132,8 @@ PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions); PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name) PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name) +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, lowercase_name) +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, camelcase_name) PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*) PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, number, int) PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, is_extension, bool) diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index ceb99bf1..0df3f3bd 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -301,8 +301,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr MessageOptions_descriptor_, MessageOptions::default_instance_); FieldOptions_descriptor_ = file->message_type(10); FieldOptions::default_instance_ = new FieldOptions(); - static const int FieldOptions_offsets_[3] = { + static const int FieldOptions_offsets_[4] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, packed_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, experimental_map_key_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, uninterpreted_option_), }; @@ -519,30 +520,30 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto() { "\n\016MessageOptions\022&\n\027message_set_wire_for" "mat\030\001 \001(\010:\005false\022C\n\024uninterpreted_option" "\030\347\007 \003(\0132$.google.protobuf.UninterpretedO" - "ption*\t\010\350\007\020\200\200\200\200\002\"\325\001\n\014FieldOptions\0222\n\005cty" + "ption*\t\010\350\007\020\200\200\200\200\002\"\345\001\n\014FieldOptions\0222\n\005cty" "pe\030\001 \001(\0162#.google.protobuf.FieldOptions." - "CType\022\034\n\024experimental_map_key\030\t \001(\t\022C\n\024u" - "ninterpreted_option\030\347\007 \003(\0132$.google.prot" - "obuf.UninterpretedOption\"#\n\005CType\022\010\n\004COR" - "D\020\001\022\020\n\014STRING_PIECE\020\002*\t\010\350\007\020\200\200\200\200\002\"]\n\013Enum" - "Options\022C\n\024uninterpreted_option\030\347\007 \003(\0132$" - ".google.protobuf.UninterpretedOption*\t\010\350" - "\007\020\200\200\200\200\002\"b\n\020EnumValueOptions\022C\n\024uninterpr" - "eted_option\030\347\007 \003(\0132$.google.protobuf.Uni" - "nterpretedOption*\t\010\350\007\020\200\200\200\200\002\"`\n\016ServiceOp" - "tions\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.g" - "oogle.protobuf.UninterpretedOption*\t\010\350\007\020" - "\200\200\200\200\002\"_\n\rMethodOptions\022C\n\024uninterpreted_" - "option\030\347\007 \003(\0132$.google.protobuf.Uninterp" - "retedOption*\t\010\350\007\020\200\200\200\200\002\"\205\002\n\023Uninterpreted" - "Option\022;\n\004name\030\002 \003(\0132-.google.protobuf.U" - "ninterpretedOption.NamePart\022\030\n\020identifie" - "r_value\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(" - "\004\022\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_" - "value\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\0323\n\010Nam" - "ePart\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_extension" - "\030\002 \002(\010B)\n\023com.google.protobufB\020Descripto" - "rProtosH\001", 3449, + "CType\022\016\n\006packed\030\002 \001(\010\022\034\n\024experimental_ma" + "p_key\030\t \001(\t\022C\n\024uninterpreted_option\030\347\007 \003" + "(\0132$.google.protobuf.UninterpretedOption" + "\"#\n\005CType\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002*\t\010" + "\350\007\020\200\200\200\200\002\"]\n\013EnumOptions\022C\n\024uninterpreted" + "_option\030\347\007 \003(\0132$.google.protobuf.Uninter" + "pretedOption*\t\010\350\007\020\200\200\200\200\002\"b\n\020EnumValueOpti" + "ons\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo" + "gle.protobuf.UninterpretedOption*\t\010\350\007\020\200\200" + "\200\200\002\"`\n\016ServiceOptions\022C\n\024uninterpreted_o" + "ption\030\347\007 \003(\0132$.google.protobuf.Uninterpr" + "etedOption*\t\010\350\007\020\200\200\200\200\002\"_\n\rMethodOptions\022C" + "\n\024uninterpreted_option\030\347\007 \003(\0132$.google.p" + "rotobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\205" + "\002\n\023UninterpretedOption\022;\n\004name\030\002 \003(\0132-.g" + "oogle.protobuf.UninterpretedOption.NameP" + "art\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022positiv" + "e_int_value\030\004 \001(\004\022\032\n\022negative_int_value\030" + "\005 \001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014string_va" + "lue\030\007 \001(\014\0323\n\010NamePart\022\021\n\tname_part\030\001 \002(\t" + "\022\024\n\014is_extension\030\002 \002(\010B)\n\023com.google.pro" + "tobufB\020DescriptorProtosH\001", 3465, &protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors); } @@ -639,7 +640,7 @@ bool FileDescriptorSet::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { #define DO_(EXPRESSION) if (!(EXPRESSION)) return false // repeated .google.protobuf.FileDescriptorProto file = 1; - for (int i = 0; i < file_.size(); i++) { + for (int i = 0; i < this->file_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(1, this->file(i), output)); } @@ -655,8 +656,8 @@ int FileDescriptorSet::ByteSize() const { int total_size = 0; // repeated .google.protobuf.FileDescriptorProto file = 1; - total_size += 1 * file_size(); - for (int i = 0; i < file_size(); i++) { + total_size += 1 * this->file_size(); + for (int i = 0; i < this->file_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->file(i)); @@ -954,27 +955,27 @@ bool FileDescriptorProto::SerializeWithCachedSizes( } // repeated string dependency = 3; - for (int i = 0; i < dependency_.size(); i++) { + for (int i = 0; i < this->dependency_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteString(3, this->dependency(i), output)); } // repeated .google.protobuf.DescriptorProto message_type = 4; - for (int i = 0; i < message_type_.size(); i++) { + for (int i = 0; i < this->message_type_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->message_type(i), output)); } // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; - for (int i = 0; i < enum_type_.size(); i++) { + for (int i = 0; i < this->enum_type_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(5, this->enum_type(i), output)); } // repeated .google.protobuf.ServiceDescriptorProto service = 6; - for (int i = 0; i < service_.size(); i++) { + for (int i = 0; i < this->service_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(6, this->service(i), output)); } // repeated .google.protobuf.FieldDescriptorProto extension = 7; - for (int i = 0; i < extension_.size(); i++) { + for (int i = 0; i < this->extension_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(7, this->extension(i), output)); } @@ -1016,39 +1017,39 @@ int FileDescriptorProto::ByteSize() const { } // repeated string dependency = 3; - total_size += 1 * dependency_size(); - for (int i = 0; i < dependency_size(); i++) { + total_size += 1 * this->dependency_size(); + for (int i = 0; i < this->dependency_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::StringSize( this->dependency(i)); } // repeated .google.protobuf.DescriptorProto message_type = 4; - total_size += 1 * message_type_size(); - for (int i = 0; i < message_type_size(); i++) { + total_size += 1 * this->message_type_size(); + for (int i = 0; i < this->message_type_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->message_type(i)); } // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; - total_size += 1 * enum_type_size(); - for (int i = 0; i < enum_type_size(); i++) { + total_size += 1 * this->enum_type_size(); + for (int i = 0; i < this->enum_type_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->enum_type(i)); } // repeated .google.protobuf.ServiceDescriptorProto service = 6; - total_size += 1 * service_size(); - for (int i = 0; i < service_size(); i++) { + total_size += 1 * this->service_size(); + for (int i = 0; i < this->service_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->service(i)); } // repeated .google.protobuf.FieldDescriptorProto extension = 7; - total_size += 1 * extension_size(); - for (int i = 0; i < extension_size(); i++) { + total_size += 1 * this->extension_size(); + for (int i = 0; i < this->extension_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->extension(i)); @@ -1564,27 +1565,27 @@ bool DescriptorProto::SerializeWithCachedSizes( } // repeated .google.protobuf.FieldDescriptorProto field = 2; - for (int i = 0; i < field_.size(); i++) { + for (int i = 0; i < this->field_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->field(i), output)); } // repeated .google.protobuf.DescriptorProto nested_type = 3; - for (int i = 0; i < nested_type_.size(); i++) { + for (int i = 0; i < this->nested_type_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->nested_type(i), output)); } // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; - for (int i = 0; i < enum_type_.size(); i++) { + for (int i = 0; i < this->enum_type_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->enum_type(i), output)); } // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; - for (int i = 0; i < extension_range_.size(); i++) { + for (int i = 0; i < this->extension_range_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(5, this->extension_range(i), output)); } // repeated .google.protobuf.FieldDescriptorProto extension = 6; - for (int i = 0; i < extension_.size(); i++) { + for (int i = 0; i < this->extension_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(6, this->extension(i), output)); } @@ -1620,40 +1621,40 @@ int DescriptorProto::ByteSize() const { } // repeated .google.protobuf.FieldDescriptorProto field = 2; - total_size += 1 * field_size(); - for (int i = 0; i < field_size(); i++) { + total_size += 1 * this->field_size(); + for (int i = 0; i < this->field_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->field(i)); } // repeated .google.protobuf.FieldDescriptorProto extension = 6; - total_size += 1 * extension_size(); - for (int i = 0; i < extension_size(); i++) { + total_size += 1 * this->extension_size(); + for (int i = 0; i < this->extension_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->extension(i)); } // repeated .google.protobuf.DescriptorProto nested_type = 3; - total_size += 1 * nested_type_size(); - for (int i = 0; i < nested_type_size(); i++) { + total_size += 1 * this->nested_type_size(); + for (int i = 0; i < this->nested_type_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->nested_type(i)); } // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; - total_size += 1 * enum_type_size(); - for (int i = 0; i < enum_type_size(); i++) { + total_size += 1 * this->enum_type_size(); + for (int i = 0; i < this->enum_type_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->enum_type(i)); } // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; - total_size += 1 * extension_range_size(); - for (int i = 0; i < extension_range_size(); i++) { + total_size += 1 * this->extension_range_size(); + for (int i = 0; i < this->extension_range_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->extension_range(i)); @@ -2407,7 +2408,7 @@ bool EnumDescriptorProto::SerializeWithCachedSizes( } // repeated .google.protobuf.EnumValueDescriptorProto value = 2; - for (int i = 0; i < value_.size(); i++) { + for (int i = 0; i < this->value_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->value(i), output)); } @@ -2443,8 +2444,8 @@ int EnumDescriptorProto::ByteSize() const { } // repeated .google.protobuf.EnumValueDescriptorProto value = 2; - total_size += 1 * value_size(); - for (int i = 0; i < value_size(); i++) { + total_size += 1 * this->value_size(); + for (int i = 0; i < this->value_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->value(i)); @@ -2919,7 +2920,7 @@ bool ServiceDescriptorProto::SerializeWithCachedSizes( } // repeated .google.protobuf.MethodDescriptorProto method = 2; - for (int i = 0; i < method_.size(); i++) { + for (int i = 0; i < this->method_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->method(i), output)); } @@ -2955,8 +2956,8 @@ int ServiceDescriptorProto::ByteSize() const { } // repeated .google.protobuf.MethodDescriptorProto method = 2; - total_size += 1 * method_size(); - for (int i = 0; i < method_size(); i++) { + total_size += 1 * this->method_size(); + for (int i = 0; i < this->method_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->method(i)); @@ -3561,7 +3562,7 @@ bool FileOptions::SerializeWithCachedSizes( } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - for (int i = 0; i < uninterpreted_option_.size(); i++) { + for (int i = 0; i < this->uninterpreted_option_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); } @@ -3606,8 +3607,8 @@ int FileOptions::ByteSize() const { } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - total_size += 2 * uninterpreted_option_size(); - for (int i = 0; i < uninterpreted_option_size(); i++) { + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->uninterpreted_option(i)); @@ -3821,7 +3822,7 @@ bool MessageOptions::SerializeWithCachedSizes( } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - for (int i = 0; i < uninterpreted_option_.size(); i++) { + for (int i = 0; i < this->uninterpreted_option_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); } @@ -3848,8 +3849,8 @@ int MessageOptions::ByteSize() const { } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - total_size += 2 * uninterpreted_option_size(); - for (int i = 0; i < uninterpreted_option_size(); i++) { + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->uninterpreted_option(i)); @@ -3954,6 +3955,7 @@ const FieldOptions_CType FieldOptions::CType_MIN; const FieldOptions_CType FieldOptions::CType_MAX; #endif // _MSC_VER + const ::std::string FieldOptions::_default_experimental_map_key_; FieldOptions::FieldOptions() @@ -3963,6 +3965,7 @@ FieldOptions::FieldOptions() ::google::protobuf::MessageFactory::generated_factory()), _cached_size_(0), ctype_(1), + packed_(false), experimental_map_key_(const_cast< ::std::string*>(&_default_experimental_map_key_)) { ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -3976,6 +3979,7 @@ FieldOptions::FieldOptions(const FieldOptions& from) ::google::protobuf::MessageFactory::generated_factory()), _cached_size_(0), ctype_(1), + packed_(false), experimental_map_key_(const_cast< ::std::string*>(&_default_experimental_map_key_)) { ::memset(_has_bits_, 0, sizeof(_has_bits_)); MergeFrom(from); @@ -4009,7 +4013,8 @@ void FieldOptions::Clear() { _extensions_.Clear(); if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { ctype_ = 1; - if (_has_bit(1)) { + packed_ = false; + if (_has_bit(2)) { if (experimental_map_key_ != &_default_experimental_map_key_) { experimental_map_key_->clear(); } @@ -4039,6 +4044,20 @@ bool FieldOptions::MergePartialFromCodedStream( } else { mutable_unknown_fields()->AddField(1)->add_varint(value); } + if (input->ExpectTag(16)) goto parse_packed; + break; + } + + // optional bool packed = 2; + case 2: { + if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) != + ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) { + goto handle_uninterpreted; + } + parse_packed: + DO_(::google::protobuf::internal::WireFormat::ReadBool( + input, &packed_)); + _set_bit(1); if (input->ExpectTag(74)) goto parse_experimental_map_key; break; } @@ -4097,13 +4116,18 @@ bool FieldOptions::SerializeWithCachedSizes( DO_(::google::protobuf::internal::WireFormat::WriteEnum(1, this->ctype(), output)); } - // optional string experimental_map_key = 9; + // optional bool packed = 2; if (_has_bit(1)) { + DO_(::google::protobuf::internal::WireFormat::WriteBool(2, this->packed(), output)); + } + + // optional string experimental_map_key = 9; + if (_has_bit(2)) { DO_(::google::protobuf::internal::WireFormat::WriteString(9, this->experimental_map_key(), output)); } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - for (int i = 0; i < uninterpreted_option_.size(); i++) { + for (int i = 0; i < this->uninterpreted_option_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); } @@ -4129,6 +4153,11 @@ int FieldOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::EnumSize(this->ctype()); } + // optional bool packed = 2; + if (has_packed()) { + total_size += 1 + 1; + } + // optional string experimental_map_key = 9; if (has_experimental_map_key()) { total_size += 1 + @@ -4137,8 +4166,8 @@ int FieldOptions::ByteSize() const { } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - total_size += 2 * uninterpreted_option_size(); - for (int i = 0; i < uninterpreted_option_size(); i++) { + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->uninterpreted_option(i)); @@ -4175,6 +4204,9 @@ void FieldOptions::MergeFrom(const FieldOptions& from) { set_ctype(from.ctype()); } if (from._has_bit(1)) { + set_packed(from.packed()); + } + if (from._has_bit(2)) { set_experimental_map_key(from.experimental_map_key()); } } @@ -4197,6 +4229,7 @@ void FieldOptions::CopyFrom(const FieldOptions& from) { void FieldOptions::Swap(FieldOptions* other) { if (other != this) { std::swap(ctype_, other->ctype_); + std::swap(packed_, other->packed_); std::swap(experimental_map_key_, other->experimental_map_key_); uninterpreted_option_.Swap(&other->uninterpreted_option_); std::swap(_has_bits_[0], other->_has_bits_[0]); @@ -4320,7 +4353,7 @@ bool EnumOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { #define DO_(EXPRESSION) if (!(EXPRESSION)) return false // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - for (int i = 0; i < uninterpreted_option_.size(); i++) { + for (int i = 0; i < this->uninterpreted_option_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); } @@ -4340,8 +4373,8 @@ int EnumOptions::ByteSize() const { int total_size = 0; // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - total_size += 2 * uninterpreted_option_size(); - for (int i = 0; i < uninterpreted_option_size(); i++) { + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->uninterpreted_option(i)); @@ -4513,7 +4546,7 @@ bool EnumValueOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { #define DO_(EXPRESSION) if (!(EXPRESSION)) return false // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - for (int i = 0; i < uninterpreted_option_.size(); i++) { + for (int i = 0; i < this->uninterpreted_option_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); } @@ -4533,8 +4566,8 @@ int EnumValueOptions::ByteSize() const { int total_size = 0; // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - total_size += 2 * uninterpreted_option_size(); - for (int i = 0; i < uninterpreted_option_size(); i++) { + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->uninterpreted_option(i)); @@ -4706,7 +4739,7 @@ bool ServiceOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { #define DO_(EXPRESSION) if (!(EXPRESSION)) return false // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - for (int i = 0; i < uninterpreted_option_.size(); i++) { + for (int i = 0; i < this->uninterpreted_option_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); } @@ -4726,8 +4759,8 @@ int ServiceOptions::ByteSize() const { int total_size = 0; // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - total_size += 2 * uninterpreted_option_size(); - for (int i = 0; i < uninterpreted_option_size(); i++) { + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->uninterpreted_option(i)); @@ -4899,7 +4932,7 @@ bool MethodOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { #define DO_(EXPRESSION) if (!(EXPRESSION)) return false // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - for (int i = 0; i < uninterpreted_option_.size(); i++) { + for (int i = 0; i < this->uninterpreted_option_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); } @@ -4919,8 +4952,8 @@ int MethodOptions::ByteSize() const { int total_size = 0; // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - total_size += 2 * uninterpreted_option_size(); - for (int i = 0; i < uninterpreted_option_size(); i++) { + total_size += 2 * this->uninterpreted_option_size(); + for (int i = 0; i < this->uninterpreted_option_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->uninterpreted_option(i)); @@ -5398,7 +5431,7 @@ bool UninterpretedOption::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { #define DO_(EXPRESSION) if (!(EXPRESSION)) return false // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; - for (int i = 0; i < name_.size(); i++) { + for (int i = 0; i < this->name_size(); i++) { DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->name(i), output)); } @@ -5472,8 +5505,8 @@ int UninterpretedOption::ByteSize() const { } // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; - total_size += 1 * name_size(); - for (int i = 0; i < name_size(); i++) { + total_size += 1 * this->name_size(); + for (int i = 0; i < this->name_size(); i++) { total_size += ::google::protobuf::internal::WireFormat::MessageSizeNoVirtual( this->name(i)); diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 8fa51dd6..e5077aae 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -12,7 +12,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 2000003 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION +#if 2000004 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. @@ -1645,6 +1645,12 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { inline ::google::protobuf::FieldOptions_CType ctype() const; inline void set_ctype(::google::protobuf::FieldOptions_CType value); + // optional bool packed = 2; + inline bool has_packed() const; + inline void clear_packed(); + inline bool packed() const; + inline void set_packed(bool value); + // optional string experimental_map_key = 9; inline bool has_experimental_map_key() const; inline void clear_experimental_map_key(); @@ -1749,12 +1755,13 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { mutable int _cached_size_; int ctype_; + bool packed_; ::std::string* experimental_map_key_; static const ::std::string _default_experimental_map_key_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( const ::google::protobuf::FileDescriptor* file); - ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? inline bool _has_bit(int index) const { @@ -3908,35 +3915,51 @@ inline void FieldOptions::set_ctype(::google::protobuf::FieldOptions_CType value ctype_ = value; } +// optional bool packed = 2; +inline bool FieldOptions::has_packed() const { + return _has_bit(1); +} +inline void FieldOptions::clear_packed() { + packed_ = false; + _clear_bit(1); +} +inline bool FieldOptions::packed() const { + return packed_; +} +inline void FieldOptions::set_packed(bool value) { + _set_bit(1); + packed_ = value; +} + // optional string experimental_map_key = 9; inline bool FieldOptions::has_experimental_map_key() const { - return _has_bit(1); + return _has_bit(2); } inline void FieldOptions::clear_experimental_map_key() { if (experimental_map_key_ != &_default_experimental_map_key_) { experimental_map_key_->clear(); } - _clear_bit(1); + _clear_bit(2); } inline const ::std::string& FieldOptions::experimental_map_key() const { return *experimental_map_key_; } inline void FieldOptions::set_experimental_map_key(const ::std::string& value) { - _set_bit(1); + _set_bit(2); if (experimental_map_key_ == &_default_experimental_map_key_) { experimental_map_key_ = new ::std::string; } experimental_map_key_->assign(value); } inline void FieldOptions::set_experimental_map_key(const char* value) { - _set_bit(1); + _set_bit(2); if (experimental_map_key_ == &_default_experimental_map_key_) { experimental_map_key_ = new ::std::string; } experimental_map_key_->assign(value); } inline ::std::string* FieldOptions::mutable_experimental_map_key() { - _set_bit(1); + _set_bit(2); if (experimental_map_key_ == &_default_experimental_map_key_) { experimental_map_key_ = new ::std::string; } diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 9cdd61c5..e0e6f7f2 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -253,6 +253,7 @@ message FileOptions { optional OptimizeMode optimize_for = 9 [default=CODE_SIZE]; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -299,6 +300,11 @@ message FieldOptions { STRING_PIECE = 2; } + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. + optional bool packed = 2; // EXPERIMENTAL. DO NOT USE. // For "map" fields, the name of the field in the enclosed type that diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index f4e60b3a..5ffaea77 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -53,7 +53,8 @@ namespace google { namespace protobuf { -namespace GOOGLE_ANONYMOUS_NAMESPACE{ +// Can't use an anonymous namespace here due to brokenness of Tru64 compiler. +namespace descriptor_unittest { // Some helpers to make assembling descriptors faster. DescriptorProto* AddMessage(FileDescriptorProto* file, const string& name) { @@ -631,6 +632,188 @@ TEST_F(DescriptorTest, FieldEnumType) { // =================================================================== +class StylizedFieldNamesTest : public testing::Test { + protected: + void SetUp() { + FileDescriptorProto file; + file.set_name("foo.proto"); + + AddExtensionRange(AddMessage(&file, "ExtendableMessage"), 1, 1000); + + DescriptorProto* message = AddMessage(&file, "TestMessage"); + AddField(message, "foo_foo", 1, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddField(message, "FooBar", 2, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddField(message, "fooBaz", 3, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddField(message, "fooFoo", 4, // Camel-case conflict with foo_foo. + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddField(message, "foobar", 5, // Lower-case conflict with FooBar. + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + + AddNestedExtension(message, "ExtendableMessage", "bar_foo", 1, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddNestedExtension(message, "ExtendableMessage", "BarBar", 2, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddNestedExtension(message, "ExtendableMessage", "BarBaz", 3, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddNestedExtension(message, "ExtendableMessage", "barFoo", 4, // Conflict + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddNestedExtension(message, "ExtendableMessage", "barbar", 5, // Conflict + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + + AddExtension(&file, "ExtendableMessage", "baz_foo", 11, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddExtension(&file, "ExtendableMessage", "BazBar", 12, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddExtension(&file, "ExtendableMessage", "BazBaz", 13, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddExtension(&file, "ExtendableMessage", "bazFoo", 14, // Conflict + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + AddExtension(&file, "ExtendableMessage", "bazbar", 15, // Conflict + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + + file_ = pool_.BuildFile(file); + ASSERT_TRUE(file_ != NULL); + ASSERT_EQ(2, file_->message_type_count()); + message_ = file_->message_type(1); + ASSERT_EQ("TestMessage", message_->name()); + ASSERT_EQ(5, message_->field_count()); + ASSERT_EQ(5, message_->extension_count()); + ASSERT_EQ(5, file_->extension_count()); + } + + DescriptorPool pool_; + const FileDescriptor* file_; + const Descriptor* message_; +}; + +TEST_F(StylizedFieldNamesTest, LowercaseName) { + EXPECT_EQ("foo_foo", message_->field(0)->lowercase_name()); + EXPECT_EQ("foobar" , message_->field(1)->lowercase_name()); + EXPECT_EQ("foobaz" , message_->field(2)->lowercase_name()); + EXPECT_EQ("foofoo" , message_->field(3)->lowercase_name()); + EXPECT_EQ("foobar" , message_->field(4)->lowercase_name()); + + EXPECT_EQ("bar_foo", message_->extension(0)->lowercase_name()); + EXPECT_EQ("barbar" , message_->extension(1)->lowercase_name()); + EXPECT_EQ("barbaz" , message_->extension(2)->lowercase_name()); + EXPECT_EQ("barfoo" , message_->extension(3)->lowercase_name()); + EXPECT_EQ("barbar" , message_->extension(4)->lowercase_name()); + + EXPECT_EQ("baz_foo", file_->extension(0)->lowercase_name()); + EXPECT_EQ("bazbar" , file_->extension(1)->lowercase_name()); + EXPECT_EQ("bazbaz" , file_->extension(2)->lowercase_name()); + EXPECT_EQ("bazfoo" , file_->extension(3)->lowercase_name()); + EXPECT_EQ("bazbar" , file_->extension(4)->lowercase_name()); +} + +TEST_F(StylizedFieldNamesTest, CamelcaseName) { + EXPECT_EQ("fooFoo", message_->field(0)->camelcase_name()); + EXPECT_EQ("fooBar", message_->field(1)->camelcase_name()); + EXPECT_EQ("fooBaz", message_->field(2)->camelcase_name()); + EXPECT_EQ("fooFoo", message_->field(3)->camelcase_name()); + EXPECT_EQ("foobar", message_->field(4)->camelcase_name()); + + EXPECT_EQ("barFoo", message_->extension(0)->camelcase_name()); + EXPECT_EQ("barBar", message_->extension(1)->camelcase_name()); + EXPECT_EQ("barBaz", message_->extension(2)->camelcase_name()); + EXPECT_EQ("barFoo", message_->extension(3)->camelcase_name()); + EXPECT_EQ("barbar", message_->extension(4)->camelcase_name()); + + EXPECT_EQ("bazFoo", file_->extension(0)->camelcase_name()); + EXPECT_EQ("bazBar", file_->extension(1)->camelcase_name()); + EXPECT_EQ("bazBaz", file_->extension(2)->camelcase_name()); + EXPECT_EQ("bazFoo", file_->extension(3)->camelcase_name()); + EXPECT_EQ("bazbar", file_->extension(4)->camelcase_name()); +} + +TEST_F(StylizedFieldNamesTest, FindByLowercaseName) { + EXPECT_EQ(message_->field(0), + message_->FindFieldByLowercaseName("foo_foo")); + EXPECT_EQ(message_->field(1), + message_->FindFieldByLowercaseName("foobar")); + EXPECT_EQ(message_->field(2), + message_->FindFieldByLowercaseName("foobaz")); + EXPECT_TRUE(message_->FindFieldByLowercaseName("FooBar") == NULL); + EXPECT_TRUE(message_->FindFieldByLowercaseName("fooBaz") == NULL); + EXPECT_TRUE(message_->FindFieldByLowercaseName("bar_foo") == NULL); + EXPECT_TRUE(message_->FindFieldByLowercaseName("nosuchfield") == NULL); + + EXPECT_EQ(message_->extension(0), + message_->FindExtensionByLowercaseName("bar_foo")); + EXPECT_EQ(message_->extension(1), + message_->FindExtensionByLowercaseName("barbar")); + EXPECT_EQ(message_->extension(2), + message_->FindExtensionByLowercaseName("barbaz")); + EXPECT_TRUE(message_->FindExtensionByLowercaseName("BarBar") == NULL); + EXPECT_TRUE(message_->FindExtensionByLowercaseName("barBaz") == NULL); + EXPECT_TRUE(message_->FindExtensionByLowercaseName("foo_foo") == NULL); + EXPECT_TRUE(message_->FindExtensionByLowercaseName("nosuchfield") == NULL); + + EXPECT_EQ(file_->extension(0), + file_->FindExtensionByLowercaseName("baz_foo")); + EXPECT_EQ(file_->extension(1), + file_->FindExtensionByLowercaseName("bazbar")); + EXPECT_EQ(file_->extension(2), + file_->FindExtensionByLowercaseName("bazbaz")); + EXPECT_TRUE(file_->FindExtensionByLowercaseName("BazBar") == NULL); + EXPECT_TRUE(file_->FindExtensionByLowercaseName("bazBaz") == NULL); + EXPECT_TRUE(file_->FindExtensionByLowercaseName("nosuchfield") == NULL); +} + +TEST_F(StylizedFieldNamesTest, FindByCamelcaseName) { + EXPECT_EQ(message_->field(0), + message_->FindFieldByCamelcaseName("fooFoo")); + EXPECT_EQ(message_->field(1), + message_->FindFieldByCamelcaseName("fooBar")); + EXPECT_EQ(message_->field(2), + message_->FindFieldByCamelcaseName("fooBaz")); + EXPECT_TRUE(message_->FindFieldByCamelcaseName("foo_foo") == NULL); + EXPECT_TRUE(message_->FindFieldByCamelcaseName("FooBar") == NULL); + EXPECT_TRUE(message_->FindFieldByCamelcaseName("barFoo") == NULL); + EXPECT_TRUE(message_->FindFieldByCamelcaseName("nosuchfield") == NULL); + + EXPECT_EQ(message_->extension(0), + message_->FindExtensionByCamelcaseName("barFoo")); + EXPECT_EQ(message_->extension(1), + message_->FindExtensionByCamelcaseName("barBar")); + EXPECT_EQ(message_->extension(2), + message_->FindExtensionByCamelcaseName("barBaz")); + EXPECT_TRUE(message_->FindExtensionByCamelcaseName("bar_foo") == NULL); + EXPECT_TRUE(message_->FindExtensionByCamelcaseName("BarBar") == NULL); + EXPECT_TRUE(message_->FindExtensionByCamelcaseName("fooFoo") == NULL); + EXPECT_TRUE(message_->FindExtensionByCamelcaseName("nosuchfield") == NULL); + + EXPECT_EQ(file_->extension(0), + file_->FindExtensionByCamelcaseName("bazFoo")); + EXPECT_EQ(file_->extension(1), + file_->FindExtensionByCamelcaseName("bazBar")); + EXPECT_EQ(file_->extension(2), + file_->FindExtensionByCamelcaseName("bazBaz")); + EXPECT_TRUE(file_->FindExtensionByCamelcaseName("baz_foo") == NULL); + EXPECT_TRUE(file_->FindExtensionByCamelcaseName("BazBar") == NULL); + EXPECT_TRUE(file_->FindExtensionByCamelcaseName("nosuchfield") == NULL); +} + +// =================================================================== + // Test enum descriptors. class EnumDescriptorTest : public testing::Test { protected: @@ -2457,6 +2640,36 @@ TEST_F(ValidationErrorTest, OutputTypeNotAMessage) { "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n"); } +TEST_F(ValidationErrorTest, IllegalPackedField) { + BuildFileWithErrors( + "name: \"foo.proto\" " + "message_type {\n" + " name: \"Foo\"" + " field { name:\"packed_string\" number:1 label:LABEL_REPEATED " + " type:TYPE_STRING " + " options { uninterpreted_option {" + " name { name_part: \"packed\" is_extension: false }" + " identifier_value: \"true\" }}}\n" + " field { name:\"packed_message\" number:3 label:LABEL_REPEATED " + " type_name: \"Foo\"" + " options { uninterpreted_option {" + " name { name_part: \"packed\" is_extension: false }" + " identifier_value: \"true\" }}}\n" + " field { name:\"optional_int32\" number: 4 label: LABEL_OPTIONAL " + " type:TYPE_INT32 " + " options { uninterpreted_option {" + " name { name_part: \"packed\" is_extension: false }" + " identifier_value: \"true\" }}}\n" + "}", + + "foo.proto: Foo.packed_string: TYPE: [packed = true] can only be " + "specified for repeated primitive fields.\n" + "foo.proto: Foo.packed_message: TYPE: [packed = true] can only be " + "specified for repeated primitive fields.\n" + "foo.proto: Foo.optional_int32: TYPE: [packed = true] can only be " + "specified for repeated primitive fields.\n" + ); +} TEST_F(ValidationErrorTest, OptionWrongType) { BuildFileWithErrors( @@ -3255,6 +3468,34 @@ TEST_F(DatabaseBackedPoolTest, DoesntReloadKnownBadFiles) { EXPECT_EQ("", error_collector.text_); } -} // anonymous namespace +TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) { + // If a lookup finds a symbol of the wrong type (e.g. we pass a type name + // to FindFieldByName()), we should fail fast, without checking the fallback + // database. + CallCountingDatabase call_counter(&database_); + DescriptorPool pool(&call_counter); + + const FileDescriptor* file = pool.FindFileByName("foo.proto"); + ASSERT_TRUE(file != NULL); + const Descriptor* foo = pool.FindMessageTypeByName("Foo"); + ASSERT_TRUE(foo != NULL); + const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum"); + ASSERT_TRUE(test_enum != NULL); + + EXPECT_NE(0, call_counter.call_count_); + call_counter.Clear(); + + EXPECT_TRUE(pool.FindMessageTypeByName("TestEnum") == NULL); + EXPECT_TRUE(pool.FindFieldByName("Foo") == NULL); + EXPECT_TRUE(pool.FindExtensionByName("Foo") == NULL); + EXPECT_TRUE(pool.FindEnumTypeByName("Foo") == NULL); + EXPECT_TRUE(pool.FindEnumValueByName("Foo") == NULL); + EXPECT_TRUE(pool.FindServiceByName("Foo") == NULL); + EXPECT_TRUE(pool.FindMethodByName("Foo") == NULL); + + EXPECT_EQ(0, call_counter.call_count_); +} + +} // namespace descriptor_unittest } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc index 5f7af94e..41b89ab5 100644 --- a/src/google/protobuf/dynamic_message_unittest.cc +++ b/src/google/protobuf/dynamic_message_unittest.cc @@ -61,6 +61,8 @@ class DynamicMessageTest : public testing::Test { const Message* prototype_; const Descriptor* extensions_descriptor_; const Message* extensions_prototype_; + const Descriptor* packed_descriptor_; + const Message* packed_prototype_; DynamicMessageTest(): factory_(&pool_) {} @@ -87,6 +89,11 @@ class DynamicMessageTest : public testing::Test { pool_.FindMessageTypeByName("protobuf_unittest.TestAllExtensions"); ASSERT_TRUE(extensions_descriptor_ != NULL); extensions_prototype_ = factory_.GetPrototype(extensions_descriptor_); + + packed_descriptor_ = + pool_.FindMessageTypeByName("protobuf_unittest.TestPackedTypes"); + ASSERT_TRUE(packed_descriptor_ != NULL); + packed_prototype_ = factory_.GetPrototype(packed_descriptor_); } }; @@ -127,6 +134,15 @@ TEST_F(DynamicMessageTest, Extensions) { reflection_tester.ExpectAllFieldsSetViaReflection(*message); } +TEST_F(DynamicMessageTest, PackedFields) { + // Check that packed fields work properly. + scoped_ptr<Message> message(packed_prototype_->New()); + TestUtil::ReflectionTester reflection_tester(packed_descriptor_); + + reflection_tester.SetPackedFieldsViaReflection(message.get()); + reflection_tester.ExpectPackedFieldsSetViaReflection(*message); +} + TEST_F(DynamicMessageTest, SpaceUsed) { // Test that SpaceUsed() works properly diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc index c3ac7ce7..631bbc43 100644 --- a/src/google/protobuf/extension_set_unittest.cc +++ b/src/google/protobuf/extension_set_unittest.cc @@ -179,6 +179,19 @@ TEST(ExtensionSetTest, Serialization) { TestUtil::ExpectAllFieldsSet(destination); } +TEST(ExtensionSetTest, PackedSerialization) { + // Serialize as TestPackedExtensions and parse as TestPackedTypes to insure + // wire compatibility of extensions. + unittest::TestPackedExtensions source; + unittest::TestPackedTypes destination; + string data; + + TestUtil::SetPackedExtensions(&source); + source.SerializeToString(&data); + EXPECT_TRUE(destination.ParseFromString(data)); + TestUtil::ExpectPackedFieldsSet(destination); +} + TEST(ExtensionSetTest, Parsing) { // Serialize as TestAllTypes and parse as TestAllExtensions. unittest::TestAllTypes source; @@ -191,6 +204,18 @@ TEST(ExtensionSetTest, Parsing) { TestUtil::ExpectAllExtensionsSet(destination); } +TEST(ExtensionSetTest, PackedParsing) { + // Serialize as TestPackedTypes and parse as TestPackedExtensions. + unittest::TestPackedTypes source; + unittest::TestPackedExtensions destination; + string data; + + TestUtil::SetPackedFields(&source); + source.SerializeToString(&data); + EXPECT_TRUE(destination.ParseFromString(data)); + TestUtil::ExpectPackedExtensionsSet(destination); +} + TEST(ExtensionSetTest, IsInitialized) { // Test that IsInitialized() returns false if required fields in nested // extensions are missing. diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index 66f95906..a0f08571 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -207,6 +207,14 @@ bool CodedInputStream::Skip(int count) { return input_->Skip(count); } +bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) { + if (buffer_size_ == 0 && !Refresh()) return false; + + *data = buffer_; + *size = buffer_size_; + return true; +} + bool CodedInputStream::ReadRaw(void* buffer, int size) { while (buffer_size_ < size) { // Reading past end of buffer. Copy what we have, then refresh. @@ -515,6 +523,26 @@ CodedOutputStream::~CodedOutputStream() { } } +bool CodedOutputStream::Skip(int count) { + if (count < 0) return false; + + while (count > buffer_size_) { + count -= buffer_size_; + if (!Refresh()) return false; + } + + Advance(count); + return true; +} + +bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) { + if (buffer_size_ == 0 && !Refresh()) return false; + + *data = buffer_; + *size = buffer_size_; + return true; +} + bool CodedOutputStream::WriteRaw(const void* data, int size) { while (buffer_size_ < size) { memcpy(buffer_, data, buffer_size_); diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index a73ac0ba..8ebe4b35 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -149,6 +149,15 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // occurs. bool Skip(int count); + // Sets *data to point directly at the unread part of the CodedInputStream's + // underlying buffer, and *size to the size of that buffer, but does not + // advance the stream's current position. This will always either produce + // a non-empty buffer or return false. If the caller consumes any of + // this data, it should then call Skip() to skip over the consumed bytes. + // This may be useful for implementing external fast parsing routines for + // types of data not covered by the CodedInputStream interface. + bool GetDirectBufferPointer(const void** data, int* size); + // Read raw bytes, copying them into the given buffer. bool ReadRaw(void* buffer, int size); @@ -381,6 +390,21 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // ZeroCopyOutputStream immediately after the last byte written. ~CodedOutputStream(); + // Skips a number of bytes, leaving the bytes unmodified in the underlying + // buffer. Returns false if an underlying write error occurs. This is + // mainly useful with GetDirectBufferPointer(). + bool Skip(int count); + + // Sets *data to point directly at the unwritten part of the + // CodedOutputStream's underlying buffer, and *size to the size of that + // buffer, but does not advance the stream's current position. This will + // always either produce a non-empty buffer or return false. If the caller + // writes any data to this buffer, it should then call Skip() to skip over + // the consumed bytes. This may be useful for implementing external fast + // serialization routines for types of data not covered by the + // CodedOutputStream interface. + bool GetDirectBufferPointer(void** data, int* size); + // Write raw bytes, copying them from the given buffer. bool WriteRaw(const void* buffer, int size); @@ -518,7 +542,7 @@ inline bool CodedInputStream::ExpectAtEnd() { inline bool CodedOutputStream::WriteVarint32(uint32 value) { if (value < 0x80 && buffer_size_ > 0) { - *buffer_ = value; + *buffer_ = static_cast<uint8>(value); Advance(1); return true; } else { @@ -537,7 +561,7 @@ inline bool CodedOutputStream::WriteVarint32SignExtended(int32 value) { inline bool CodedOutputStream::WriteTag(uint32 value) { if (value < (1 << 7)) { if (buffer_size_ != 0) { - buffer_[0] = value; + buffer_[0] = static_cast<uint8>(value); Advance(1); return true; } diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index 459b94a6..6a6eafe9 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -77,6 +77,9 @@ namespace { // which failed will be printed. The case type must be printable using // ostream::operator<<. +// TODO(kenton): gTest now supports "parameterized tests" which would be +// a better way to accomplish this. Rewrite when time permits. + #define TEST_1D(FIXTURE, NAME, CASES) \ class FIXTURE##_##NAME##_DD : public FIXTURE { \ protected: \ @@ -614,6 +617,73 @@ TEST_1D(CodedStreamTest, SkipInput, kBlockSizes) { } // ------------------------------------------------------------------- +// GetDirectBufferPointer + +TEST_F(CodedStreamTest, GetDirectBufferPointerInput) { + ArrayInputStream input(buffer_, sizeof(buffer_), 8); + CodedInputStream coded_input(&input); + + const void* ptr; + int size; + + EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size)); + EXPECT_EQ(buffer_, ptr); + EXPECT_EQ(8, size); + + // Peeking again should return the same pointer. + EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size)); + EXPECT_EQ(buffer_, ptr); + EXPECT_EQ(8, size); + + // Skip forward in the same buffer then peek again. + EXPECT_TRUE(coded_input.Skip(3)); + EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size)); + EXPECT_EQ(buffer_ + 3, ptr); + EXPECT_EQ(5, size); + + // Skip to end of buffer and peek -- should get next buffer. + EXPECT_TRUE(coded_input.Skip(5)); + EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size)); + EXPECT_EQ(buffer_ + 8, ptr); + EXPECT_EQ(8, size); +} + +TEST_F(CodedStreamTest, GetDirectBufferPointerOutput) { + ArrayOutputStream output(buffer_, sizeof(buffer_), 8); + CodedOutputStream coded_output(&output); + + void* ptr; + int size; + + EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size)); + EXPECT_EQ(buffer_, ptr); + EXPECT_EQ(8, size); + + // Peeking again should return the same pointer. + EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size)); + EXPECT_EQ(buffer_, ptr); + EXPECT_EQ(8, size); + + // Skip forward in the same buffer then peek again. + EXPECT_TRUE(coded_output.Skip(3)); + EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size)); + EXPECT_EQ(buffer_ + 3, ptr); + EXPECT_EQ(5, size); + + // Skip to end of buffer and peek -- should get next buffer. + EXPECT_TRUE(coded_output.Skip(5)); + EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size)); + EXPECT_EQ(buffer_ + 8, ptr); + EXPECT_EQ(8, size); + + // Skip over multiple buffers. + EXPECT_TRUE(coded_output.Skip(22)); + EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size)); + EXPECT_EQ(buffer_ + 30, ptr); + EXPECT_EQ(2, size); +} + +// ------------------------------------------------------------------- // Limits TEST_1D(CodedStreamTest, BasicLimit, kBlockSizes) { diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index f6c932ff..097411cb 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -145,24 +145,42 @@ bool Message::ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input) { decoder.ConsumedEntireMessage(); } +bool Message::ParseFromBoundedZeroCopyStream( + io::ZeroCopyInputStream* input, int size) { + io::CodedInputStream decoder(input); + decoder.PushLimit(size); + return ParseFromCodedStream(&decoder) && + decoder.ConsumedEntireMessage() && + decoder.BytesUntilLimit() == 0; +} + +bool Message::ParsePartialFromBoundedZeroCopyStream( + io::ZeroCopyInputStream* input, int size) { + io::CodedInputStream decoder(input); + decoder.PushLimit(size); + return ParsePartialFromCodedStream(&decoder) && + decoder.ConsumedEntireMessage() && + decoder.BytesUntilLimit() == 0; +} + bool Message::ParseFromString(const string& data) { io::ArrayInputStream input(data.data(), data.size()); - return ParseFromZeroCopyStream(&input); + return ParseFromBoundedZeroCopyStream(&input, data.size()); } bool Message::ParsePartialFromString(const string& data) { io::ArrayInputStream input(data.data(), data.size()); - return ParsePartialFromZeroCopyStream(&input); + return ParsePartialFromBoundedZeroCopyStream(&input, data.size()); } bool Message::ParseFromArray(const void* data, int size) { io::ArrayInputStream input(data, size); - return ParseFromZeroCopyStream(&input); + return ParseFromBoundedZeroCopyStream(&input, size); } bool Message::ParsePartialFromArray(const void* data, int size) { io::ArrayInputStream input(data, size); - return ParsePartialFromZeroCopyStream(&input); + return ParsePartialFromBoundedZeroCopyStream(&input, size); } bool Message::ParseFromFileDescriptor(int file_descriptor) { diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index d96fcc60..0674a12c 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -232,6 +232,14 @@ class LIBPROTOBUF_EXPORT Message { // Like ParseFromZeroCopyStream(), but accepts messages that are missing // required fields. bool ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input); + // Read a protocol buffer from the given zero-copy input stream, expecting + // the message to be exactly "size" bytes long. If successful, exactly + // this many bytes will have been consumed from the input. + bool ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size); + // Like ParseFromBoundedZeroCopyStream(), but accepts messages that are + // missing required fields. + bool ParsePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, + int size); // Parse a protocol buffer contained in a string. bool ParseFromString(const string& data); // Like ParseFromString(), but accepts messages that are missing diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc index da99741b..46e68446 100644 --- a/src/google/protobuf/message_unittest.cc +++ b/src/google/protobuf/message_unittest.cc @@ -107,6 +107,19 @@ TEST(MessageTest, ParseFromFileDescriptor) { EXPECT_GE(close(file), 0); } +TEST(MessageTest, ParsePackedFromFileDescriptor) { + string filename = + TestSourceDir() + + "/google/protobuf/testdata/golden_packed_fields_message"; + int file = open(filename.c_str(), O_RDONLY | O_BINARY); + + unittest::TestPackedTypes message; + EXPECT_TRUE(message.ParseFromFileDescriptor(file)); + TestUtil::ExpectPackedFieldsSet(message); + + EXPECT_GE(close(file), 0); +} + TEST(MessageTest, ParseHelpers) { // TODO(kenton): Test more helpers? They're all two-liners so it seems // like a waste of time. @@ -134,6 +147,25 @@ TEST(MessageTest, ParseHelpers) { EXPECT_TRUE(stream.eof()); TestUtil::ExpectAllFieldsSet(message); } + + { + // Test ParseFromBoundedZeroCopyStream. + string data_with_junk(data); + data_with_junk.append("some junk on the end"); + io::ArrayInputStream stream(data_with_junk.data(), data_with_junk.size()); + protobuf_unittest::TestAllTypes message; + EXPECT_TRUE(message.ParseFromBoundedZeroCopyStream(&stream, data.size())); + TestUtil::ExpectAllFieldsSet(message); + } + + { + // Test that ParseFromBoundedZeroCopyStream fails (but doesn't crash) if + // EOF is reached before the expected number of bytes. + io::ArrayInputStream stream(data.data(), data.size()); + protobuf_unittest::TestAllTypes message; + EXPECT_FALSE( + message.ParseFromBoundedZeroCopyStream(&stream, data.size() + 1)); + } } TEST(MessageTest, ParseFailsIfNotInitialized) { diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc index 40120d95..c1e9fa78 100644 --- a/src/google/protobuf/test_util.cc +++ b/src/google/protobuf/test_util.cc @@ -636,6 +636,180 @@ void TestUtil::ExpectRepeatedFieldsModified( } +// ------------------------------------------------------------------- + +void TestUtil::SetPackedFields(unittest::TestPackedTypes* message) { + message->add_packed_int32 (601); + message->add_packed_int64 (602); + message->add_packed_uint32 (603); + message->add_packed_uint64 (604); + message->add_packed_sint32 (605); + message->add_packed_sint64 (606); + message->add_packed_fixed32 (607); + message->add_packed_fixed64 (608); + message->add_packed_sfixed32(609); + message->add_packed_sfixed64(610); + message->add_packed_float (611); + message->add_packed_double (612); + message->add_packed_bool (true); + message->add_packed_enum (unittest::FOREIGN_BAR); + // add a second one of each field + message->add_packed_int32 (701); + message->add_packed_int64 (702); + message->add_packed_uint32 (703); + message->add_packed_uint64 (704); + message->add_packed_sint32 (705); + message->add_packed_sint64 (706); + message->add_packed_fixed32 (707); + message->add_packed_fixed64 (708); + message->add_packed_sfixed32(709); + message->add_packed_sfixed64(710); + message->add_packed_float (711); + message->add_packed_double (712); + message->add_packed_bool (false); + message->add_packed_enum (unittest::FOREIGN_BAZ); +} + +// ------------------------------------------------------------------- + +void TestUtil::ModifyPackedFields(unittest::TestPackedTypes* message) { + message->set_packed_int32 (1, 801); + message->set_packed_int64 (1, 802); + message->set_packed_uint32 (1, 803); + message->set_packed_uint64 (1, 804); + message->set_packed_sint32 (1, 805); + message->set_packed_sint64 (1, 806); + message->set_packed_fixed32 (1, 807); + message->set_packed_fixed64 (1, 808); + message->set_packed_sfixed32(1, 809); + message->set_packed_sfixed64(1, 810); + message->set_packed_float (1, 811); + message->set_packed_double (1, 812); + message->set_packed_bool (1, true); + message->set_packed_enum (1, unittest::FOREIGN_FOO); +} + +// ------------------------------------------------------------------- + +void TestUtil::ExpectPackedFieldsSet(const unittest::TestPackedTypes& message) { + ASSERT_EQ(2, message.packed_int32_size ()); + ASSERT_EQ(2, message.packed_int64_size ()); + ASSERT_EQ(2, message.packed_uint32_size ()); + ASSERT_EQ(2, message.packed_uint64_size ()); + ASSERT_EQ(2, message.packed_sint32_size ()); + ASSERT_EQ(2, message.packed_sint64_size ()); + ASSERT_EQ(2, message.packed_fixed32_size ()); + ASSERT_EQ(2, message.packed_fixed64_size ()); + ASSERT_EQ(2, message.packed_sfixed32_size()); + ASSERT_EQ(2, message.packed_sfixed64_size()); + ASSERT_EQ(2, message.packed_float_size ()); + ASSERT_EQ(2, message.packed_double_size ()); + ASSERT_EQ(2, message.packed_bool_size ()); + ASSERT_EQ(2, message.packed_enum_size ()); + + EXPECT_EQ(601 , message.packed_int32 (0)); + EXPECT_EQ(602 , message.packed_int64 (0)); + EXPECT_EQ(603 , message.packed_uint32 (0)); + EXPECT_EQ(604 , message.packed_uint64 (0)); + EXPECT_EQ(605 , message.packed_sint32 (0)); + EXPECT_EQ(606 , message.packed_sint64 (0)); + EXPECT_EQ(607 , message.packed_fixed32 (0)); + EXPECT_EQ(608 , message.packed_fixed64 (0)); + EXPECT_EQ(609 , message.packed_sfixed32(0)); + EXPECT_EQ(610 , message.packed_sfixed64(0)); + EXPECT_EQ(611 , message.packed_float (0)); + EXPECT_EQ(612 , message.packed_double (0)); + EXPECT_EQ(true , message.packed_bool (0)); + EXPECT_EQ(unittest::FOREIGN_BAR, message.packed_enum(0)); + + EXPECT_EQ(701 , message.packed_int32 (1)); + EXPECT_EQ(702 , message.packed_int64 (1)); + EXPECT_EQ(703 , message.packed_uint32 (1)); + EXPECT_EQ(704 , message.packed_uint64 (1)); + EXPECT_EQ(705 , message.packed_sint32 (1)); + EXPECT_EQ(706 , message.packed_sint64 (1)); + EXPECT_EQ(707 , message.packed_fixed32 (1)); + EXPECT_EQ(708 , message.packed_fixed64 (1)); + EXPECT_EQ(709 , message.packed_sfixed32(1)); + EXPECT_EQ(710 , message.packed_sfixed64(1)); + EXPECT_EQ(711 , message.packed_float (1)); + EXPECT_EQ(712 , message.packed_double (1)); + EXPECT_EQ(false, message.packed_bool (1)); + EXPECT_EQ(unittest::FOREIGN_BAZ, message.packed_enum(1)); +} + +// ------------------------------------------------------------------- + +void TestUtil::ExpectPackedClear( + const unittest::TestPackedTypes& message) { + // Packed repeated fields are empty. + EXPECT_EQ(0, message.packed_int32_size ()); + EXPECT_EQ(0, message.packed_int64_size ()); + EXPECT_EQ(0, message.packed_uint32_size ()); + EXPECT_EQ(0, message.packed_uint64_size ()); + EXPECT_EQ(0, message.packed_sint32_size ()); + EXPECT_EQ(0, message.packed_sint64_size ()); + EXPECT_EQ(0, message.packed_fixed32_size ()); + EXPECT_EQ(0, message.packed_fixed64_size ()); + EXPECT_EQ(0, message.packed_sfixed32_size()); + EXPECT_EQ(0, message.packed_sfixed64_size()); + EXPECT_EQ(0, message.packed_float_size ()); + EXPECT_EQ(0, message.packed_double_size ()); + EXPECT_EQ(0, message.packed_bool_size ()); + EXPECT_EQ(0, message.packed_enum_size ()); +} + +// ------------------------------------------------------------------- + +void TestUtil::ExpectPackedFieldsModified( + const unittest::TestPackedTypes& message) { + // Do the same for packed repeated fields. + ASSERT_EQ(2, message.packed_int32_size ()); + ASSERT_EQ(2, message.packed_int64_size ()); + ASSERT_EQ(2, message.packed_uint32_size ()); + ASSERT_EQ(2, message.packed_uint64_size ()); + ASSERT_EQ(2, message.packed_sint32_size ()); + ASSERT_EQ(2, message.packed_sint64_size ()); + ASSERT_EQ(2, message.packed_fixed32_size ()); + ASSERT_EQ(2, message.packed_fixed64_size ()); + ASSERT_EQ(2, message.packed_sfixed32_size()); + ASSERT_EQ(2, message.packed_sfixed64_size()); + ASSERT_EQ(2, message.packed_float_size ()); + ASSERT_EQ(2, message.packed_double_size ()); + ASSERT_EQ(2, message.packed_bool_size ()); + ASSERT_EQ(2, message.packed_enum_size ()); + + EXPECT_EQ(601 , message.packed_int32 (0)); + EXPECT_EQ(602 , message.packed_int64 (0)); + EXPECT_EQ(603 , message.packed_uint32 (0)); + EXPECT_EQ(604 , message.packed_uint64 (0)); + EXPECT_EQ(605 , message.packed_sint32 (0)); + EXPECT_EQ(606 , message.packed_sint64 (0)); + EXPECT_EQ(607 , message.packed_fixed32 (0)); + EXPECT_EQ(608 , message.packed_fixed64 (0)); + EXPECT_EQ(609 , message.packed_sfixed32(0)); + EXPECT_EQ(610 , message.packed_sfixed64(0)); + EXPECT_EQ(611 , message.packed_float (0)); + EXPECT_EQ(612 , message.packed_double (0)); + EXPECT_EQ(true , message.packed_bool (0)); + EXPECT_EQ(unittest::FOREIGN_BAR, message.packed_enum(0)); + // Actually verify the second (modified) elements now. + EXPECT_EQ(801 , message.packed_int32 (1)); + EXPECT_EQ(802 , message.packed_int64 (1)); + EXPECT_EQ(803 , message.packed_uint32 (1)); + EXPECT_EQ(804 , message.packed_uint64 (1)); + EXPECT_EQ(805 , message.packed_sint32 (1)); + EXPECT_EQ(806 , message.packed_sint64 (1)); + EXPECT_EQ(807 , message.packed_fixed32 (1)); + EXPECT_EQ(808 , message.packed_fixed64 (1)); + EXPECT_EQ(809 , message.packed_sfixed32(1)); + EXPECT_EQ(810 , message.packed_sfixed64(1)); + EXPECT_EQ(811 , message.packed_float (1)); + EXPECT_EQ(812 , message.packed_double (1)); + EXPECT_EQ(true , message.packed_bool (1)); + EXPECT_EQ(unittest::FOREIGN_FOO, message.packed_enum(1)); +} + // =================================================================== // Extensions // @@ -1246,6 +1420,183 @@ void TestUtil::ExpectRepeatedExtensionsModified( // ------------------------------------------------------------------- +void TestUtil::SetPackedExtensions(unittest::TestPackedExtensions* message) { + message->AddExtension(unittest::packed_int32_extension , 601); + message->AddExtension(unittest::packed_int64_extension , 602); + message->AddExtension(unittest::packed_uint32_extension , 603); + message->AddExtension(unittest::packed_uint64_extension , 604); + message->AddExtension(unittest::packed_sint32_extension , 605); + message->AddExtension(unittest::packed_sint64_extension , 606); + message->AddExtension(unittest::packed_fixed32_extension , 607); + message->AddExtension(unittest::packed_fixed64_extension , 608); + message->AddExtension(unittest::packed_sfixed32_extension, 609); + message->AddExtension(unittest::packed_sfixed64_extension, 610); + message->AddExtension(unittest::packed_float_extension , 611); + message->AddExtension(unittest::packed_double_extension , 612); + message->AddExtension(unittest::packed_bool_extension , true); + message->AddExtension(unittest::packed_enum_extension, unittest::FOREIGN_BAR); + // add a second one of each field + message->AddExtension(unittest::packed_int32_extension , 701); + message->AddExtension(unittest::packed_int64_extension , 702); + message->AddExtension(unittest::packed_uint32_extension , 703); + message->AddExtension(unittest::packed_uint64_extension , 704); + message->AddExtension(unittest::packed_sint32_extension , 705); + message->AddExtension(unittest::packed_sint64_extension , 706); + message->AddExtension(unittest::packed_fixed32_extension , 707); + message->AddExtension(unittest::packed_fixed64_extension , 708); + message->AddExtension(unittest::packed_sfixed32_extension, 709); + message->AddExtension(unittest::packed_sfixed64_extension, 710); + message->AddExtension(unittest::packed_float_extension , 711); + message->AddExtension(unittest::packed_double_extension , 712); + message->AddExtension(unittest::packed_bool_extension , false); + message->AddExtension(unittest::packed_enum_extension, unittest::FOREIGN_BAZ); +} + +// ------------------------------------------------------------------- + +void TestUtil::ModifyPackedExtensions(unittest::TestPackedExtensions* message) { + message->SetExtension(unittest::packed_int32_extension , 1, 801); + message->SetExtension(unittest::packed_int64_extension , 1, 802); + message->SetExtension(unittest::packed_uint32_extension , 1, 803); + message->SetExtension(unittest::packed_uint64_extension , 1, 804); + message->SetExtension(unittest::packed_sint32_extension , 1, 805); + message->SetExtension(unittest::packed_sint64_extension , 1, 806); + message->SetExtension(unittest::packed_fixed32_extension , 1, 807); + message->SetExtension(unittest::packed_fixed64_extension , 1, 808); + message->SetExtension(unittest::packed_sfixed32_extension, 1, 809); + message->SetExtension(unittest::packed_sfixed64_extension, 1, 810); + message->SetExtension(unittest::packed_float_extension , 1, 811); + message->SetExtension(unittest::packed_double_extension , 1, 812); + message->SetExtension(unittest::packed_bool_extension , 1, true); + message->SetExtension(unittest::packed_enum_extension , 1, + unittest::FOREIGN_FOO); +} + +// ------------------------------------------------------------------- + +void TestUtil::ExpectPackedExtensionsSet( + const unittest::TestPackedExtensions& message) { + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_int32_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_int64_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_uint32_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_uint64_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sint32_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sint64_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_fixed32_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_fixed64_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sfixed32_extension)); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sfixed64_extension)); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_float_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_double_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_bool_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_enum_extension )); + + EXPECT_EQ(601 , message.GetExtension(unittest::packed_int32_extension , 0)); + EXPECT_EQ(602 , message.GetExtension(unittest::packed_int64_extension , 0)); + EXPECT_EQ(603 , message.GetExtension(unittest::packed_uint32_extension , 0)); + EXPECT_EQ(604 , message.GetExtension(unittest::packed_uint64_extension , 0)); + EXPECT_EQ(605 , message.GetExtension(unittest::packed_sint32_extension , 0)); + EXPECT_EQ(606 , message.GetExtension(unittest::packed_sint64_extension , 0)); + EXPECT_EQ(607 , message.GetExtension(unittest::packed_fixed32_extension , 0)); + EXPECT_EQ(608 , message.GetExtension(unittest::packed_fixed64_extension , 0)); + EXPECT_EQ(609 , message.GetExtension(unittest::packed_sfixed32_extension, 0)); + EXPECT_EQ(610 , message.GetExtension(unittest::packed_sfixed64_extension, 0)); + EXPECT_EQ(611 , message.GetExtension(unittest::packed_float_extension , 0)); + EXPECT_EQ(612 , message.GetExtension(unittest::packed_double_extension , 0)); + EXPECT_EQ(true , message.GetExtension(unittest::packed_bool_extension , 0)); + EXPECT_EQ(unittest::FOREIGN_BAR, + message.GetExtension(unittest::packed_enum_extension, 0)); + EXPECT_EQ(701 , message.GetExtension(unittest::packed_int32_extension , 1)); + EXPECT_EQ(702 , message.GetExtension(unittest::packed_int64_extension , 1)); + EXPECT_EQ(703 , message.GetExtension(unittest::packed_uint32_extension , 1)); + EXPECT_EQ(704 , message.GetExtension(unittest::packed_uint64_extension , 1)); + EXPECT_EQ(705 , message.GetExtension(unittest::packed_sint32_extension , 1)); + EXPECT_EQ(706 , message.GetExtension(unittest::packed_sint64_extension , 1)); + EXPECT_EQ(707 , message.GetExtension(unittest::packed_fixed32_extension , 1)); + EXPECT_EQ(708 , message.GetExtension(unittest::packed_fixed64_extension , 1)); + EXPECT_EQ(709 , message.GetExtension(unittest::packed_sfixed32_extension, 1)); + EXPECT_EQ(710 , message.GetExtension(unittest::packed_sfixed64_extension, 1)); + EXPECT_EQ(711 , message.GetExtension(unittest::packed_float_extension , 1)); + EXPECT_EQ(712 , message.GetExtension(unittest::packed_double_extension , 1)); + EXPECT_EQ(false, message.GetExtension(unittest::packed_bool_extension , 1)); + EXPECT_EQ(unittest::FOREIGN_BAZ, + message.GetExtension(unittest::packed_enum_extension, 1)); +} + +// ------------------------------------------------------------------- + +void TestUtil::ExpectPackedExtensionsClear( + const unittest::TestPackedExtensions& message) { + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_int32_extension )); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_int64_extension )); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_uint32_extension )); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_uint64_extension )); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_sint32_extension )); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_sint64_extension )); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_fixed32_extension )); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_fixed64_extension )); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_sfixed32_extension)); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_sfixed64_extension)); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_float_extension )); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_double_extension )); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_bool_extension )); + EXPECT_EQ(0, message.ExtensionSize(unittest::packed_enum_extension )); +} + +// ------------------------------------------------------------------- + +void TestUtil::ExpectPackedExtensionsModified( + const unittest::TestPackedExtensions& message) { + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_int32_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_int64_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_uint32_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_uint64_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sint32_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sint64_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_fixed32_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_fixed64_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sfixed32_extension)); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sfixed64_extension)); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_float_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_double_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_bool_extension )); + ASSERT_EQ(2, message.ExtensionSize(unittest::packed_enum_extension )); + EXPECT_EQ(601 , message.GetExtension(unittest::packed_int32_extension , 0)); + EXPECT_EQ(602 , message.GetExtension(unittest::packed_int64_extension , 0)); + EXPECT_EQ(603 , message.GetExtension(unittest::packed_uint32_extension , 0)); + EXPECT_EQ(604 , message.GetExtension(unittest::packed_uint64_extension , 0)); + EXPECT_EQ(605 , message.GetExtension(unittest::packed_sint32_extension , 0)); + EXPECT_EQ(606 , message.GetExtension(unittest::packed_sint64_extension , 0)); + EXPECT_EQ(607 , message.GetExtension(unittest::packed_fixed32_extension , 0)); + EXPECT_EQ(608 , message.GetExtension(unittest::packed_fixed64_extension , 0)); + EXPECT_EQ(609 , message.GetExtension(unittest::packed_sfixed32_extension, 0)); + EXPECT_EQ(610 , message.GetExtension(unittest::packed_sfixed64_extension, 0)); + EXPECT_EQ(611 , message.GetExtension(unittest::packed_float_extension , 0)); + EXPECT_EQ(612 , message.GetExtension(unittest::packed_double_extension , 0)); + EXPECT_EQ(true , message.GetExtension(unittest::packed_bool_extension , 0)); + EXPECT_EQ(unittest::FOREIGN_BAR, + message.GetExtension(unittest::packed_enum_extension, 0)); + + // Actually verify the second (modified) elements now. + EXPECT_EQ(801 , message.GetExtension(unittest::packed_int32_extension , 1)); + EXPECT_EQ(802 , message.GetExtension(unittest::packed_int64_extension , 1)); + EXPECT_EQ(803 , message.GetExtension(unittest::packed_uint32_extension , 1)); + EXPECT_EQ(804 , message.GetExtension(unittest::packed_uint64_extension , 1)); + EXPECT_EQ(805 , message.GetExtension(unittest::packed_sint32_extension , 1)); + EXPECT_EQ(806 , message.GetExtension(unittest::packed_sint64_extension , 1)); + EXPECT_EQ(807 , message.GetExtension(unittest::packed_fixed32_extension , 1)); + EXPECT_EQ(808 , message.GetExtension(unittest::packed_fixed64_extension , 1)); + EXPECT_EQ(809 , message.GetExtension(unittest::packed_sfixed32_extension, 1)); + EXPECT_EQ(810 , message.GetExtension(unittest::packed_sfixed64_extension, 1)); + EXPECT_EQ(811 , message.GetExtension(unittest::packed_float_extension , 1)); + EXPECT_EQ(812 , message.GetExtension(unittest::packed_double_extension , 1)); + EXPECT_EQ(true , message.GetExtension(unittest::packed_bool_extension , 1)); + EXPECT_EQ(unittest::FOREIGN_FOO, + message.GetExtension(unittest::packed_enum_extension, 1)); +} + +// ------------------------------------------------------------------- + void TestUtil::ExpectAllFieldsAndExtensionsInOrder(const string& serialized) { // We set each field individually, serialize separately, and concatenate all // the strings in canonical order to determine the expected serialization. @@ -1335,7 +1686,8 @@ TestUtil::ReflectionTester::ReflectionTester( // Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes. const FieldDescriptor* TestUtil::ReflectionTester::F(const string& name) { const FieldDescriptor* result = NULL; - if (base_descriptor_->name() == "TestAllExtensions") { + if (base_descriptor_->name() == "TestAllExtensions" || + base_descriptor_->name() == "TestPackedExtensions") { result = base_descriptor_->file()->FindExtensionByName(name + "_extension"); } else { result = base_descriptor_->FindFieldByName(name); @@ -1475,6 +1827,40 @@ void TestUtil::ReflectionTester::SetAllFieldsViaReflection(Message* message) { reflection->SetString(message, F("default_cord"), "425"); } +void TestUtil::ReflectionTester::SetPackedFieldsViaReflection( + Message* message) { + const Reflection* reflection = message->GetReflection(); + reflection->AddInt32 (message, F("packed_int32" ), 601); + reflection->AddInt64 (message, F("packed_int64" ), 602); + reflection->AddUInt32(message, F("packed_uint32" ), 603); + reflection->AddUInt64(message, F("packed_uint64" ), 604); + reflection->AddInt32 (message, F("packed_sint32" ), 605); + reflection->AddInt64 (message, F("packed_sint64" ), 606); + reflection->AddUInt32(message, F("packed_fixed32" ), 607); + reflection->AddUInt64(message, F("packed_fixed64" ), 608); + reflection->AddInt32 (message, F("packed_sfixed32"), 609); + reflection->AddInt64 (message, F("packed_sfixed64"), 610); + reflection->AddFloat (message, F("packed_float" ), 611); + reflection->AddDouble(message, F("packed_double" ), 612); + reflection->AddBool (message, F("packed_bool" ), true); + reflection->AddEnum (message, F("packed_enum" ), foreign_bar_); + + reflection->AddInt32 (message, F("packed_int32" ), 701); + reflection->AddInt64 (message, F("packed_int64" ), 702); + reflection->AddUInt32(message, F("packed_uint32" ), 703); + reflection->AddUInt64(message, F("packed_uint64" ), 704); + reflection->AddInt32 (message, F("packed_sint32" ), 705); + reflection->AddInt64 (message, F("packed_sint64" ), 706); + reflection->AddUInt32(message, F("packed_fixed32" ), 707); + reflection->AddUInt64(message, F("packed_fixed64" ), 708); + reflection->AddInt32 (message, F("packed_sfixed32"), 709); + reflection->AddInt64 (message, F("packed_sfixed64"), 710); + reflection->AddFloat (message, F("packed_float" ), 711); + reflection->AddDouble(message, F("packed_double" ), 712); + reflection->AddBool (message, F("packed_bool" ), false); + reflection->AddEnum (message, F("packed_enum" ), foreign_baz_); +} + // ------------------------------------------------------------------- void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection( @@ -1725,6 +2111,58 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection( EXPECT_EQ("425", reflection->GetStringReference(message, F("default_cord"), &scratch)); } +void TestUtil::ReflectionTester::ExpectPackedFieldsSetViaReflection( + const Message& message) { + const Reflection* reflection = message.GetReflection(); + + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_int32" ))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_int64" ))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_uint32" ))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_uint64" ))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_sint32" ))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_sint64" ))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_fixed32" ))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_fixed64" ))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_sfixed32"))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_sfixed64"))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_float" ))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_double" ))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_bool" ))); + ASSERT_EQ(2, reflection->FieldSize(message, F("packed_enum" ))); + + EXPECT_EQ(601 , reflection->GetRepeatedInt32 (message, F("packed_int32" ), 0)); + EXPECT_EQ(602 , reflection->GetRepeatedInt64 (message, F("packed_int64" ), 0)); + EXPECT_EQ(603 , reflection->GetRepeatedUInt32(message, F("packed_uint32" ), 0)); + EXPECT_EQ(604 , reflection->GetRepeatedUInt64(message, F("packed_uint64" ), 0)); + EXPECT_EQ(605 , reflection->GetRepeatedInt32 (message, F("packed_sint32" ), 0)); + EXPECT_EQ(606 , reflection->GetRepeatedInt64 (message, F("packed_sint64" ), 0)); + EXPECT_EQ(607 , reflection->GetRepeatedUInt32(message, F("packed_fixed32" ), 0)); + EXPECT_EQ(608 , reflection->GetRepeatedUInt64(message, F("packed_fixed64" ), 0)); + EXPECT_EQ(609 , reflection->GetRepeatedInt32 (message, F("packed_sfixed32"), 0)); + EXPECT_EQ(610 , reflection->GetRepeatedInt64 (message, F("packed_sfixed64"), 0)); + EXPECT_EQ(611 , reflection->GetRepeatedFloat (message, F("packed_float" ), 0)); + EXPECT_EQ(612 , reflection->GetRepeatedDouble(message, F("packed_double" ), 0)); + EXPECT_EQ(true , reflection->GetRepeatedBool (message, F("packed_bool" ), 0)); + EXPECT_EQ(foreign_bar_, + reflection->GetRepeatedEnum(message, F("packed_enum"), 0)); + + EXPECT_EQ(701 , reflection->GetRepeatedInt32 (message, F("packed_int32" ), 1)); + EXPECT_EQ(702 , reflection->GetRepeatedInt64 (message, F("packed_int64" ), 1)); + EXPECT_EQ(703 , reflection->GetRepeatedUInt32(message, F("packed_uint32" ), 1)); + EXPECT_EQ(704 , reflection->GetRepeatedUInt64(message, F("packed_uint64" ), 1)); + EXPECT_EQ(705 , reflection->GetRepeatedInt32 (message, F("packed_sint32" ), 1)); + EXPECT_EQ(706 , reflection->GetRepeatedInt64 (message, F("packed_sint64" ), 1)); + EXPECT_EQ(707 , reflection->GetRepeatedUInt32(message, F("packed_fixed32" ), 1)); + EXPECT_EQ(708 , reflection->GetRepeatedUInt64(message, F("packed_fixed64" ), 1)); + EXPECT_EQ(709 , reflection->GetRepeatedInt32 (message, F("packed_sfixed32"), 1)); + EXPECT_EQ(710 , reflection->GetRepeatedInt64 (message, F("packed_sfixed64"), 1)); + EXPECT_EQ(711 , reflection->GetRepeatedFloat (message, F("packed_float" ), 1)); + EXPECT_EQ(712 , reflection->GetRepeatedDouble(message, F("packed_double" ), 1)); + EXPECT_EQ(false, reflection->GetRepeatedBool (message, F("packed_bool" ), 1)); + EXPECT_EQ(foreign_baz_, + reflection->GetRepeatedEnum(message, F("packed_enum"), 1)); +} + // ------------------------------------------------------------------- void TestUtil::ReflectionTester::ExpectClearViaReflection( @@ -1890,6 +2328,26 @@ void TestUtil::ReflectionTester::ExpectClearViaReflection( EXPECT_EQ("123", reflection->GetStringReference(message, F("default_cord"), &scratch)); } +void TestUtil::ReflectionTester::ExpectPackedClearViaReflection( + const Message& message) { + const Reflection* reflection = message.GetReflection(); + + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_int32" ))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_int64" ))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_uint32" ))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_uint64" ))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_sint32" ))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_sint64" ))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_fixed32" ))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_fixed64" ))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_sfixed32"))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_sfixed64"))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_float" ))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_double" ))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_bool" ))); + EXPECT_EQ(0, reflection->FieldSize(message, F("packed_enum" ))); +} + // ------------------------------------------------------------------- void TestUtil::ReflectionTester::ModifyRepeatedFieldsViaReflection( @@ -1930,5 +2388,24 @@ void TestUtil::ReflectionTester::ModifyRepeatedFieldsViaReflection( reflection->SetRepeatedString(message, F("repeated_cord"), 1, "525"); } +void TestUtil::ReflectionTester::ModifyPackedFieldsViaReflection( + Message* message) { + const Reflection* reflection = message->GetReflection(); + reflection->SetRepeatedInt32 (message, F("packed_int32" ), 1, 801); + reflection->SetRepeatedInt64 (message, F("packed_int64" ), 1, 802); + reflection->SetRepeatedUInt32(message, F("packed_uint32" ), 1, 803); + reflection->SetRepeatedUInt64(message, F("packed_uint64" ), 1, 804); + reflection->SetRepeatedInt32 (message, F("packed_sint32" ), 1, 805); + reflection->SetRepeatedInt64 (message, F("packed_sint64" ), 1, 806); + reflection->SetRepeatedUInt32(message, F("packed_fixed32" ), 1, 807); + reflection->SetRepeatedUInt64(message, F("packed_fixed64" ), 1, 808); + reflection->SetRepeatedInt32 (message, F("packed_sfixed32"), 1, 809); + reflection->SetRepeatedInt64 (message, F("packed_sfixed64"), 1, 810); + reflection->SetRepeatedFloat (message, F("packed_float" ), 1, 811); + reflection->SetRepeatedDouble(message, F("packed_double" ), 1, 812); + reflection->SetRepeatedBool (message, F("packed_bool" ), 1, true); + reflection->SetRepeatedEnum (message, F("packed_enum" ), 1, foreign_foo_); +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h index af03afc3..ca840c71 100644 --- a/src/google/protobuf/test_util.h +++ b/src/google/protobuf/test_util.h @@ -52,30 +52,44 @@ class TestUtil { static void SetAllFields(unittest::TestAllTypes* message); static void SetAllExtensions(unittest::TestAllExtensions* message); static void SetAllFieldsAndExtensions(unittest::TestFieldOrderings* message); + static void SetPackedFields(unittest::TestPackedTypes* message); + static void SetPackedExtensions(unittest::TestPackedExtensions* message); // Use the repeated versions of the set_*() accessors to modify all the // repeated fields of the messsage (which should already have been - // initialized with SetAllFields()). SetAllFields() itself only tests + // initialized with Set*Fields()). Set*Fields() itself only tests // the add_*() accessors. static void ModifyRepeatedFields(unittest::TestAllTypes* message); static void ModifyRepeatedExtensions(unittest::TestAllExtensions* message); + static void ModifyPackedFields(unittest::TestPackedTypes* message); + static void ModifyPackedExtensions(unittest::TestPackedExtensions* message); // Check that all fields have the values that they should have after - // SetAllFields() is called. + // Set*Fields() is called. static void ExpectAllFieldsSet(const unittest::TestAllTypes& message); static void ExpectAllExtensionsSet( const unittest::TestAllExtensions& message); + static void ExpectPackedFieldsSet(const unittest::TestPackedTypes& message); + static void ExpectPackedExtensionsSet( + const unittest::TestPackedExtensions& message); // Expect that the message is modified as would be expected from - // ModifyRepeatedFields(). + // Modify*Fields(). static void ExpectRepeatedFieldsModified( const unittest::TestAllTypes& message); static void ExpectRepeatedExtensionsModified( const unittest::TestAllExtensions& message); + static void ExpectPackedFieldsModified( + const unittest::TestPackedTypes& message); + static void ExpectPackedExtensionsModified( + const unittest::TestPackedExtensions& message); // Check that all fields have their default values. static void ExpectClear(const unittest::TestAllTypes& message); static void ExpectExtensionsClear(const unittest::TestAllExtensions& message); + static void ExpectPackedClear(const unittest::TestPackedTypes& message); + static void ExpectPackedExtensionsClear( + const unittest::TestPackedExtensions& message); // Check that the passed-in serialization is the canonical serialization we // expect for a TestFieldOrderings message filled in by @@ -97,6 +111,11 @@ class TestUtil { void ExpectAllFieldsSetViaReflection(const Message& message); void ExpectClearViaReflection(const Message& message); + void SetPackedFieldsViaReflection(Message* message); + void ModifyPackedFieldsViaReflection(Message* message); + void ExpectPackedFieldsSetViaReflection(const Message& message); + void ExpectPackedClearViaReflection(const Message& message); + private: const FieldDescriptor* F(const string& name); diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto index 0aa66b9f..46ce77c3 100644 --- a/src/google/protobuf/unittest.proto +++ b/src/google/protobuf/unittest.proto @@ -461,6 +461,46 @@ message OneBytes { optional bytes data = 1; } +// Test messages for packed fields + +message TestPackedTypes { + repeated int32 packed_int32 = 90 [packed = true]; + repeated int64 packed_int64 = 91 [packed = true]; + repeated uint32 packed_uint32 = 92 [packed = true]; + repeated uint64 packed_uint64 = 93 [packed = true]; + repeated sint32 packed_sint32 = 94 [packed = true]; + repeated sint64 packed_sint64 = 95 [packed = true]; + repeated fixed32 packed_fixed32 = 96 [packed = true]; + repeated fixed64 packed_fixed64 = 97 [packed = true]; + repeated sfixed32 packed_sfixed32 = 98 [packed = true]; + repeated sfixed64 packed_sfixed64 = 99 [packed = true]; + repeated float packed_float = 100 [packed = true]; + repeated double packed_double = 101 [packed = true]; + repeated bool packed_bool = 102 [packed = true]; + repeated ForeignEnum packed_enum = 103 [packed = true]; +} + +message TestPackedExtensions { + extensions 1 to max; +} + +extend TestPackedExtensions { + repeated int32 packed_int32_extension = 90 [packed = true]; + repeated int64 packed_int64_extension = 91 [packed = true]; + repeated uint32 packed_uint32_extension = 92 [packed = true]; + repeated uint64 packed_uint64_extension = 93 [packed = true]; + repeated sint32 packed_sint32_extension = 94 [packed = true]; + repeated sint64 packed_sint64_extension = 95 [packed = true]; + repeated fixed32 packed_fixed32_extension = 96 [packed = true]; + repeated fixed64 packed_fixed64_extension = 97 [packed = true]; + repeated sfixed32 packed_sfixed32_extension = 98 [packed = true]; + repeated sfixed64 packed_sfixed64_extension = 99 [packed = true]; + repeated float packed_float_extension = 100 [packed = true]; + repeated double packed_double_extension = 101 [packed = true]; + repeated bool packed_bool_extension = 102 [packed = true]; + repeated ForeignEnum packed_enum_extension = 103 [packed = true]; +} + // Test that RPC services work. message FooRequest {} message FooResponse {} diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc index 6a9be5a4..f42f9a59 100644 --- a/src/google/protobuf/unknown_field_set.cc +++ b/src/google/protobuf/unknown_field_set.cc @@ -154,6 +154,46 @@ int UnknownFieldSet::SpaceUsed() const { return sizeof(*this) + SpaceUsedExcludingSelf(); } +UnknownFieldSet::Internal::FieldMap UnknownFieldSet::kEmptyMap; +const UnknownFieldSet::iterator UnknownFieldSet::kEmptyIterator( + kEmptyMap.end(), &kEmptyMap); +const UnknownFieldSet::const_iterator UnknownFieldSet::kEmptyConstIterator( + kEmptyMap.end(), &kEmptyMap); + +void UnknownFieldSet::iterator::AdvanceToNonEmpty() { + while (inner_iterator_ != inner_map_->end() && + (inner_iterator_->second->index() == -1 || + inner_iterator_->second->empty())) { + ++inner_iterator_; + } +} + +void UnknownFieldSet::const_iterator::AdvanceToNonEmpty() { + while (inner_iterator_ != inner_map_->end() && + (inner_iterator_->second->index() == -1 || + inner_iterator_->second->empty())) { + ++inner_iterator_; + } +} + +UnknownFieldSet::iterator UnknownFieldSet::begin() { + if (internal_ == NULL) return kEmptyIterator; + + UnknownFieldSet::iterator result(internal_->fields_.begin(), + &internal_->fields_); + result.AdvanceToNonEmpty(); + return result; +} + +UnknownFieldSet::const_iterator UnknownFieldSet::begin() const { + if (internal_ == NULL) return kEmptyIterator; + + UnknownFieldSet::const_iterator result(internal_->fields_.begin(), + &internal_->fields_); + result.AdvanceToNonEmpty(); + return result; +} + UnknownField::UnknownField(int number) : number_(number), index_(-1) { diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h index 55eec6e2..f17012df 100644 --- a/src/google/protobuf/unknown_field_set.h +++ b/src/google/protobuf/unknown_field_set.h @@ -70,6 +70,13 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { void Clear(); // Is this set empty? + // + // Note that this is equivalent to field_count() == 0 but is NOT necessarily + // equivalent to begin() == end(). The iterator class skips fields which are + // themselves empty, so if field_count() is non-zero but field(i)->empty() is + // true for all i, then begin() will be equal to end() but empty() will return + // false. This inconsistency almost never occurs in practice because typical + // code does not add empty fields to an UnknownFieldSet. inline bool empty() const; // Merge the contents of some other UnknownFieldSet with this one. @@ -78,6 +85,117 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { // Swaps the contents of some other UnknownFieldSet with this one. inline void Swap(UnknownFieldSet* x); + // Find a field by field number. Returns NULL if not found. + const UnknownField* FindFieldByNumber(int number) const; + + // Add a field by field number. If the field number already exists, returns + // the existing UnknownField. + UnknownField* AddField(int number); + + // Computes (an estimate of) the total number of bytes currently used for + // storing the unknown fields in memory. Does NOT include + // sizeof(*this) in the calculation. + int SpaceUsedExcludingSelf() const; + + // Version of SpaceUsed() including sizeof(*this). + int SpaceUsed() const; + + // STL-style iteration --------------------------------------------- + // These iterate over the non-empty UnknownFields in order by field + // number. All iterators are invalidated whenever the UnknownFieldSet + // is modified. + + class const_iterator; + + class LIBPROTOBUF_EXPORT iterator { + public: + iterator() {} + + bool operator==(const iterator& other) { + return inner_iterator_ == other.inner_iterator_; + } + bool operator!=(const iterator& other) { + return inner_iterator_ != other.inner_iterator_; + } + + UnknownField& operator*() { return *inner_iterator_->second; } + UnknownField* operator->() { return inner_iterator_->second; } + iterator& operator++() { + ++inner_iterator_; + AdvanceToNonEmpty(); + return *this; + } + iterator operator++(int) { + iterator copy(*this); + ++*this; + return copy; + } + + private: + friend class UnknownFieldSet; + friend class LIBPROTOBUF_EXPORT UnknownFieldSet::const_iterator; + iterator(map<int, UnknownField*>::iterator inner_iterator, + map<int, UnknownField*>* inner_map) + : inner_iterator_(inner_iterator), inner_map_(inner_map) {} + + void AdvanceToNonEmpty(); + + map<int, UnknownField*>::iterator inner_iterator_; + map<int, UnknownField*>* inner_map_; + }; + + class LIBPROTOBUF_EXPORT const_iterator { + public: + const_iterator() {} + const_iterator(const iterator& other) + : inner_iterator_(other.inner_iterator_), inner_map_(other.inner_map_) {} + + bool operator==(const const_iterator& other) { + return inner_iterator_ == other.inner_iterator_; + } + bool operator!=(const const_iterator& other) { + return inner_iterator_ != other.inner_iterator_; + } + + UnknownField& operator*() { return *inner_iterator_->second; } + UnknownField* operator->() { return inner_iterator_->second; } + const_iterator& operator++() { + ++inner_iterator_; + AdvanceToNonEmpty(); + return *this; + } + const_iterator operator++(int) { + const_iterator copy(*this); + ++*this; + return copy; + } + + private: + friend class UnknownFieldSet; + const_iterator(map<int, UnknownField*>::const_iterator inner_iterator, + const map<int, UnknownField*>* inner_map) + : inner_iterator_(inner_iterator), inner_map_(inner_map) {} + + void AdvanceToNonEmpty(); + + map<int, UnknownField*>::const_iterator inner_iterator_; + const map<int, UnknownField*>* inner_map_; + }; + + iterator begin(); + iterator end() { + return internal_ == NULL ? kEmptyIterator : + iterator(internal_->fields_.end(), &internal_->fields_); + } + const_iterator begin() const; + const_iterator end() const { + return internal_ == NULL ? kEmptyConstIterator : + const_iterator(internal_->fields_.end(), &internal_->fields_); + } + + // Old-style iteration --------------------------------------------- + // New code should use begin() and end() rather than these methods. + // Returns the number of fields present in the UnknownFieldSet. inline int field_count() const; // Get a field in the set, where 0 <= index < field_count(). The fields @@ -87,13 +205,6 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { // 0 <= index < field_count(). The fields appear in arbitrary order. inline UnknownField* mutable_field(int index); - // Find a field by field number. Returns NULL if not found. - const UnknownField* FindFieldByNumber(int number) const; - - // Add a field by field number. If the field number already exists, returns - // the existing UnknownField. - UnknownField* AddField(int number); - // Parsing helpers ------------------------------------------------- // These work exactly like the similarly-named methods of Message. @@ -105,13 +216,6 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { return ParseFromArray(data.data(), data.size()); } - // Computes (an estimate of) the total number of bytes currently used for - // storing the unknown fields in memory. Does NOT include - // sizeof(*this) in the calculation. - int SpaceUsedExcludingSelf() const; - // Version of SpaceUsed() including sizeof(*this). - int SpaceUsed() const; - private: // "Active" fields are ones which have been added since the last time Clear() // was called. Inactive fields are objects we are keeping around incase @@ -139,6 +243,11 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { // Don't keep more inactive fields than this. static const int kMaxInactiveFields = 100; + // Used by begin() and end() when internal_ is NULL. + static Internal::FieldMap kEmptyMap; + static const iterator kEmptyIterator; + static const const_iterator kEmptyConstIterator; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet); }; @@ -160,6 +269,9 @@ class LIBPROTOBUF_EXPORT UnknownField { // Clears all fields. void Clear(); + // Is this field empty? (I.e. all of the *_size() methods return zero.) + inline bool empty() const; + // Merge the contents of some other UnknownField with this one. For each // wire type, the values are simply concatenated. void MergeFrom(const UnknownField& other); @@ -256,6 +368,14 @@ inline UnknownField* UnknownFieldSet::mutable_field(int index) { return internal_->active_fields_[index]; } +inline bool UnknownField::empty() const { + return varint_.size() == 0 && + fixed32_.size() == 0 && + fixed64_.size() == 0 && + length_delimited_.size() == 0 && + group_.size() == 0; +} + inline int UnknownField::number() const { return number_; } inline int UnknownField::index () const { return index_; } @@ -322,8 +442,8 @@ inline UnknownFieldSet* UnknownField::add_group() { } inline void UnknownField::clear_varint () { varint_.Clear(); } -inline void UnknownField::clear_fixed32() { varint_.Clear(); } -inline void UnknownField::clear_fixed64() { varint_.Clear(); } +inline void UnknownField::clear_fixed32() { fixed32_.Clear(); } +inline void UnknownField::clear_fixed64() { fixed64_.Clear(); } inline void UnknownField::clear_length_delimited() { length_delimited_.Clear(); } diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc index c7e78b23..0a75af9f 100644 --- a/src/google/protobuf/unknown_field_set_unittest.cc +++ b/src/google/protobuf/unknown_field_set_unittest.cc @@ -516,6 +516,92 @@ TEST_F(UnknownFieldSetTest, SpaceUsed) { EXPECT_EQ(expected_size, unknown_fields.SpaceUsed()); } +TEST_F(UnknownFieldSetTest, Empty) { + UnknownFieldSet unknown_fields; + EXPECT_TRUE(unknown_fields.empty()); + unknown_fields.AddField(6)->add_varint(123); + EXPECT_FALSE(unknown_fields.empty()); + unknown_fields.Clear(); + EXPECT_TRUE(unknown_fields.empty()); +} + +TEST_F(UnknownFieldSetTest, FieldEmpty) { + UnknownFieldSet unknown_fields; + UnknownField* field = unknown_fields.AddField(1); + + EXPECT_TRUE(field->empty()); + + field->add_varint(1); + EXPECT_FALSE(field->empty()); + field->Clear(); + EXPECT_TRUE(field->empty()); + + field->add_fixed32(1); + EXPECT_FALSE(field->empty()); + field->Clear(); + EXPECT_TRUE(field->empty()); + + field->add_fixed64(1); + EXPECT_FALSE(field->empty()); + field->Clear(); + EXPECT_TRUE(field->empty()); + + field->add_length_delimited("foo"); + EXPECT_FALSE(field->empty()); + field->Clear(); + EXPECT_TRUE(field->empty()); + + field->add_group(); + EXPECT_FALSE(field->empty()); + field->Clear(); + EXPECT_TRUE(field->empty()); +} + +TEST_F(UnknownFieldSetTest, Iterator) { + UnknownFieldSet unknown_fields; + EXPECT_TRUE(unknown_fields.begin() == unknown_fields.end()); + + // Populate the UnknownFieldSet with some inactive fields by adding some + // fields and then clearing. + unknown_fields.AddField(6); + unknown_fields.AddField(4); + unknown_fields.Clear(); + + // Add a bunch of "active" fields. + UnknownField* a = unknown_fields.AddField(5); + unknown_fields.AddField(3); + unknown_fields.AddField(9); + unknown_fields.AddField(1); + UnknownField* b = unknown_fields.AddField(2); + + // Only make some of them non-empty. + a->add_varint(1); + b->add_length_delimited("foo"); + + // Iterate! + { + UnknownFieldSet::iterator iter = unknown_fields.begin(); + ASSERT_TRUE(iter != unknown_fields.end()); + EXPECT_EQ(b, &*iter); + ++iter; + ASSERT_TRUE(iter != unknown_fields.end()); + EXPECT_EQ(a, &*iter); + ++iter; + EXPECT_TRUE(iter == unknown_fields.end()); + } + + { + UnknownFieldSet::const_iterator iter = unknown_fields.begin(); + ASSERT_TRUE(iter != unknown_fields.end()); + EXPECT_EQ(b, &*iter); + ++iter; + ASSERT_TRUE(iter != unknown_fields.end()); + EXPECT_EQ(a, &*iter); + ++iter; + EXPECT_TRUE(iter == unknown_fields.end()); + } +} + } // namespace } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index 99ea619b..aeea3ccb 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -369,93 +369,155 @@ bool WireFormat::ParseAndMergeField( const Reflection* message_reflection = message->GetReflection(); if (field == NULL || - GetTagWireType(tag) != WireTypeForFieldType(field->type())) { + GetTagWireType(tag) != WireTypeForField(field)) { // We don't recognize this field. Either the field number is unknown // or the wire type doesn't match. Put it in our unknown field set. return SkipField(input, tag, message_reflection->MutableUnknownFields(message)); } - switch (field->type()) { -#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \ - case FieldDescriptor::TYPE_##TYPE: { \ - CPPTYPE value; \ - if (!Read##TYPE_METHOD(input, &value)) return false; \ - if (field->is_repeated()) { \ - message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ - } else { \ - message_reflection->Set##CPPTYPE_METHOD(message, field, value); \ - } \ - break; \ - } - - HANDLE_TYPE( INT32, Int32, int32, Int32) - HANDLE_TYPE( INT64, Int64, int64, Int64) - HANDLE_TYPE(SINT32, SInt32, int32, Int32) - HANDLE_TYPE(SINT64, SInt64, int64, Int64) - HANDLE_TYPE(UINT32, UInt32, uint32, UInt32) - HANDLE_TYPE(UINT64, UInt64, uint64, UInt64) - - HANDLE_TYPE( FIXED32, Fixed32, uint32, UInt32) - HANDLE_TYPE( FIXED64, Fixed64, uint64, UInt64) - HANDLE_TYPE(SFIXED32, SFixed32, int32, Int32) - HANDLE_TYPE(SFIXED64, SFixed64, int64, Int64) - - HANDLE_TYPE(FLOAT , Float , float , Float ) - HANDLE_TYPE(DOUBLE, Double, double, Double) - - HANDLE_TYPE(BOOL, Bool, bool, Bool) - - HANDLE_TYPE(STRING, String, string, String) - HANDLE_TYPE(BYTES, Bytes, string, String) + if (field->options().packed()) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + io::CodedInputStream::Limit limit = input->PushLimit(length); -#undef HANDLE_TYPE + switch (field->type()) { +#define HANDLE_PACKED_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: { \ + while (input->BytesUntilLimit() > 0) { \ + CPPTYPE value; \ + if (!Read##TYPE_METHOD(input, &value)) return false; \ + message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ + } \ + break; \ + } - case FieldDescriptor::TYPE_ENUM: { - int value; - if (!ReadEnum(input, &value)) return false; - const EnumValueDescriptor* enum_value = - field->enum_type()->FindValueByNumber(value); - if (enum_value != NULL) { - if (field->is_repeated()) { - message_reflection->AddEnum(message, field, enum_value); - } else { - message_reflection->SetEnum(message, field, enum_value); + HANDLE_PACKED_TYPE( INT32, Int32, int32, Int32) + HANDLE_PACKED_TYPE( INT64, Int64, int64, Int64) + HANDLE_PACKED_TYPE(SINT32, SInt32, int32, Int32) + HANDLE_PACKED_TYPE(SINT64, SInt64, int64, Int64) + HANDLE_PACKED_TYPE(UINT32, UInt32, uint32, UInt32) + HANDLE_PACKED_TYPE(UINT64, UInt64, uint64, UInt64) + + HANDLE_PACKED_TYPE( FIXED32, Fixed32, uint32, UInt32) + HANDLE_PACKED_TYPE( FIXED64, Fixed64, uint64, UInt64) + HANDLE_PACKED_TYPE(SFIXED32, SFixed32, int32, Int32) + HANDLE_PACKED_TYPE(SFIXED64, SFixed64, int64, Int64) + + HANDLE_PACKED_TYPE(FLOAT , Float , float , Float ) + HANDLE_PACKED_TYPE(DOUBLE, Double, double, Double) + + HANDLE_PACKED_TYPE(BOOL, Bool, bool, Bool) +#undef HANDLE_PACKED_TYPE + + case FieldDescriptor::TYPE_ENUM: { + while (input->BytesUntilLimit() > 0) { + int value; + if (!ReadEnum(input, &value)) return false; + const EnumValueDescriptor* enum_value = + field->enum_type()->FindValueByNumber(value); + if (enum_value != NULL) { + message_reflection->AddEnum(message, field, enum_value); + } } - } else { - // The enum value is not one of the known values. Add it to the - // UnknownFieldSet. - int64 sign_extended_value = static_cast<int64>(value); - message_reflection->MutableUnknownFields(message) - ->AddField(GetTagFieldNumber(tag)) - ->add_varint(sign_extended_value); + + break; } - break; + + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_BYTES: + // Can't have packed fields of these types: these should be caught by + // the protocol compiler. + return false; + break; } + input->PopLimit(limit); + } else { + switch (field->type()) { +#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: { \ + CPPTYPE value; \ + if (!Read##TYPE_METHOD(input, &value)) return false; \ + if (field->is_repeated()) { \ + message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ + } else { \ + message_reflection->Set##CPPTYPE_METHOD(message, field, value); \ + } \ + break; \ + } + + HANDLE_TYPE( INT32, Int32, int32, Int32) + HANDLE_TYPE( INT64, Int64, int64, Int64) + HANDLE_TYPE(SINT32, SInt32, int32, Int32) + HANDLE_TYPE(SINT64, SInt64, int64, Int64) + HANDLE_TYPE(UINT32, UInt32, uint32, UInt32) + HANDLE_TYPE(UINT64, UInt64, uint64, UInt64) - case FieldDescriptor::TYPE_GROUP: { - Message* sub_message; - if (field->is_repeated()) { - sub_message = message_reflection->AddMessage(message, field); - } else { - sub_message = message_reflection->MutableMessage(message, field); + HANDLE_TYPE( FIXED32, Fixed32, uint32, UInt32) + HANDLE_TYPE( FIXED64, Fixed64, uint64, UInt64) + HANDLE_TYPE(SFIXED32, SFixed32, int32, Int32) + HANDLE_TYPE(SFIXED64, SFixed64, int64, Int64) + + HANDLE_TYPE(FLOAT , Float , float , Float ) + HANDLE_TYPE(DOUBLE, Double, double, Double) + + HANDLE_TYPE(BOOL, Bool, bool, Bool) + + HANDLE_TYPE(STRING, String, string, String) + HANDLE_TYPE(BYTES, Bytes, string, String) + +#undef HANDLE_TYPE + + case FieldDescriptor::TYPE_ENUM: { + int value; + if (!ReadEnum(input, &value)) return false; + const EnumValueDescriptor* enum_value = + field->enum_type()->FindValueByNumber(value); + if (enum_value != NULL) { + if (field->is_repeated()) { + message_reflection->AddEnum(message, field, enum_value); + } else { + message_reflection->SetEnum(message, field, enum_value); + } + } else { + // The enum value is not one of the known values. Add it to the + // UnknownFieldSet. + int64 sign_extended_value = static_cast<int64>(value); + message_reflection->MutableUnknownFields(message) + ->AddField(GetTagFieldNumber(tag)) + ->add_varint(sign_extended_value); + } + break; } - if (!ReadGroup(GetTagFieldNumber(tag), input, sub_message)) return false; - break; - } - case FieldDescriptor::TYPE_MESSAGE: { - Message* sub_message; - if (field->is_repeated()) { - sub_message = message_reflection->AddMessage(message, field); - } else { - sub_message = message_reflection->MutableMessage(message, field); + case FieldDescriptor::TYPE_GROUP: { + Message* sub_message; + if (field->is_repeated()) { + sub_message = message_reflection->AddMessage(message, field); + } else { + sub_message = message_reflection->MutableMessage(message, field); + } + + if (!ReadGroup(GetTagFieldNumber(tag), input, sub_message)) + return false; + break; } - if (!ReadMessage(input, sub_message)) return false; - break; + case FieldDescriptor::TYPE_MESSAGE: { + Message* sub_message; + if (field->is_repeated()) { + sub_message = message_reflection->AddMessage(message, field); + } else { + sub_message = message_reflection->MutableMessage(message, field); + } + + if (!ReadMessage(input, sub_message)) return false; + break; + } } } @@ -602,8 +664,53 @@ bool WireFormat::SerializeFieldWithCachedSizes( count = 1; } + const bool is_packed = field->options().packed(); + if (is_packed && count > 0) { + if (!WriteTag(field->number(), WIRETYPE_LENGTH_DELIMITED, output)) + return false; + const int data_size = FieldDataOnlyByteSize(field, message); + if (!output->WriteVarint32(data_size)) return false; + } + for (int j = 0; j < count; j++) { switch (field->type()) { +#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: { \ + const CPPTYPE value = field->is_repeated() ? \ + message_reflection->GetRepeated##CPPTYPE_METHOD( \ + message, field, j) : \ + message_reflection->Get##CPPTYPE_METHOD( \ + message, field); \ + if (is_packed) { \ + if (!Write##TYPE_METHOD##NoTag(value, output)) { \ + return false; \ + } \ + } else { \ + if (!Write##TYPE_METHOD(field->number(), value, output)) { \ + return false; \ + } \ + } \ + break; \ + } + + HANDLE_PRIMITIVE_TYPE( INT32, int32, Int32, Int32) + HANDLE_PRIMITIVE_TYPE( INT64, int64, Int64, Int64) + HANDLE_PRIMITIVE_TYPE(SINT32, int32, SInt32, Int32) + HANDLE_PRIMITIVE_TYPE(SINT64, int64, SInt64, Int64) + HANDLE_PRIMITIVE_TYPE(UINT32, uint32, UInt32, UInt32) + HANDLE_PRIMITIVE_TYPE(UINT64, uint64, UInt64, UInt64) + + HANDLE_PRIMITIVE_TYPE( FIXED32, uint32, Fixed32, UInt32) + HANDLE_PRIMITIVE_TYPE( FIXED64, uint64, Fixed64, UInt64) + HANDLE_PRIMITIVE_TYPE(SFIXED32, int32, SFixed32, Int32) + HANDLE_PRIMITIVE_TYPE(SFIXED64, int64, SFixed64, Int64) + + HANDLE_PRIMITIVE_TYPE(FLOAT , float , Float , Float ) + HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double) + + HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool) +#undef HANDLE_PRIMITIVE_TYPE + #define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \ case FieldDescriptor::TYPE_##TYPE: \ if (!Write##TYPE_METHOD( \ @@ -617,23 +724,6 @@ bool WireFormat::SerializeFieldWithCachedSizes( } \ break; - HANDLE_TYPE( INT32, Int32, Int32) - HANDLE_TYPE( INT64, Int64, Int64) - HANDLE_TYPE(SINT32, SInt32, Int32) - HANDLE_TYPE(SINT64, SInt64, Int64) - HANDLE_TYPE(UINT32, UInt32, UInt32) - HANDLE_TYPE(UINT64, UInt64, UInt64) - - HANDLE_TYPE( FIXED32, Fixed32, UInt32) - HANDLE_TYPE( FIXED64, Fixed64, UInt64) - HANDLE_TYPE(SFIXED32, SFixed32, Int32) - HANDLE_TYPE(SFIXED64, SFixed64, Int64) - - HANDLE_TYPE(FLOAT , Float , Float ) - HANDLE_TYPE(DOUBLE, Double, Double) - - HANDLE_TYPE(BOOL, Bool, Bool) - HANDLE_TYPE(GROUP , Group , Message) HANDLE_TYPE(MESSAGE, Message, Message) #undef HANDLE_TYPE @@ -642,7 +732,12 @@ bool WireFormat::SerializeFieldWithCachedSizes( const EnumValueDescriptor* value = field->is_repeated() ? message_reflection->GetRepeatedEnum(message, field, j) : message_reflection->GetEnum(message, field); - if (!WriteEnum(field->number(), value->number(), output)) return false; + if (is_packed) { + if (!WriteEnumNoTag(value->number(), output)) return false; + } else { + if (!WriteEnum(field->number(), value->number(), output)) + return false; + } break; } @@ -736,36 +831,60 @@ int WireFormat::FieldByteSize( return MessageSetItemByteSize(field, message); } - int our_size = 0; - int count = 0; - if (field->is_repeated()) { count = message_reflection->FieldSize(message, field); } else if (message_reflection->HasField(message, field)) { count = 1; } - our_size += count * TagSize(field->number(), field->type()); + const int data_size = FieldDataOnlyByteSize(field, message); + int our_size = data_size; + if (field->options().packed()) { + if (data_size > 0) { + // Packed fields get serialized like a string, not their native type. + // Technically this doesn't really matter; the size only changes if it's + // a GROUP + our_size += TagSize(field->number(), FieldDescriptor::TYPE_STRING); + our_size += io::CodedOutputStream::VarintSize32(data_size); + } + } else { + our_size += count * TagSize(field->number(), field->type()); + } + return our_size; +} + +int WireFormat::FieldDataOnlyByteSize( + const FieldDescriptor* field, + const Message& message) { + const Reflection* message_reflection = message.GetReflection(); + + int count = 0; + if (field->is_repeated()) { + count = message_reflection->FieldSize(message, field); + } else if (message_reflection->HasField(message, field)) { + count = 1; + } + int data_size = 0; switch (field->type()) { #define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \ case FieldDescriptor::TYPE_##TYPE: \ if (field->is_repeated()) { \ for (int j = 0; j < count; j++) { \ - our_size += TYPE_METHOD##Size( \ + data_size += TYPE_METHOD##Size( \ message_reflection->GetRepeated##CPPTYPE_METHOD( \ message, field, j)); \ } \ } else { \ - our_size += TYPE_METHOD##Size( \ + data_size += TYPE_METHOD##Size( \ message_reflection->Get##CPPTYPE_METHOD(message, field)); \ } \ break; #define HANDLE_FIXED_TYPE(TYPE, TYPE_METHOD) \ case FieldDescriptor::TYPE_##TYPE: \ - our_size += count * k##TYPE_METHOD##Size; \ + data_size += count * k##TYPE_METHOD##Size; \ break; HANDLE_TYPE( INT32, Int32, Int32) @@ -793,11 +912,11 @@ int WireFormat::FieldByteSize( case FieldDescriptor::TYPE_ENUM: { if (field->is_repeated()) { for (int j = 0; j < count; j++) { - our_size += EnumSize( + data_size += EnumSize( message_reflection->GetRepeatedEnum(message, field, j)->number()); } } else { - our_size += EnumSize( + data_size += EnumSize( message_reflection->GetEnum(message, field)->number()); } break; @@ -813,13 +932,12 @@ int WireFormat::FieldByteSize( message_reflection->GetRepeatedStringReference( message, field, j, &scratch) : message_reflection->GetStringReference(message, field, &scratch); - our_size += StringSize(value); + data_size += StringSize(value); } break; } } - - return our_size; + return data_size; } int WireFormat::MessageSetItemByteSize( diff --git a/src/google/protobuf/wire_format.h b/src/google/protobuf/wire_format.h index 06f20d2a..9004caaa 100644 --- a/src/google/protobuf/wire_format.h +++ b/src/google/protobuf/wire_format.h @@ -163,13 +163,20 @@ class LIBPROTOBUF_EXPORT WireFormat { static inline WireType WireTypeForFieldType(FieldDescriptor::Type type) { return kWireTypeForFieldType[type]; } + // This is different from WireTypeForFieldType(field->type()) in the case of + // packed repeated fields. + static inline WireType WireTypeForField(const FieldDescriptor* field); // Number of bits in a tag which identify the wire type. static const int kTagTypeBits = 3; // Mask for those bits. static const uint32 kTagTypeMask = (1 << kTagTypeBits) - 1; - // Helper functions for encoding and decoding tags. (Inlined below.) + // Helper functions for encoding and decoding tags. (Inlined below and in + // _inl.h) + // + // This is different from MakeTag(field->number(), field->type()) in the case + // of packed repeated fields. static uint32 MakeTag(const FieldDescriptor* field); static uint32 MakeTag(int field_number, WireType type); static WireType GetTagWireType(uint32 tag); @@ -258,10 +265,27 @@ class LIBPROTOBUF_EXPORT WireFormat { template<typename MessageType> static inline bool ReadMessageNoVirtual(input, MessageType* value); - // Write a tag. The Write*() functions automatically include the tag, so - // normally there's no need to call this. + // Write a tag. The Write*() functions typically include the tag, so + // normally there's no need to call this unless using the Write*NoTag() + // variants. static inline bool WriteTag(field_number, WireType type, output) INL; + // Write fields, without tags. + static inline bool WriteInt32NoTag (int32 value, output) INL; + static inline bool WriteInt64NoTag (int64 value, output) INL; + static inline bool WriteUInt32NoTag (uint32 value, output) INL; + static inline bool WriteUInt64NoTag (uint64 value, output) INL; + static inline bool WriteSInt32NoTag (int32 value, output) INL; + static inline bool WriteSInt64NoTag (int64 value, output) INL; + static inline bool WriteFixed32NoTag (uint32 value, output) INL; + static inline bool WriteFixed64NoTag (uint64 value, output) INL; + static inline bool WriteSFixed32NoTag(int32 value, output) INL; + static inline bool WriteSFixed64NoTag(int64 value, output) INL; + static inline bool WriteFloatNoTag (float value, output) INL; + static inline bool WriteDoubleNoTag (double value, output) INL; + static inline bool WriteBoolNoTag (bool value, output) INL; + static inline bool WriteEnumNoTag (int value, output) INL; + // Write fields, including tags. static inline bool WriteInt32 (field_number, int32 value, output) INL; static inline bool WriteInt64 (field_number, int64 value, output) INL; @@ -355,6 +379,14 @@ class LIBPROTOBUF_EXPORT WireFormat { const FieldDescriptor* field, const Message& message); + // Computes the byte size of a field, excluding tags. For packed fields, it + // only includes the size of the raw data, and not the size of the total + // length, but for other length-delimited types, the size of the length is + // included. + static int FieldDataOnlyByteSize( + const FieldDescriptor* field, // Cannot be NULL + const Message& message); + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormat); }; @@ -368,10 +400,6 @@ class LIBPROTOBUF_EXPORT WireFormat { static_cast<uint32>( \ ((FIELD_NUMBER) << ::google::protobuf::internal::WireFormat::kTagTypeBits) | (TYPE)) -inline uint32 WireFormat::MakeTag(const FieldDescriptor* field) { - return MakeTag(field->number(), WireTypeForFieldType(field->type())); -} - inline uint32 WireFormat::MakeTag(int field_number, WireType type) { return GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(field_number, type); } diff --git a/src/google/protobuf/wire_format_inl.h b/src/google/protobuf/wire_format_inl.h index 539d8c67..451ac11c 100644 --- a/src/google/protobuf/wire_format_inl.h +++ b/src/google/protobuf/wire_format_inl.h @@ -38,6 +38,8 @@ #include <string> #include <google/protobuf/stubs/common.h> #include <google/protobuf/wire_format.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/io/coded_stream.h> @@ -51,6 +53,19 @@ namespace google { namespace protobuf { namespace internal { +inline WireFormat::WireType WireFormat::WireTypeForField( + const FieldDescriptor* field) { + if (field->options().packed()) { + return WIRETYPE_LENGTH_DELIMITED; + } else { + return WireTypeForFieldType(field->type()); + } +} + +inline uint32 WireFormat::MakeTag(const FieldDescriptor* field) { + return MakeTag(field->number(), WireTypeForField(field)); +} + inline bool WireFormat::ReadInt32(io::CodedInputStream* input, int32* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; @@ -210,75 +225,132 @@ inline bool WireFormat::WriteTag(int field_number, WireType type, return output->WriteTag(MakeTag(field_number, type)); } +inline bool WireFormat::WriteInt32NoTag(int32 value, + io::CodedOutputStream* output) { + return output->WriteVarint32SignExtended(value); +} +inline bool WireFormat::WriteInt64NoTag(int64 value, + io::CodedOutputStream* output) { + return output->WriteVarint64(static_cast<uint64>(value)); +} +inline bool WireFormat::WriteUInt32NoTag(uint32 value, + io::CodedOutputStream* output) { + return output->WriteVarint32(value); +} +inline bool WireFormat::WriteUInt64NoTag(uint64 value, + io::CodedOutputStream* output) { + return output->WriteVarint64(value); +} +inline bool WireFormat::WriteSInt32NoTag(int32 value, + io::CodedOutputStream* output) { + return output->WriteVarint32(ZigZagEncode32(value)); +} +inline bool WireFormat::WriteSInt64NoTag(int64 value, + io::CodedOutputStream* output) { + return output->WriteVarint64(ZigZagEncode64(value)); +} +inline bool WireFormat::WriteFixed32NoTag(uint32 value, + io::CodedOutputStream* output) { + return output->WriteLittleEndian32(value); +} +inline bool WireFormat::WriteFixed64NoTag(uint64 value, + io::CodedOutputStream* output) { + return output->WriteLittleEndian64(value); +} +inline bool WireFormat::WriteSFixed32NoTag(int32 value, + io::CodedOutputStream* output) { + return output->WriteLittleEndian32(static_cast<uint32>(value)); +} +inline bool WireFormat::WriteSFixed64NoTag(int64 value, + io::CodedOutputStream* output) { + return output->WriteLittleEndian64(static_cast<uint64>(value)); +} +inline bool WireFormat::WriteFloatNoTag(float value, + io::CodedOutputStream* output) { + return output->WriteLittleEndian32(EncodeFloat(value)); +} +inline bool WireFormat::WriteDoubleNoTag(double value, + io::CodedOutputStream* output) { + return output->WriteLittleEndian64(EncodeDouble(value)); +} +inline bool WireFormat::WriteBoolNoTag(bool value, + io::CodedOutputStream* output) { + return output->WriteVarint32(value ? 1 : 0); +} +inline bool WireFormat::WriteEnumNoTag(int value, + io::CodedOutputStream* output) { + return output->WriteVarint32SignExtended(value); +} + inline bool WireFormat::WriteInt32(int field_number, int32 value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_VARINT, output) && - output->WriteVarint32SignExtended(value); + WriteInt32NoTag(value, output); } inline bool WireFormat::WriteInt64(int field_number, int64 value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_VARINT, output) && - output->WriteVarint64(static_cast<uint64>(value)); + WriteInt64NoTag(value, output); } inline bool WireFormat::WriteUInt32(int field_number, uint32 value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_VARINT, output) && - output->WriteVarint32(value); + WriteUInt32NoTag(value, output); } inline bool WireFormat::WriteUInt64(int field_number, uint64 value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_VARINT, output) && - output->WriteVarint64(value); + WriteUInt64NoTag(value, output); } inline bool WireFormat::WriteSInt32(int field_number, int32 value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_VARINT, output) && - output->WriteVarint32(ZigZagEncode32(value)); + WriteSInt32NoTag(value, output); } inline bool WireFormat::WriteSInt64(int field_number, int64 value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_VARINT, output) && - output->WriteVarint64(ZigZagEncode64(value)); + WriteSInt64NoTag(value, output); } inline bool WireFormat::WriteFixed32(int field_number, uint32 value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_FIXED32, output) && - output->WriteLittleEndian32(value); + WriteFixed32NoTag(value, output); } inline bool WireFormat::WriteFixed64(int field_number, uint64 value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_FIXED64, output) && - output->WriteLittleEndian64(value); + WriteFixed64NoTag(value, output); } inline bool WireFormat::WriteSFixed32(int field_number, int32 value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_FIXED32, output) && - output->WriteLittleEndian32(static_cast<uint32>(value)); + WriteSFixed32NoTag(value, output); } inline bool WireFormat::WriteSFixed64(int field_number, int64 value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_FIXED64, output) && - output->WriteLittleEndian64(static_cast<uint64>(value)); + WriteSFixed64NoTag(value, output); } inline bool WireFormat::WriteFloat(int field_number, float value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_FIXED32, output) && - output->WriteLittleEndian32(EncodeFloat(value)); + WriteFloatNoTag(value, output); } inline bool WireFormat::WriteDouble(int field_number, double value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_FIXED64, output) && - output->WriteLittleEndian64(EncodeDouble(value)); + WriteDoubleNoTag(value, output); } inline bool WireFormat::WriteBool(int field_number, bool value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_VARINT, output) && - output->WriteVarint32(value ? 1 : 0); + WriteBoolNoTag(value, output); } inline bool WireFormat::WriteEnum(int field_number, int value, io::CodedOutputStream* output) { return WriteTag(field_number, WIRETYPE_VARINT, output) && - output->WriteVarint32SignExtended(value); + WriteEnumNoTag(value, output); } inline bool WireFormat::WriteString(int field_number, const string& value, diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc index 43dccd1a..5a7c6c23 100644 --- a/src/google/protobuf/wire_format_unittest.cc +++ b/src/google/protobuf/wire_format_unittest.cc @@ -90,6 +90,40 @@ TEST(WireFormatTest, ParseExtensions) { TestUtil::ExpectAllExtensionsSet(dest); } +TEST(WireFormatTest, ParsePacked) { + unittest::TestPackedTypes source, dest; + string data; + + // Serialize using the generated code. + TestUtil::SetPackedFields(&source); + source.SerializeToString(&data); + + // Parse using WireFormat. + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + WireFormat::ParseAndMergePartial(&input, &dest); + + // Check. + TestUtil::ExpectPackedFieldsSet(dest); +} + +TEST(WireFormatTest, ParsePackedExtensions) { + unittest::TestPackedExtensions source, dest; + string data; + + // Serialize using the generated code. + TestUtil::SetPackedExtensions(&source); + source.SerializeToString(&data); + + // Parse using WireFormat. + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + WireFormat::ParseAndMergePartial(&input, &dest); + + // Check. + TestUtil::ExpectPackedExtensionsSet(dest); +} + TEST(WireFormatTest, ByteSize) { unittest::TestAllTypes message; TestUtil::SetAllFields(&message); @@ -111,6 +145,27 @@ TEST(WireFormatTest, ByteSizeExtensions) { EXPECT_EQ(0, WireFormat::ByteSize(message)); } +TEST(WireFormatTest, ByteSizePacked) { + unittest::TestPackedTypes message; + TestUtil::SetPackedFields(&message); + + EXPECT_EQ(message.ByteSize(), WireFormat::ByteSize(message)); + message.Clear(); + EXPECT_EQ(0, message.ByteSize()); + EXPECT_EQ(0, WireFormat::ByteSize(message)); +} + +TEST(WireFormatTest, ByteSizePackedExtensions) { + unittest::TestPackedExtensions message; + TestUtil::SetPackedExtensions(&message); + + EXPECT_EQ(message.ByteSize(), + WireFormat::ByteSize(message)); + message.Clear(); + EXPECT_EQ(0, message.ByteSize()); + EXPECT_EQ(0, WireFormat::ByteSize(message)); +} + TEST(WireFormatTest, Serialize) { unittest::TestAllTypes message; string generated_data; |