aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xgenerate_descriptor_proto.sh1
-rw-r--r--javanano/README.md23
-rw-r--r--javanano/pom.xml15
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java264
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java28
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/Extension.java33
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/FieldArray.java34
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/FieldData.java52
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/InternalNano.java8
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/MessageNano.java8
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java4
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java4
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/NanoTest.java80
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto4
-rw-r--r--protoc-artifacts/README.md10
-rwxr-xr-xprotoc-artifacts/build-protoc.sh5
-rw-r--r--ruby/.gitignore2
-rw-r--r--ruby/Gemfile.lock2
-rw-r--r--ruby/README.md7
-rw-r--r--ruby/Rakefile3
-rw-r--r--ruby/ext/google/protobuf_c/repeated_field.c20
-rw-r--r--ruby/ext/google/protobuf_c/storage.c4
-rw-r--r--ruby/google-protobuf.gemspec3
-rw-r--r--ruby/lib/google/protobuf.rb2
-rw-r--r--ruby/lib/google/protobuf/repeated_field.rb40
-rw-r--r--ruby/pom.xml2
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java29
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java24
-rw-r--r--ruby/tests/basic.rb57
-rw-r--r--src/Makefile.am12
-rw-r--r--src/google/protobuf/any.proto12
-rw-r--r--src/google/protobuf/api.proto104
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum.cc40
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum_field.cc32
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum_field.h1
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_extension.cc2
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_field.h1
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_generator.cc6
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message.cc91
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message.h2
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message_field.cc29
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message_field.h3
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_params.h20
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_primitive_field.cc8
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_primitive_field.h1
-rw-r--r--src/google/protobuf/duration.proto10
-rw-r--r--src/google/protobuf/empty.proto49
-rw-r--r--src/google/protobuf/source_context.proto45
-rw-r--r--src/google/protobuf/struct.proto17
-rw-r--r--src/google/protobuf/timestamp.proto13
-rw-r--r--src/google/protobuf/type.proto196
51 files changed, 1310 insertions, 152 deletions
diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh
index b25a3c6a..2dad36ab 100755
--- a/generate_descriptor_proto.sh
+++ b/generate_descriptor_proto.sh
@@ -27,6 +27,7 @@ __EOF__
fi
cd src
+make $@ google/protobuf/stubs/pbconfig.h
CORE_PROTO_IS_CORRECT=0
while [ $CORE_PROTO_IS_CORRECT -ne 1 ]
do
diff --git a/javanano/README.md b/javanano/README.md
index 7d696aa7..e19b90b1 100644
--- a/javanano/README.md
+++ b/javanano/README.md
@@ -145,6 +145,7 @@ optional_field_style -> default or accessors
enum_style -> c or java
ignore_services -> true or false
parcelable_messages -> true or false
+generate_intdefs -> true or false
```
**java_package=\<file-name\>|\<package-name\>** (no default)
@@ -302,6 +303,28 @@ parcelable_messages -> true or false
Android-specific option to generate Parcelable messages.
+**generate_intdefs={true,false}** (default: false)
+ Android-specific option to generate @IntDef annotations for enums.
+
+ If turned on, an '@IntDef' annotation (a public @interface) will be
+ generated for each enum, and every integer parameter and return
+ value in the generated code meant for this enum will be annotated
+ with it. This interface is generated with the same name and at the
+ same place as the enum members' container interfaces described
+ above under 'enum_style=java', regardless of the enum_style option
+ used. When this is combined with enum_style=java, the interface
+ will be both the '@IntDef' annotation and the container of the enum
+ members; otherwise the interface has an empty body.
+
+ Your app must declare a compile-time dependency on the
+ android-support-annotations library.
+
+ For more information on how these @IntDef annotations help with
+ compile-time type safety, see:
+ https://sites.google.com/a/android.com/tools/tech-docs/support-annotations
+ and
+ https://developer.android.com/reference/android/support/annotation/IntDef.html
+
To use nano protobufs within the Android repo:
----------------------------------------------
diff --git a/javanano/pom.xml b/javanano/pom.xml
index 7a2be9df..3d8cfb9f 100644
--- a/javanano/pom.xml
+++ b/javanano/pom.xml
@@ -97,19 +97,19 @@
<arg value="src/test/java/com/google/protobuf/nano/map_test.proto" />
</exec>
<exec executable="../src/protoc">
- <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true:target/generated-test-sources" />
+ <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true,generate_clone=true:target/generated-test-sources" />
<arg value="--proto_path=src/test/java/com" />
<arg value="src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto" />
<arg value="src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto" />
<arg value="src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto" />
</exec>
<exec executable="../src/protoc">
- <arg value="--javanano_out=store_unknown_fields=true:target/generated-test-sources" />
+ <arg value="--javanano_out=store_unknown_fields=true,generate_clone=true:target/generated-test-sources" />
<arg value="--proto_path=src/test/java/com" />
<arg value="src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto" />
</exec>
<exec executable="../src/protoc">
- <arg value="--javanano_out=java_nano_generate_has=true,generate_equals=true:target/generated-test-sources" />
+ <arg value="--javanano_out=java_nano_generate_has=true,generate_equals=true,generate_clone=true:target/generated-test-sources" />
<arg value="--proto_path=src/test/java/com" />
<arg value="src/test/java/com/google/protobuf/nano/unittest_has_nano.proto" />
</exec>
@@ -139,6 +139,15 @@
<arg value="--proto_path=src/test/java/com" />
<arg value="src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto" />
</exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=
+ optional_field_style=reftypes_compat_mode,
+ generate_equals=true,
+ java_outer_classname=google/protobuf/nano/unittest_reference_types_nano.proto|NanoReferenceTypesCompat
+ :target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto" />
+ </exec>
</tasks>
<testSourceRoot>target/generated-test-sources</testSourceRoot>
</configuration>
diff --git a/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
index 35907183..b1b0c53a 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
@@ -31,6 +31,9 @@
package com.google.protobuf.nano;
import java.io.IOException;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
/**
* Encodes and writes protocol message fields.
@@ -47,15 +50,17 @@ import java.io.IOException;
* @author kneton@google.com Kenton Varda
*/
public final class CodedOutputByteBufferNano {
- private final byte[] buffer;
- private final int limit;
- private int position;
+ /* max bytes per java UTF-16 char in UTF-8 */
+ private static final int MAX_UTF8_EXPANSION = 3;
+ private final ByteBuffer buffer;
private CodedOutputByteBufferNano(final byte[] buffer, final int offset,
final int length) {
+ this(ByteBuffer.wrap(buffer, offset, length));
+ }
+
+ private CodedOutputByteBufferNano(final ByteBuffer buffer) {
this.buffer = buffer;
- position = offset;
- limit = offset + length;
}
/**
@@ -287,14 +292,213 @@ public final class CodedOutputByteBufferNano {
/** Write a {@code string} field to the stream. */
public void writeStringNoTag(final 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.
- final byte[] bytes = value.getBytes(InternalNano.UTF_8);
- writeRawVarint32(bytes.length);
- writeRawBytes(bytes);
+ // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+ // and at most 3 times of it. Optimize for the case where we know this length results in a
+ // constant varint length - saves measuring length of the string.
+ try {
+ final int minLengthVarIntSize = computeRawVarint32Size(value.length());
+ final int maxLengthVarIntSize = computeRawVarint32Size(value.length() * MAX_UTF8_EXPANSION);
+ if (minLengthVarIntSize == maxLengthVarIntSize) {
+ int oldPosition = buffer.position();
+ // Buffer.position, when passed a position that is past its limit, throws
+ // IllegalArgumentException, and this class is documented to throw
+ // OutOfSpaceException instead.
+ if (buffer.remaining() < minLengthVarIntSize) {
+ throw new OutOfSpaceException(oldPosition + minLengthVarIntSize, buffer.limit());
+ }
+ buffer.position(oldPosition + minLengthVarIntSize);
+ encode(value, buffer);
+ int newPosition = buffer.position();
+ buffer.position(oldPosition);
+ writeRawVarint32(newPosition - oldPosition - minLengthVarIntSize);
+ buffer.position(newPosition);
+ } else {
+ writeRawVarint32(encodedLength(value));
+ encode(value, buffer);
+ }
+ } catch (BufferOverflowException e) {
+ final OutOfSpaceException outOfSpaceException = new OutOfSpaceException(buffer.position(),
+ buffer.limit());
+ outOfSpaceException.initCause(e);
+ throw outOfSpaceException;
+ }
+ }
+
+ // These UTF-8 handling methods are copied from Guava's Utf8 class.
+ /**
+ * Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string,
+ * this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in
+ * both time and space.
+ *
+ * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
+ * surrogates)
+ */
+ private static int encodedLength(CharSequence sequence) {
+ // Warning to maintainers: this implementation is highly optimized.
+ int utf16Length = sequence.length();
+ int utf8Length = utf16Length;
+ int i = 0;
+
+ // This loop optimizes for pure ASCII.
+ while (i < utf16Length && sequence.charAt(i) < 0x80) {
+ i++;
+ }
+
+ // This loop optimizes for chars less than 0x800.
+ for (; i < utf16Length; i++) {
+ char c = sequence.charAt(i);
+ if (c < 0x800) {
+ utf8Length += ((0x7f - c) >>> 31); // branch free!
+ } else {
+ utf8Length += encodedLengthGeneral(sequence, i);
+ break;
+ }
+ }
+
+ if (utf8Length < utf16Length) {
+ // Necessary and sufficient condition for overflow because of maximum 3x expansion
+ throw new IllegalArgumentException("UTF-8 length does not fit in int: "
+ + (utf8Length + (1L << 32)));
+ }
+ return utf8Length;
+ }
+
+ private static int encodedLengthGeneral(CharSequence sequence, int start) {
+ int utf16Length = sequence.length();
+ int utf8Length = 0;
+ for (int i = start; i < utf16Length; i++) {
+ char c = sequence.charAt(i);
+ if (c < 0x800) {
+ utf8Length += (0x7f - c) >>> 31; // branch free!
+ } else {
+ utf8Length += 2;
+ // jdk7+: if (Character.isSurrogate(c)) {
+ if (Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) {
+ // Check that we have a well-formed surrogate pair.
+ int cp = Character.codePointAt(sequence, i);
+ if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+ throw new IllegalArgumentException("Unpaired surrogate at index " + i);
+ }
+ i++;
+ }
+ }
+ }
+ return utf8Length;
}
+ /**
+ * Encodes {@code sequence} into UTF-8, in {@code byteBuffer}. For a string, this method is
+ * equivalent to {@code buffer.put(string.getBytes(UTF_8))}, but is more efficient in both time
+ * and space. Bytes are written starting at the current position. This method requires paired
+ * surrogates, and therefore does not support chunking.
+ *
+ * <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to
+ * compute the exact amount needed, or leave room for {@code 3 * sequence.length()}, which is the
+ * largest possible number of bytes that any input can be encoded to.
+ *
+ * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
+ * surrogates)
+ * @throws BufferOverflowException if {@code sequence} encoded in UTF-8 does not fit in
+ * {@code byteBuffer}'s remaining space.
+ * @throws ReadOnlyBufferException if {@code byteBuffer} is a read-only buffer.
+ */
+ private static void encode(CharSequence sequence, ByteBuffer byteBuffer) {
+ if (byteBuffer.isReadOnly()) {
+ throw new ReadOnlyBufferException();
+ } else if (byteBuffer.hasArray()) {
+ try {
+ int encoded = encode(sequence,
+ byteBuffer.array(),
+ byteBuffer.arrayOffset() + byteBuffer.position(),
+ byteBuffer.remaining());
+ byteBuffer.position(encoded - byteBuffer.arrayOffset());
+ } catch (ArrayIndexOutOfBoundsException e) {
+ BufferOverflowException boe = new BufferOverflowException();
+ boe.initCause(e);
+ throw boe;
+ }
+ } else {
+ encodeDirect(sequence, byteBuffer);
+ }
+ }
+
+ private static void encodeDirect(CharSequence sequence, ByteBuffer byteBuffer) {
+ int utf16Length = sequence.length();
+ for (int i = 0; i < utf16Length; i++) {
+ final char c = sequence.charAt(i);
+ if (c < 0x80) { // ASCII
+ byteBuffer.put((byte) c);
+ } else if (c < 0x800) { // 11 bits, two UTF-8 bytes
+ byteBuffer.put((byte) ((0xF << 6) | (c >>> 6)));
+ byteBuffer.put((byte) (0x80 | (0x3F & c)));
+ } else if (c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) {
+ // Maximium single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+ byteBuffer.put((byte) ((0xF << 5) | (c >>> 12)));
+ byteBuffer.put((byte) (0x80 | (0x3F & (c >>> 6))));
+ byteBuffer.put((byte) (0x80 | (0x3F & c)));
+ } else {
+ final char low;
+ if (i + 1 == sequence.length()
+ || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
+ throw new IllegalArgumentException("Unpaired surrogate at index " + (i - 1));
+ }
+ int codePoint = Character.toCodePoint(c, low);
+ byteBuffer.put((byte) ((0xF << 4) | (codePoint >>> 18)));
+ byteBuffer.put((byte) (0x80 | (0x3F & (codePoint >>> 12))));
+ byteBuffer.put((byte) (0x80 | (0x3F & (codePoint >>> 6))));
+ byteBuffer.put((byte) (0x80 | (0x3F & codePoint)));
+ }
+ }
+ }
+
+ private static int encode(CharSequence sequence, byte[] bytes, int offset, int length) {
+ int utf16Length = sequence.length();
+ int j = offset;
+ int i = 0;
+ int limit = offset + length;
+ // Designed to take advantage of
+ // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+ for (char c; i < utf16Length && i + j < limit && (c = sequence.charAt(i)) < 0x80; i++) {
+ bytes[j + i] = (byte) c;
+ }
+ if (i == utf16Length) {
+ return j + utf16Length;
+ }
+ j += i;
+ for (char c; i < utf16Length; i++) {
+ c = sequence.charAt(i);
+ if (c < 0x80 && j < limit) {
+ bytes[j++] = (byte) c;
+ } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes
+ bytes[j++] = (byte) ((0xF << 6) | (c >>> 6));
+ bytes[j++] = (byte) (0x80 | (0x3F & c));
+ } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) {
+ // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+ bytes[j++] = (byte) ((0xF << 5) | (c >>> 12));
+ bytes[j++] = (byte) (0x80 | (0x3F & (c >>> 6)));
+ bytes[j++] = (byte) (0x80 | (0x3F & c));
+ } else if (j <= limit - 4) {
+ // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8 bytes
+ final char low;
+ if (i + 1 == sequence.length()
+ || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
+ throw new IllegalArgumentException("Unpaired surrogate at index " + (i - 1));
+ }
+ int codePoint = Character.toCodePoint(c, low);
+ bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
+ bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
+ bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
+ bytes[j++] = (byte) (0x80 | (0x3F & codePoint));
+ } else {
+ throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
+ }
+ }
+ return j;
+ }
+
+ // End guava UTF-8 methods
+
+
/** Write a {@code group} field to the stream. */
public void writeGroupNoTag(final MessageNano value) throws IOException {
value.writeTo(this);
@@ -602,9 +806,8 @@ public final class CodedOutputByteBufferNano {
* {@code string} field.
*/
public static int computeStringSizeNoTag(final String value) {
- final byte[] bytes = value.getBytes(InternalNano.UTF_8);
- return computeRawVarint32Size(bytes.length) +
- bytes.length;
+ final int length = encodedLength(value);
+ return computeRawVarint32Size(length) + length;
}
/**
@@ -687,7 +890,7 @@ public final class CodedOutputByteBufferNano {
* Otherwise, throws {@code UnsupportedOperationException}.
*/
public int spaceLeft() {
- return limit - position;
+ return buffer.remaining();
}
/**
@@ -705,6 +908,23 @@ public final class CodedOutputByteBufferNano {
}
/**
+ * Returns the position within the internal buffer.
+ */
+ public int position() {
+ return buffer.position();
+ }
+
+ /**
+ * Resets the position within the internal buffer to zero.
+ *
+ * @see #position
+ * @see #spaceLeft
+ */
+ public void reset() {
+ buffer.clear();
+ }
+
+ /**
* If you create a CodedOutputStream around a simple flat array, you must
* not attempt to write more bytes than the array has space. Otherwise,
* this exception will be thrown.
@@ -720,12 +940,12 @@ public final class CodedOutputByteBufferNano {
/** Write a single byte. */
public void writeRawByte(final byte value) throws IOException {
- if (position == limit) {
+ if (!buffer.hasRemaining()) {
// We're writing to a single buffer.
- throw new OutOfSpaceException(position, limit);
+ throw new OutOfSpaceException(buffer.position(), buffer.limit());
}
- buffer[position++] = value;
+ buffer.put(value);
}
/** Write a single byte, represented by an integer value. */
@@ -741,13 +961,11 @@ public final class CodedOutputByteBufferNano {
/** Write part of an array of bytes. */
public void writeRawBytes(final byte[] value, int offset, int length)
throws IOException {
- if (limit - position >= length) {
- // We have room in the current buffer.
- System.arraycopy(value, offset, buffer, position, length);
- position += length;
+ if (buffer.remaining() >= length) {
+ buffer.put(value, offset, length);
} else {
// We're writing to a single buffer.
- throw new OutOfSpaceException(position, limit);
+ throw new OutOfSpaceException(buffer.position(), buffer.limit());
}
}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java b/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
index b979390d..87973d76 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
@@ -160,28 +160,10 @@ public abstract class ExtendableMessageNano<M extends ExtendableMessageNano<M>>
return true;
}
- /**
- * Returns whether the stored unknown field data in this message is equivalent to that in the
- * other message.
- *
- * @param other the other message.
- * @return whether the two sets of unknown field data are equal.
- */
- protected final boolean unknownFieldDataEquals(M other) {
- if (unknownFieldData == null || unknownFieldData.isEmpty()) {
- return other.unknownFieldData == null || other.unknownFieldData.isEmpty();
- } else {
- return unknownFieldData.equals(other.unknownFieldData);
- }
- }
-
- /**
- * Computes the hashcode representing the unknown field data stored in this message.
- *
- * @return the hashcode for the unknown field data.
- */
- protected final int unknownFieldDataHashCode() {
- return (unknownFieldData == null || unknownFieldData.isEmpty()
- ? 0 : unknownFieldData.hashCode());
+ @Override
+ public M clone() throws CloneNotSupportedException {
+ M cloned = (M) super.clone();
+ InternalNano.cloneUnknownFieldData(this, cloned);
+ return cloned;
}
}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/Extension.java b/javanano/src/main/java/com/google/protobuf/nano/Extension.java
index c29b030f..c458f9b1 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/Extension.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/Extension.java
@@ -79,12 +79,30 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
* Should be used by the generated code only.
*
* @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
+ * @deprecated use {@link #createMessageTyped(int, Class, long)} instead.
*/
+ @Deprecated
public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
Extension<M, T> createMessageTyped(int type, Class<T> clazz, int tag) {
return new Extension<M, T>(type, clazz, tag, false);
}
+ // Note: these create...() methods take a long for the tag parameter,
+ // because tags are represented as unsigned ints, and these values exist
+ // in generated code as long values. However, they can fit in 32-bits, so
+ // it's safe to cast them to int without loss of precision.
+
+ /**
+ * Creates an {@code Extension} of the given message type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
+ */
+ public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
+ Extension<M, T> createMessageTyped(int type, Class<T> clazz, long tag) {
+ return new Extension<M, T>(type, clazz, (int) tag, false);
+ }
+
/**
* Creates a repeated {@code Extension} of the given message type and tag number.
* Should be used by the generated code only.
@@ -92,8 +110,8 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
* @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
*/
public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
- Extension<M, T[]> createRepeatedMessageTyped(int type, Class<T[]> clazz, int tag) {
- return new Extension<M, T[]>(type, clazz, tag, true);
+ Extension<M, T[]> createRepeatedMessageTyped(int type, Class<T[]> clazz, long tag) {
+ return new Extension<M, T[]>(type, clazz, (int) tag, true);
}
/**
@@ -104,8 +122,8 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
* @param clazz the boxed Java type of this extension
*/
public static <M extends ExtendableMessageNano<M>, T>
- Extension<M, T> createPrimitiveTyped(int type, Class<T> clazz, int tag) {
- return new PrimitiveExtension<M, T>(type, clazz, tag, false, 0, 0);
+ Extension<M, T> createPrimitiveTyped(int type, Class<T> clazz, long tag) {
+ return new PrimitiveExtension<M, T>(type, clazz, (int) tag, false, 0, 0);
}
/**
@@ -117,8 +135,9 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
*/
public static <M extends ExtendableMessageNano<M>, T>
Extension<M, T> createRepeatedPrimitiveTyped(
- int type, Class<T> clazz, int tag, int nonPackedTag, int packedTag) {
- return new PrimitiveExtension<M, T>(type, clazz, tag, true, nonPackedTag, packedTag);
+ int type, Class<T> clazz, long tag, long nonPackedTag, long packedTag) {
+ return new PrimitiveExtension<M, T>(type, clazz, (int) tag, true,
+ (int) nonPackedTag, (int) packedTag);
}
/**
@@ -136,7 +155,7 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
protected final Class<T> clazz;
/**
- * Tag number of this extension.
+ * Tag number of this extension. The data should be viewed as an unsigned 32-bit value.
*/
public final int tag;
diff --git a/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
index cdb66da2..eca9c0d9 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
@@ -35,9 +35,12 @@ package com.google.protobuf.nano;
* A custom version of {@link android.util.SparseArray} with the minimal API
* for storing {@link FieldData} objects.
*
+ * <p>This class is an internal implementation detail of nano and should not
+ * be called directly by clients.
+ *
* Based on {@link android.support.v4.util.SpareArrayCompat}.
*/
-class FieldArray {
+public final class FieldArray implements Cloneable {
private static final FieldData DELETED = new FieldData();
private boolean mGarbage = false;
@@ -48,7 +51,7 @@ class FieldArray {
/**
* Creates a new FieldArray containing no fields.
*/
- public FieldArray() {
+ FieldArray() {
this(10);
}
@@ -57,7 +60,7 @@ class FieldArray {
* require any additional memory allocation to store the specified
* number of mappings.
*/
- public FieldArray(int initialCapacity) {
+ FieldArray(int initialCapacity) {
initialCapacity = idealIntArraySize(initialCapacity);
mFieldNumbers = new int[initialCapacity];
mData = new FieldData[initialCapacity];
@@ -68,7 +71,7 @@ class FieldArray {
* Gets the FieldData mapped from the specified fieldNumber, or <code>null</code>
* if no such mapping has been made.
*/
- public FieldData get(int fieldNumber) {
+ FieldData get(int fieldNumber) {
int i = binarySearch(fieldNumber);
if (i < 0 || mData[i] == DELETED) {
@@ -81,7 +84,7 @@ class FieldArray {
/**
* Removes the data from the specified fieldNumber, if there was any.
*/
- public void remove(int fieldNumber) {
+ void remove(int fieldNumber) {
int i = binarySearch(fieldNumber);
if (i >= 0 && mData[i] != DELETED) {
@@ -118,7 +121,7 @@ class FieldArray {
* Adds a mapping from the specified fieldNumber to the specified data,
* replacing the previous mapping if there was one.
*/
- public void put(int fieldNumber, FieldData data) {
+ void put(int fieldNumber, FieldData data) {
int i = binarySearch(fieldNumber);
if (i >= 0) {
@@ -167,7 +170,7 @@ class FieldArray {
* Returns the number of key-value mappings that this FieldArray
* currently stores.
*/
- public int size() {
+ int size() {
if (mGarbage) {
gc();
}
@@ -184,7 +187,7 @@ class FieldArray {
* the value from the <code>index</code>th key-value mapping that this
* FieldArray stores.
*/
- public FieldData dataAt(int index) {
+ FieldData dataAt(int index) {
if (mGarbage) {
gc();
}
@@ -270,4 +273,19 @@ class FieldArray {
}
return true;
}
+
+ @Override
+ public final FieldArray clone() {
+ // Trigger GC so we compact and don't copy DELETED elements.
+ int size = size();
+ FieldArray clone = new FieldArray(size);
+ System.arraycopy(mFieldNumbers, 0, clone.mFieldNumbers, 0, size);
+ for (int i = 0; i < size; i++) {
+ if (mData[i] != null) {
+ clone.mData[i] = mData[i].clone();
+ }
+ }
+ clone.mSize = size;
+ return clone;
+ }
}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/FieldData.java b/javanano/src/main/java/com/google/protobuf/nano/FieldData.java
index 21ead88b..ebebabc8 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/FieldData.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/FieldData.java
@@ -39,7 +39,7 @@ import java.util.List;
* Stores unknown fields. These might be extensions or fields that the generated API doesn't
* know about yet.
*/
-class FieldData {
+class FieldData implements Cloneable {
private Extension<?, ?> cachedExtension;
private Object value;
/** The serialised values for this object. Will be cleared if getValue is called */
@@ -187,4 +187,54 @@ class FieldData {
return result;
}
+ @Override
+ public final FieldData clone() {
+ FieldData clone = new FieldData();
+ try {
+ clone.cachedExtension = cachedExtension;
+ if (unknownFieldData == null) {
+ clone.unknownFieldData = null;
+ } else {
+ clone.unknownFieldData.addAll(unknownFieldData);
+ }
+
+ // Whether we need to deep clone value depends on its type. Primitive reference types
+ // (e.g. Integer, Long etc.) are ok, since they're immutable. We need to clone arrays
+ // and messages.
+ if (value == null) {
+ // No cloning required.
+ } else if (value instanceof MessageNano) {
+ clone.value = ((MessageNano) value).clone();
+ } else if (value instanceof byte[]) {
+ clone.value = ((byte[]) value).clone();
+ } else if (value instanceof byte[][]) {
+ byte[][] valueArray = (byte[][]) value;
+ byte[][] cloneArray = new byte[valueArray.length][];
+ clone.value = cloneArray;
+ for (int i = 0; i < valueArray.length; i++) {
+ cloneArray[i] = valueArray[i].clone();
+ }
+ } else if (value instanceof boolean[]) {
+ clone.value = ((boolean[]) value).clone();
+ } else if (value instanceof int[]) {
+ clone.value = ((int[]) value).clone();
+ } else if (value instanceof long[]) {
+ clone.value = ((long[]) value).clone();
+ } else if (value instanceof float[]) {
+ clone.value = ((float[]) value).clone();
+ } else if (value instanceof double[]) {
+ clone.value = ((double[]) value).clone();
+ } else if (value instanceof MessageNano[]) {
+ MessageNano[] valueArray = (MessageNano[]) value;
+ MessageNano[] cloneArray = new MessageNano[valueArray.length];
+ clone.value = cloneArray;
+ for (int i = 0; i < valueArray.length; i++) {
+ cloneArray[i] = valueArray[i].clone();
+ }
+ }
+ return clone;
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
index e7ba8d12..f1263df5 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
@@ -536,4 +536,12 @@ public final class InternalNano {
}
return o.hashCode();
}
+
+ // This avoids having to make FieldArray public.
+ public static void cloneUnknownFieldData(ExtendableMessageNano original,
+ ExtendableMessageNano cloned) {
+ if (original.unknownFieldData != null) {
+ cloned.unknownFieldData = (FieldArray) original.unknownFieldData.clone();
+ }
+ }
}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java b/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java
index 81e58571..23475027 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java
@@ -187,4 +187,12 @@ public abstract class MessageNano {
public String toString() {
return MessageNanoPrinter.print(this);
}
+
+ /**
+ * Provides support for cloning. This only works if you specify the generate_clone method.
+ */
+ @Override
+ public MessageNano clone() throws CloneNotSupportedException {
+ return (MessageNano) super.clone();
+ }
}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
index c4b2ad3d..d9500bb9 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
@@ -109,6 +109,10 @@ public final class MessageNanoPrinter {
for (Field field : clazz.getFields()) {
int modifiers = field.getModifiers();
String fieldName = field.getName();
+ if ("cachedSize".equals(fieldName)) {
+ // TODO(bduff): perhaps cachedSize should have a more obscure name.
+ continue;
+ }
if ((modifiers & Modifier.PUBLIC) == Modifier.PUBLIC
&& (modifiers & Modifier.STATIC) != Modifier.STATIC
diff --git a/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java b/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
index a17fccf3..b1678d1b 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
@@ -42,6 +42,10 @@ import java.util.Arrays;
final class UnknownFieldData {
final int tag;
+ /**
+ * Important: this should be treated as immutable, even though it's possible
+ * to change the array values.
+ */
final byte[] bytes;
UnknownFieldData(int tag, byte[] bytes) {
diff --git a/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
index 7de84310..3a75777a 100644
--- a/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
+++ b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
@@ -31,11 +31,13 @@
package com.google.protobuf.nano;
import com.google.protobuf.nano.MapTestProto.TestMap;
+import com.google.protobuf.nano.CodedOutputByteBufferNano;
import com.google.protobuf.nano.MapTestProto.TestMap.MessageValue;
import com.google.protobuf.nano.NanoAccessorsOuterClass.TestNanoAccessors;
import com.google.protobuf.nano.NanoHasOuterClass.TestAllTypesNanoHas;
import com.google.protobuf.nano.NanoOuterClass.TestAllTypesNano;
import com.google.protobuf.nano.UnittestRecursiveNano.RecursiveMessageNano;
+import com.google.protobuf.nano.NanoReferenceTypesCompat;
import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano;
import com.google.protobuf.nano.UnittestSingleNano.SingleMessageNano;
import com.google.protobuf.nano.testext.Extensions;
@@ -2300,6 +2302,59 @@ public class NanoTest extends TestCase {
}
}
+ public void testDifferentStringLengthsNano() throws Exception {
+ // Test string serialization roundtrip using strings of the following lengths,
+ // with ASCII and Unicode characters requiring different UTF-8 byte counts per
+ // char, hence causing the length delimiter varint to sometimes require more
+ // bytes for the Unicode strings than the ASCII string of the same length.
+ int[] lengths = new int[] {
+ 0,
+ 1,
+ (1 << 4) - 1, // 1 byte for ASCII and Unicode
+ (1 << 7) - 1, // 1 byte for ASCII, 2 bytes for Unicode
+ (1 << 11) - 1, // 2 bytes for ASCII and Unicode
+ (1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode
+ (1 << 17) - 1, // 3 bytes for ASCII and Unicode
+ };
+ for (int i : lengths) {
+ testEncodingOfString('q', i); // 1 byte per char
+ testEncodingOfString('\u07FF', i); // 2 bytes per char
+ testEncodingOfString('\u0981', i); // 3 bytes per char
+ }
+ }
+
+ /** Regression test for https://github.com/google/protobuf/issues/292 */
+ public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() throws Exception {
+ String testCase = "Foooooooo";
+ assertEquals(CodedOutputByteBufferNano.computeRawVarint32Size(testCase.length()),
+ CodedOutputByteBufferNano.computeRawVarint32Size(testCase.length() * 3));
+ assertEquals(11, CodedOutputByteBufferNano.computeStringSize(1, testCase));
+ // Tag is one byte, varint describing string length is 1 byte, string length is 9 bytes.
+ // An array of size 1 will cause a failure when trying to write the varint.
+ for (int i = 0; i < 11; i++) {
+ CodedOutputByteBufferNano bufferNano = CodedOutputByteBufferNano.newInstance(new byte[i]);
+ try {
+ bufferNano.writeString(1, testCase);
+ fail("Should have thrown an out of space exception");
+ } catch (CodedOutputByteBufferNano.OutOfSpaceException expected) {}
+ }
+ }
+
+ private void testEncodingOfString(char c, int length) throws InvalidProtocolBufferNanoException {
+ TestAllTypesNano testAllTypesNano = new TestAllTypesNano();
+ final String fullString = fullString(c, length);
+ testAllTypesNano.optionalString = fullString;
+ final TestAllTypesNano resultNano = new TestAllTypesNano();
+ MessageNano.mergeFrom(resultNano, MessageNano.toByteArray(testAllTypesNano));
+ assertEquals(fullString, resultNano.optionalString);
+ }
+
+ private String fullString(char c, int length) {
+ char[] result = new char[length];
+ Arrays.fill(result, c);
+ return new String(result);
+ }
+
public void testNanoWithHasParseFrom() throws Exception {
TestAllTypesNanoHas msg = null;
// Test false on creation, after clear and upon empty parse.
@@ -2986,6 +3041,10 @@ public class NanoTest extends TestCase {
assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat)));
assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble)));
assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum)));
+
+ // Clone the message and ensure it's still equal.
+ Extensions.ExtendableMessage clone = message.clone();
+ assertEquals(clone, message);
}
public void testNullExtensions() throws Exception {
@@ -4345,6 +4404,11 @@ public class NanoTest extends TestCase {
assertMapSet(testMap.sfixed64ToSfixed64Field, int64Values, int64Values);
}
+ public void testRepeatedFieldInitializedInReftypesCompatMode() {
+ NanoReferenceTypesCompat.TestAllTypesNano proto = new NanoReferenceTypesCompat.TestAllTypesNano();
+ assertNotNull(proto.repeatedString);
+ }
+
private void assertRepeatedPackablesEqual(
NanoRepeatedPackables.NonPacked nonPacked, NanoRepeatedPackables.Packed packed) {
// Not using MessageNano.equals() -- that belongs to a separate test.
@@ -4364,6 +4428,22 @@ public class NanoTest extends TestCase {
assertTrue(Arrays.equals(nonPacked.enums, packed.enums));
}
+ public void testClone() throws Exception {
+ // A simple message.
+ AnotherMessage anotherMessage = new AnotherMessage();
+ anotherMessage.string = "Hello";
+ anotherMessage.value = true;
+ anotherMessage.integers = new int[] { 1, 2, 3 };
+
+ AnotherMessage clone = anotherMessage.clone();
+ assertEquals(clone, anotherMessage);
+
+ // Verify it was a deep clone - changes to the clone shouldn't affect the
+ // original.
+ clone.integers[1] = 100;
+ assertFalse(clone.equals(anotherMessage));
+ }
+
private void assertHasWireData(MessageNano message, boolean expected) {
byte[] bytes = MessageNano.toByteArray(message);
int wireLength = bytes.length;
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
index 2a678a80..ca56b3dd 100644
--- a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
@@ -16,11 +16,15 @@ enum AnEnum {
message AnotherMessage {
optional string string = 1;
optional bool value = 2;
+ repeated int32 integers = 3;
}
message ContainerMessage {
extend ExtendableMessage {
optional bool another_thing = 100;
+ // The largest permitted field number, per
+ // https://developers.google.com/protocol-buffers/docs/proto#simple
+ optional bool large_field_number = 536870911;
}
}
diff --git a/protoc-artifacts/README.md b/protoc-artifacts/README.md
index 3a530197..1ed1435e 100644
--- a/protoc-artifacts/README.md
+++ b/protoc-artifacts/README.md
@@ -63,9 +63,6 @@ deployment for all platforms. Currently the following platforms are supported:
- MSYS with MinGW32 (x86_32 only)
- MacOSX (x86_32 and x86_64)
-Remove any ``SNAPSHOT`` or ``pre`` suffix from the version string before
-deploying.
-
Use the following command to deploy artifacts for the host platform to a
staging repository.
```
@@ -118,3 +115,10 @@ stored:
</activeProfiles>
</settings>
```
+
+### Tested build environments
+We have succesfully built artifacts on the following environments:
+- Linux x86_32 and x86_64: Ubuntu 14.04.2 64-bit
+- Windows x86_32: MSYS with ``mingw32-gcc-g++ 4.8.1-4`` on Windows 7 64-bit
+- Windows x86_64: Cygwin64 with ``mingw64-x86_64-gcc-g++ 4.8.3-1`` on Windows 7 64-bit
+- Mac OS X x86_32 and x86_64: Mac OS X 10.9.5
diff --git a/protoc-artifacts/build-protoc.sh b/protoc-artifacts/build-protoc.sh
index 96ca97c2..2f67c508 100755
--- a/protoc-artifacts/build-protoc.sh
+++ b/protoc-artifacts/build-protoc.sh
@@ -158,6 +158,9 @@ if [[ "$(uname)" == CYGWIN* ]]; then
elif [[ "$(uname)" == MINGW32* ]]; then
assertEq "$OS" windows $LINENO
assertEq "$ARCH" x86_32 $LINENO
+elif [[ "$(uname)" == MINGW64* ]]; then
+ assertEq "$OS" windows $LINENO
+ assertEq "$ARCH" x86_64 $LINENO
elif [[ "$(uname)" == Linux* ]]; then
if [[ "$OS" == linux ]]; then
if [[ "$ARCH" == x86_64 ]]; then
@@ -209,7 +212,7 @@ export CXXFLAGS LDFLAGS
TARGET_FILE=target/protoc.exe
cd "$WORKING_DIR"/.. && ./configure $CONFIGURE_ARGS &&
- cd src && make clean && make $MAKE_TARGET &&
+ cd src && make clean && make google/protobuf/stubs/pbconfig.h $MAKE_TARGET &&
cd "$WORKING_DIR" && mkdir -p target &&
(cp ../src/protoc $TARGET_FILE || cp ../src/protoc.exe $TARGET_FILE) ||
exit 1
diff --git a/ruby/.gitignore b/ruby/.gitignore
index 80c978f2..bd8745dd 100644
--- a/ruby/.gitignore
+++ b/ruby/.gitignore
@@ -4,3 +4,5 @@ tags
lib/google/protobuf_java.jar
protobuf-jruby.iml
target/
+pkg/
+tmp/
diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock
index 89deb47d..6f349276 100644
--- a/ruby/Gemfile.lock
+++ b/ruby/Gemfile.lock
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
- google-protobuf (3.0.0.alpha.2)
+ google-protobuf (3.0.0.alpha.3.1.pre)
GEM
remote: https://rubygems.org/
diff --git a/ruby/README.md b/ruby/README.md
index d2fa76ab..16474322 100644
--- a/ruby/README.md
+++ b/ruby/README.md
@@ -63,7 +63,7 @@ To build this Ruby extension, you will need:
To Build the JRuby extension, you will need:
* Maven
-* The latest version of the protobuf java library
+* The latest version of the protobuf java library (see ../java/README.md)
* Install JRuby via rbenv or RVM
First switch to the desired platform with rbenv or RVM.
@@ -75,8 +75,9 @@ Then install the required Ruby gems:
Then build the Gem:
- $ rake gem
- $ gem install pkg/protobuf-$VERSION.gem
+ $ rake
+ $ rake clobber_package gem
+ $ gem install `ls pkg/google-protobuf-*.gem`
To run the specs:
diff --git a/ruby/Rakefile b/ruby/Rakefile
index 7c1d8495..c25103d8 100644
--- a/ruby/Rakefile
+++ b/ruby/Rakefile
@@ -6,6 +6,9 @@ require "rake/testtask"
spec = Gem::Specification.load("google-protobuf.gemspec")
if RUBY_PLATFORM == "java"
+ if `which mvn` == ''
+ raise ArgumentError, "maven needs to be installed"
+ end
task :clean do
system("mvn clean")
end
diff --git a/ruby/ext/google/protobuf_c/repeated_field.c b/ruby/ext/google/protobuf_c/repeated_field.c
index 8cf2e29b..5148ee87 100644
--- a/ruby/ext/google/protobuf_c/repeated_field.c
+++ b/ruby/ext/google/protobuf_c/repeated_field.c
@@ -47,6 +47,15 @@ RepeatedField* ruby_to_RepeatedField(VALUE _self) {
return self;
}
+static int index_position(VALUE _index, RepeatedField* repeated_field) {
+ int index = NUM2INT(_index);
+ if (index < 0 && repeated_field->size > 0) {
+ index = repeated_field->size + index;
+ }
+ return index;
+}
+
+
/*
* call-seq:
* RepeatedField.each(&block)
@@ -74,8 +83,7 @@ VALUE RepeatedField_each(VALUE _self) {
* call-seq:
* RepeatedField.[](index) => value
*
- * Accesses the element at the given index. Throws an exception on out-of-bounds
- * errors.
+ * Accesses the element at the given index. Returns nil on out-of-bounds
*/
VALUE RepeatedField_index(VALUE _self, VALUE _index) {
RepeatedField* self = ruby_to_RepeatedField(_self);
@@ -83,9 +91,9 @@ VALUE RepeatedField_index(VALUE _self, VALUE _index) {
upb_fieldtype_t field_type = self->field_type;
VALUE field_type_class = self->field_type_class;
- int index = NUM2INT(_index);
+ int index = index_position(_index, self);
if (index < 0 || index >= self->size) {
- rb_raise(rb_eRangeError, "Index out of range");
+ return Qnil;
}
void* memory = (void *) (((uint8_t *)self->elements) + index * element_size);
@@ -105,9 +113,9 @@ VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
VALUE field_type_class = self->field_type_class;
int element_size = native_slot_size(field_type);
- int index = NUM2INT(_index);
+ int index = index_position(_index, self);
if (index < 0 || index >= (INT_MAX - 1)) {
- rb_raise(rb_eRangeError, "Index out of range");
+ return Qnil;
}
if (index >= self->size) {
RepeatedField_reserve(self, index + 1);
diff --git a/ruby/ext/google/protobuf_c/storage.c b/ruby/ext/google/protobuf_c/storage.c
index 5b1549d2..2ad8bd74 100644
--- a/ruby/ext/google/protobuf_c/storage.c
+++ b/ruby/ext/google/protobuf_c/storage.c
@@ -155,7 +155,9 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
break;
}
case UPB_TYPE_MESSAGE: {
- if (CLASS_OF(value) != type_class) {
+ if (CLASS_OF(value) == CLASS_OF(Qnil)) {
+ value = Qnil;
+ } else if (CLASS_OF(value) != type_class) {
rb_raise(rb_eTypeError,
"Invalid type %s to assign to submessage field.",
rb_class2name(CLASS_OF(value)));
diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec
index abbbde35..28cdebf5 100644
--- a/ruby/google-protobuf.gemspec
+++ b/ruby/google-protobuf.gemspec
@@ -4,10 +4,11 @@ Gem::Specification.new do |s|
s.licenses = ["BSD"]
s.summary = "Protocol Buffers"
s.description = "Protocol Buffers are Google's data interchange format."
+ s.homepage = "https://developers.google.com/protocol-buffers"
s.authors = ["Protobuf Authors"]
s.email = "protobuf@googlegroups.com"
s.require_paths = ["lib"]
- s.files = ["lib/google/protobuf.rb"]
+ s.files = `git ls-files -z`.split("\x0").find_all{|f| f =~ /lib\/.+\.rb/}
unless RUBY_PLATFORM == "java"
s.files += `git ls-files "*.c" "*.h" extconf.rb Makefile`.split
s.extensions= ["ext/google/protobuf_c/extconf.rb"]
diff --git a/ruby/lib/google/protobuf.rb b/ruby/lib/google/protobuf.rb
index 75869dd8..72797245 100644
--- a/ruby/lib/google/protobuf.rb
+++ b/ruby/lib/google/protobuf.rb
@@ -34,3 +34,5 @@ if RUBY_PLATFORM == "java"
else
require 'google/protobuf_c'
end
+
+require 'google/protobuf/repeated_field'
diff --git a/ruby/lib/google/protobuf/repeated_field.rb b/ruby/lib/google/protobuf/repeated_field.rb
new file mode 100644
index 00000000..5b934e56
--- /dev/null
+++ b/ruby/lib/google/protobuf/repeated_field.rb
@@ -0,0 +1,40 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc. All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# add syntatic sugar on top of the core library
+module Google
+ module Protobuf
+ class RepeatedField
+
+ alias_method :size, :length
+
+ end
+ end
+end
diff --git a/ruby/pom.xml b/ruby/pom.xml
index 1630fe84..01f0e16b 100644
--- a/ruby/pom.xml
+++ b/ruby/pom.xml
@@ -78,7 +78,7 @@
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
- <version>3.0.0-pre</version>
+ <version>3.0.0-alpha-3-pre</version>
</dependency>
</dependencies>
</project>
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
index 04bc0b76..c7fd7aa7 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
@@ -246,16 +246,15 @@ public class RubyMessage extends RubyObject {
public IRubyObject dup(ThreadContext context) {
RubyMessage dup = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK);
IRubyObject value;
- for (Descriptors.FieldDescriptor fieldDescriptor : builder.getAllFields().keySet()) {
+ for (Descriptors.FieldDescriptor fieldDescriptor : this.descriptor.getFields()) {
if (fieldDescriptor.isRepeated()) {
- dup.repeatedFields.put(fieldDescriptor, getRepeatedField(context, fieldDescriptor));
- } else if (builder.hasField(fieldDescriptor)) {
- dup.fields.put(fieldDescriptor, wrapField(context, fieldDescriptor, builder.getField(fieldDescriptor)));
+ dup.addRepeatedField(fieldDescriptor, this.getRepeatedField(context, fieldDescriptor));
+ } else if (fields.containsKey(fieldDescriptor)) {
+ dup.fields.put(fieldDescriptor, fields.get(fieldDescriptor));
+ } else if (this.builder.hasField(fieldDescriptor)) {
+ dup.fields.put(fieldDescriptor, wrapField(context, fieldDescriptor, this.builder.getField(fieldDescriptor)));
}
}
- for (Descriptors.FieldDescriptor fieldDescriptor : fields.keySet()) {
- dup.fields.put(fieldDescriptor, fields.get(fieldDescriptor));
- }
for (Descriptors.FieldDescriptor fieldDescriptor : maps.keySet()) {
dup.maps.put(fieldDescriptor, maps.get(fieldDescriptor));
}
@@ -411,6 +410,7 @@ public class RubyMessage extends RubyObject {
for (int i = 0; i < count; i++) {
ret.push(context, wrapField(context, fieldDescriptor, this.builder.getRepeatedField(fieldDescriptor, i)));
}
+ addRepeatedField(fieldDescriptor, ret);
return ret;
}
@@ -659,14 +659,14 @@ public class RubyMessage extends RubyObject {
} else {
Descriptors.FieldDescriptor.Type fieldType = fieldDescriptor.getType();
IRubyObject typeClass = context.runtime.getObject();
+ boolean addValue = true;
if (fieldType == Descriptors.FieldDescriptor.Type.MESSAGE) {
typeClass = ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context);
+ if (value.isNil()){
+ addValue = false;
+ }
} else if (fieldType == Descriptors.FieldDescriptor.Type.ENUM) {
typeClass = ((RubyEnumDescriptor) getDescriptorForField(context, fieldDescriptor)).enummodule(context);
- }
- Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
- // Convert integer enum to symbol
- if (fieldType == Descriptors.FieldDescriptor.Type.ENUM) {
Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType();
if (Utils.isRubyNum(value)) {
Descriptors.EnumValueDescriptor val =
@@ -674,7 +674,12 @@ public class RubyMessage extends RubyObject {
if (val.getIndex() != -1) value = context.runtime.newSymbol(val.getName());
}
}
- this.fields.put(fieldDescriptor, value);
+ if (addValue) {
+ Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+ this.fields.put(fieldDescriptor, value);
+ } else {
+ this.fields.remove(fieldDescriptor);
+ }
}
}
return context.runtime.getNil();
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
index 9788317a..84bf8956 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
@@ -108,8 +108,9 @@ public class RubyRepeatedField extends RubyObject {
*/
@JRubyMethod(name = "[]=")
public IRubyObject indexSet(ThreadContext context, IRubyObject index, IRubyObject value) {
+ int arrIndex = normalizeArrayIndex(index);
Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
- this.storage.set(RubyNumeric.num2int(index), value);
+ this.storage.set(arrIndex, value);
return context.runtime.getNil();
}
@@ -117,12 +118,15 @@ public class RubyRepeatedField extends RubyObject {
* call-seq:
* RepeatedField.[](index) => value
*
- * Accesses the element at the given index. Throws an exception on out-of-bounds
- * errors.
+ * Accesses the element at the given index. Returns nil on out-of-bounds
*/
@JRubyMethod(name = "[]")
public IRubyObject index(ThreadContext context, IRubyObject index) {
- return this.storage.eltInternal(RubyNumeric.num2int(index));
+ int arrIndex = normalizeArrayIndex(index);
+ if (arrIndex < 0 || arrIndex >= this.storage.size()) {
+ return context.runtime.getNil();
+ }
+ return this.storage.eltInternal(arrIndex);
}
/*
@@ -134,8 +138,7 @@ public class RubyRepeatedField extends RubyObject {
@JRubyMethod(rest = true)
public IRubyObject insert(ThreadContext context, IRubyObject[] args) {
for (int i = 0; i < args.length; i++) {
- Utils.checkType(context, fieldType, args[i], (RubyModule) typeClass);
- this.storage.add(args[i]);
+ push(context, args[i]);
}
return context.runtime.getNil();
}
@@ -385,6 +388,15 @@ public class RubyRepeatedField extends RubyObject {
}
}
+ private int normalizeArrayIndex(IRubyObject index) {
+ int arrIndex = RubyNumeric.num2int(index);
+ int arrSize = this.storage.size();
+ if (arrIndex < 0 && arrSize > 0) {
+ arrIndex = arrSize + arrIndex;
+ }
+ return arrIndex;
+ }
+
private RubyArray storage;
private Descriptors.FieldDescriptor.Type fieldType;
private IRubyObject typeClass;
diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb
index 1c3fb62c..1c2a03dc 100644
--- a/ruby/tests/basic.rb
+++ b/ruby/tests/basic.rb
@@ -154,6 +154,8 @@ module BasicTest
assert m.optional_bytes == "world"
m.optional_msg = TestMessage2.new(:foo => 42)
assert m.optional_msg == TestMessage2.new(:foo => 42)
+ m.optional_msg = nil
+ assert m.optional_msg == nil
end
def test_ctor_args
@@ -314,6 +316,17 @@ module BasicTest
assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102]
end
+ def test_parent_rptfield
+ #make sure we set the RepeatedField and can add to it
+ m = TestMessage.new
+ assert m.repeated_string == []
+ m.repeated_string << 'ok'
+ m.repeated_string.push('ok2')
+ assert m.repeated_string == ['ok', 'ok2']
+ m.repeated_string += ['ok3']
+ assert m.repeated_string == ['ok', 'ok2', 'ok3']
+ end
+
def test_rptfield_msg
l = Google::Protobuf::RepeatedField.new(:message, TestMessage)
l.push TestMessage.new
@@ -377,6 +390,39 @@ module BasicTest
end
end
+ def test_rptfield_array_ducktyping
+ l = Google::Protobuf::RepeatedField.new(:int32)
+ length_methods = %w(count length size)
+ length_methods.each do |lm|
+ assert l.send(lm) == 0
+ end
+ # out of bounds returns a nil
+ assert l[0] == nil
+ assert l[1] == nil
+ assert l[-1] == nil
+ l.push 4
+ length_methods.each do |lm|
+ assert l.send(lm) == 1
+ end
+ assert l[0] == 4
+ assert l[1] == nil
+ assert l[-1] == 4
+ assert l[-2] == nil
+
+ l.push 2
+ length_methods.each do |lm|
+ assert l.send(lm) == 2
+ end
+ assert l[0] == 4
+ assert l[1] == 2
+ assert l[2] == nil
+ assert l[-1] == 2
+ assert l[-2] == 4
+ assert l[-3] == nil
+
+ #adding out of scope will backfill with empty objects
+ end
+
def test_map_basic
# allowed key types:
# :int32, :int64, :uint32, :uint64, :bool, :string, :bytes.
@@ -712,9 +758,12 @@ module BasicTest
m = TestMessage.new
m.optional_string = "hello"
m.optional_int32 = 42
- m.repeated_msg.push TestMessage2.new(:foo => 100)
- m.repeated_msg.push TestMessage2.new(:foo => 200)
-
+ tm1 = TestMessage2.new(:foo => 100)
+ tm2 = TestMessage2.new(:foo => 200)
+ m.repeated_msg.push tm1
+ assert m.repeated_msg[-1] == tm1
+ m.repeated_msg.push tm2
+ assert m.repeated_msg[-1] == tm2
m2 = m.dup
assert m == m2
m.optional_int32 += 1
@@ -827,7 +876,6 @@ module BasicTest
assert m['a.b'] == 4
end
-
def test_int_ranges
m = TestMessage.new
@@ -933,7 +981,6 @@ module BasicTest
assert_raise RangeError do
m.optional_uint64 = 1.5
end
-
end
def test_stress_test
diff --git a/src/Makefile.am b/src/Makefile.am
index 7811b0ae..1e4516fb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,7 +24,17 @@ AM_LDFLAGS = $(PTHREAD_CFLAGS)
# If I say "dist_include_DATA", automake complains that $(includedir) is not
# a "legitimate" directory for DATA. Screw you, automake.
protodir = $(includedir)
-nobase_dist_proto_DATA = google/protobuf/descriptor.proto \
+nobase_dist_proto_DATA = google/protobuf/descriptor.proto \
+ google/protobuf/any.proto \
+ google/protobuf/api.proto \
+ google/protobuf/duration.proto \
+ google/protobuf/empty.proto \
+ google/protobuf/field_mask.proto \
+ google/protobuf/source_context.proto \
+ google/protobuf/struct.proto \
+ google/protobuf/timestamp.proto \
+ google/protobuf/type.proto \
+ google/protobuf/wrappers.proto \
google/protobuf/compiler/plugin.proto
# Not sure why these don't get cleaned automatically.
diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto
index bf2aa0a9..3aba15b3 100644
--- a/src/google/protobuf/any.proto
+++ b/src/google/protobuf/any.proto
@@ -40,7 +40,8 @@ option java_package = "com.google.protobuf";
// `Any` contains an arbitrary serialized message along with a URL
// that describes the type of the serialized message.
//
-//
+// The proto runtimes and/or compiler will eventually
+// provide utilities to pack/unpack Any values (projected Q1/15).
//
// # JSON
// The JSON representation of an `Any` value uses the regular
@@ -76,21 +77,24 @@ message Any {
// For URLs which use the schema `http`, `https`, or no schema, the
// following restrictions and interpretations apply:
//
- // * If no schema is provided, https is assumed.
+ // * If no schema is provided, `https` is assumed.
// * The last segment of the URL's path must represent the fully
// qualified name of the type (as in `path/google.protobuf.Duration`).
// * An HTTP GET on the URL must yield a [google.protobuf.Type][google.protobuf.Type]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
// URL, or have them precompiled into a binary to avoid any
- // lookup. Therefore, binary compatibility need to be preserved
+ // lookup. Therefore, binary compatibility needs to be preserved
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
// Schemas other than `http`, `https` (or the empty schema) might be
// used with implementation specific semantics.
//
- //
+ // Types originating from the `google.*` package
+ // namespace should use `type.googleapis.com/full.type.name` (without
+ // schema and path). A type service will eventually become available which
+ // serves those URLs (projected Q2/15).
string type_url = 1;
// Must be valid serialized data of the above specified type.
diff --git a/src/google/protobuf/api.proto b/src/google/protobuf/api.proto
new file mode 100644
index 00000000..00857f55
--- /dev/null
+++ b/src/google/protobuf/api.proto
@@ -0,0 +1,104 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+syntax = "proto3";
+
+package google.protobuf;
+
+import "google/protobuf/source_context.proto";
+import "google/protobuf/type.proto";
+
+option java_multiple_files = true;
+option java_outer_classname = "ApiProto";
+option java_package = "com.google.protobuf";
+
+
+// Api is a light-weight descriptor for a protocol buffer service.
+message Api {
+ // The fully qualified name of this api, including package name
+ // followed by the api's simple name.
+ string name = 1;
+
+ // The methods of this api, in unspecified order.
+ repeated Method methods = 2;
+
+ // Any metadata attached to the API.
+ repeated Option options = 3;
+
+ // A version string for this api. If specified, must have the form
+ // `major-version.minor-version`, as in `1.10`. If the minor version
+ // is omitted, it defaults to zero. If the entire version field is
+ // empty, the major version is derived from the package name, as
+ // outlined below. If the field is not empty, the version in the
+ // package name will be verified to be consistent with what is
+ // provided here.
+ //
+ // The versioning schema uses [semantic
+ // versioning](http://semver.org) where the major version number
+ // indicates a breaking change and the minor version an additive,
+ // non-breaking change. Both version numbers are signals to users
+ // what to expect from different versions, and should be carefully
+ // chosen based on the product plan.
+ //
+ // The major version is also reflected in the package name of the
+ // API, which must end in `v<major-version>`, as in
+ // `google.feature.v1`. For major versions 0 and 1, the suffix can
+ // be omitted. Zero major versions must only be used for
+ // experimental, none-GA apis.
+ //
+ // See also: [design doc](http://go/api-versioning).
+ //
+ //
+ string version = 4;
+
+ // Source context for the protocol buffer service represented by this
+ // message.
+ SourceContext source_context = 5;
+}
+
+// Method represents a method of an api.
+message Method {
+ // The simple name of this method.
+ string name = 1;
+
+ // A URL of the input message type.
+ string request_type_url = 2;
+
+ // If true, the request is streamed.
+ bool request_streaming = 3;
+
+ // The URL of the output message type.
+ string response_type_url = 4;
+
+ // If true, the response is streamed.
+ bool response_streaming = 5;
+
+ // Any metadata attached to the method.
+ repeated Option options = 6;
+}
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum.cc b/src/google/protobuf/compiler/javanano/javanano_enum.cc
index f934b05f..c6e8dfe9 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_enum.cc
@@ -73,13 +73,45 @@ void EnumGenerator::Generate(io::Printer* printer) {
"// enum $classname$\n",
"classname", descriptor_->name());
+ const string classname = RenameJavaKeywords(descriptor_->name());
+
// Start of container interface
+ // If generating intdefs, we use the container interface as the intdef if
+ // present. Otherwise, we just make an empty @interface parallel to the
+ // constants.
+ bool use_intdef = params_.generate_intdefs();
bool use_shell_class = params_.java_enum_style();
- if (use_shell_class) {
- printer->Print(
- "public interface $classname$ {\n",
- "classname", RenameJavaKeywords(descriptor_->name()));
+ if (use_intdef) {
+ // @IntDef annotation so tools can enforce correctness
+ // Annotations will be discarded by the compiler
+ printer->Print("@java.lang.annotation.Retention("
+ "java.lang.annotation.RetentionPolicy.SOURCE)\n"
+ "@android.support.annotation.IntDef({\n");
printer->Indent();
+ for (int i = 0; i < canonical_values_.size(); i++) {
+ const string constant_name =
+ RenameJavaKeywords(canonical_values_[i]->name());
+ if (use_shell_class) {
+ printer->Print("$classname$.$name$,\n",
+ "classname", classname,
+ "name", constant_name);
+ } else {
+ printer->Print("$name$,\n", "name", constant_name);
+ }
+ }
+ printer->Outdent();
+ printer->Print("})\n");
+ }
+ if (use_shell_class || use_intdef) {
+ printer->Print(
+ "public $at_for_intdef$interface $classname$ {\n",
+ "classname", classname,
+ "at_for_intdef", use_intdef ? "@" : "");
+ if (use_shell_class) {
+ printer->Indent();
+ } else {
+ printer->Print("}\n\n");
+ }
}
// Canonical values
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
index 8a59d323..7666db38 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
@@ -76,6 +76,10 @@ void SetEnumVariables(const Params& params,
internal::WireFormatLite::MakeTag(descriptor->number(),
internal::WireFormat::WireTypeForFieldType(descriptor->type())));
(*variables)["message_name"] = descriptor->containing_type()->name();
+ const EnumDescriptor* enum_type = descriptor->enum_type();
+ (*variables)["message_type_intdef"] = "@"
+ + ToJavaName(params, enum_type->name(), true,
+ enum_type->containing_type(), enum_type->file());
}
void LoadEnumValues(const Params& params,
@@ -116,8 +120,10 @@ EnumFieldGenerator::~EnumFieldGenerator() {}
void EnumFieldGenerator::
GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
- printer->Print(variables_,
- "public $type$ $name$;\n");
+ if (params_.generate_intdefs()) {
+ printer->Print(variables_, "$message_type_intdef$\n");
+ }
+ printer->Print(variables_, "public $type$ $name$;\n");
if (params_.generate_has()) {
printer->Print(variables_,
@@ -256,12 +262,22 @@ AccessorEnumFieldGenerator::~AccessorEnumFieldGenerator() {}
void AccessorEnumFieldGenerator::
GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_, "private int $name$_;\n");
+ if (params_.generate_intdefs()) {
+ printer->Print(variables_, "$message_type_intdef$\n");
+ }
printer->Print(variables_,
- "private int $name$_;\n"
"public int get$capitalized_name$() {\n"
" return $name$_;\n"
"}\n"
- "public $message_name$ set$capitalized_name$(int value) {\n"
+ "public $message_name$ set$capitalized_name$(");
+ if (params_.generate_intdefs()) {
+ printer->Print(variables_,
+ "\n"
+ " $message_type_intdef$ ");
+ }
+ printer->Print(variables_,
+ "int value) {\n"
" $name$_ = value;\n"
" $set_has$;\n"
" return this;\n"
@@ -499,6 +515,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
void RepeatedEnumFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n"
+ " cloned.$name$ = this.$name$.clone();\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
printer->Print(variables_,
"if (!com.google.protobuf.nano.InternalNano.equals(\n"
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.h b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
index 00adc61f..b94790d6 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
@@ -106,6 +106,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCodeCode(io::Printer* printer) const;
+ void GenerateFixClonedCode(io::Printer* printer) const;
private:
void GenerateRepeatedDataSizeCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.cc b/src/google/protobuf/compiler/javanano/javanano_extension.cc
index 754ed550..0b9d1d8d 100644
--- a/src/google/protobuf/compiler/javanano/javanano_extension.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_extension.cc
@@ -140,7 +140,7 @@ void ExtensionGenerator::Generate(io::Printer* printer) const {
" com.google.protobuf.nano.Extension.create$repeated$$ext_type$(\n"
" com.google.protobuf.nano.Extension.$type$,\n"
" $class$.class,\n"
- " $tag_params$);\n");
+ " $tag_params$L);\n");
}
} // namespace javanano
diff --git a/src/google/protobuf/compiler/javanano/javanano_field.h b/src/google/protobuf/compiler/javanano/javanano_field.h
index c2cf091c..57c221f4 100644
--- a/src/google/protobuf/compiler/javanano/javanano_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_field.h
@@ -83,6 +83,7 @@ class FieldGenerator {
virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
virtual void GenerateHashCodeCode(io::Printer* printer) const = 0;
+ virtual void GenerateFixClonedCode(io::Printer* printer) const {}
protected:
const Params& params_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc
index b5fbcd5f..ad215cb7 100644
--- a/src/google/protobuf/compiler/javanano/javanano_generator.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc
@@ -152,6 +152,12 @@ bool JavaNanoGenerator::Generate(const FileDescriptor* file,
params.set_ignore_services(option_value == "true");
} else if (option_name == "parcelable_messages") {
params.set_parcelable_messages(option_value == "true");
+ } else if (option_name == "generate_clone") {
+ params.set_generate_clone(option_value == "true");
+ } else if (option_name == "generate_intdefs") {
+ params.set_generate_intdefs(option_value == "true");
+ } else if (option_name == "generate_clear") {
+ params.set_generate_clear(option_value == "true");
} else {
*error = "Ignore unknown javanano generator option: " + option_name;
}
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc
index 707f6b84..a41da5ae 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message.cc
@@ -136,21 +136,37 @@ void MessageGenerator::Generate(io::Printer* printer) {
}
if (params_.store_unknown_fields() && params_.parcelable_messages()) {
printer->Print(
- " com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$> {\n",
+ " com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$>",
"classname", descriptor_->name());
} else if (params_.store_unknown_fields()) {
printer->Print(
- " com.google.protobuf.nano.ExtendableMessageNano<$classname$> {\n",
+ " com.google.protobuf.nano.ExtendableMessageNano<$classname$>",
"classname", descriptor_->name());
} else if (params_.parcelable_messages()) {
printer->Print(
- " com.google.protobuf.nano.android.ParcelableMessageNano {\n");
+ " com.google.protobuf.nano.android.ParcelableMessageNano");
} else {
printer->Print(
- " com.google.protobuf.nano.MessageNano {\n");
+ " com.google.protobuf.nano.MessageNano");
+ }
+ if (params_.generate_clone()) {
+ printer->Print(" implements java.lang.Cloneable {\n");
+ } else {
+ printer->Print(" {\n");
}
printer->Indent();
+ if (params_.parcelable_messages()) {
+ printer->Print(
+ "\n"
+ "// Used by Parcelable\n"
+ "@SuppressWarnings({\"unused\"})\n"
+ "public static final android.os.Parcelable.Creator<$classname$> CREATOR =\n"
+ " new com.google.protobuf.nano.android.ParcelableMessageNanoCreator<\n"
+ " $classname$>($classname$.class);\n",
+ "classname", descriptor_->name());
+ }
+
// Nested types and extensions
for (int i = 0; i < descriptor_->extension_count(); i++) {
ExtensionGenerator(descriptor_->extension(i), params_).Generate(printer);
@@ -288,20 +304,28 @@ void MessageGenerator::Generate(io::Printer* printer) {
}
printer->Print("}\n");
} else {
+ printer->Print(
+ "\n"
+ "public $classname$() {\n",
+ "classname", descriptor_->name());
if (params_.generate_clear()) {
- printer->Print(
- "\n"
- "public $classname$() {\n"
- " clear();\n"
- "}\n",
- "classname", descriptor_->name());
+ printer->Print(" clear();\n");
+ } else {
+ printer->Indent();
+ GenerateFieldInitializers(printer);
+ printer->Outdent();
}
+ printer->Print("}\n");
}
// Other methods in this class
GenerateClear(printer);
+ if (params_.generate_clone()) {
+ GenerateClone(printer);
+ }
+
if (params_.generate_equals()) {
GenerateEquals(printer);
GenerateHashCode(printer);
@@ -495,6 +519,15 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
"classname", descriptor_->name());
printer->Indent();
+ GenerateFieldInitializers(printer);
+
+ printer->Outdent();
+ printer->Print(
+ " return this;\n"
+ "}\n");
+}
+
+void MessageGenerator::GenerateFieldInitializers(io::Printer* printer) {
// Clear bit fields.
int totalInts = (field_generators_.total_bits() + 31) / 32;
for (int i = 0; i < totalInts; i++) {
@@ -520,12 +553,34 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
if (params_.store_unknown_fields()) {
printer->Print("unknownFieldData = null;\n");
}
+ printer->Print("cachedSize = -1;\n");
+}
+
+void MessageGenerator::GenerateClone(io::Printer* printer) {
+ printer->Print(
+ "@Override\n"
+ "public $classname$ clone() {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+
+ printer->Print(
+ "$classname$ cloned;\n"
+ "try {\n"
+ " cloned = ($classname$) super.clone();\n"
+ "} catch (java.lang.CloneNotSupportedException e) {\n"
+ " throw new java.lang.AssertionError(e);\n"
+ "}\n",
+ "classname", descriptor_->name());
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i)).GenerateFixClonedCode(printer);
+ }
printer->Outdent();
printer->Print(
- " cachedSize = -1;\n"
- " return this;\n"
- "}\n");
+ " return cloned;\n"
+ "}\n"
+ "\n");
}
void MessageGenerator::GenerateEquals(io::Printer* printer) {
@@ -568,7 +623,11 @@ void MessageGenerator::GenerateEquals(io::Printer* printer) {
if (params_.store_unknown_fields()) {
printer->Print(
- "return unknownFieldDataEquals(other);\n");
+ "if (unknownFieldData == null || unknownFieldData.isEmpty()) {\n"
+ " return other.unknownFieldData == null || other.unknownFieldData.isEmpty();\n"
+ "} else {\n"
+ " return unknownFieldData.equals(other.unknownFieldData);\n"
+ "}");
} else {
printer->Print(
"return true;\n");
@@ -598,7 +657,9 @@ void MessageGenerator::GenerateHashCode(io::Printer* printer) {
if (params_.store_unknown_fields()) {
printer->Print(
- "result = 31 * result + unknownFieldDataHashCode();\n");
+ "result = 31 * result + \n"
+ " (unknownFieldData == null || unknownFieldData.isEmpty() ? 0 : \n"
+ " unknownFieldData.hashCode());\n");
}
printer->Print("return result;\n");
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.h b/src/google/protobuf/compiler/javanano/javanano_message.h
index 6f25a3a0..281ec64f 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.h
+++ b/src/google/protobuf/compiler/javanano/javanano_message.h
@@ -77,8 +77,10 @@ class MessageGenerator {
const FieldDescriptor* field);
void GenerateClear(io::Printer* printer);
+ void GenerateFieldInitializers(io::Printer* printer);
void GenerateEquals(io::Printer* printer);
void GenerateHashCode(io::Printer* printer);
+ void GenerateClone(io::Printer* printer);
const Params& params_;
const Descriptor* descriptor_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.cc b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
index 181c4060..d1d04b52 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
@@ -127,6 +127,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
void MessageFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null) {\n"
+ " cloned.$name$ = this.$name$.clone();\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
printer->Print(variables_,
"if (this.$name$ == null) { \n"
@@ -213,6 +221,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
void MessageOneofFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$oneof_name$ != null) {\n"
+ " cloned.$oneof_name$ = this.$oneof_name$.clone();\n"
+ "}\n");
+}
+
+void MessageOneofFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
GenerateOneofFieldEquals(descriptor_, variables_, printer);
}
@@ -313,6 +329,19 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
void RepeatedMessageFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n"
+ " cloned.$name$ = new $type$[this.$name$.length];\n"
+ " for (int i = 0; i < this.$name$.length; i++) {\n"
+ " if (this.$name$[i] != null) {\n"
+ " cloned.$name$[i] = this.$name$[i].clone();\n"
+ " }\n"
+ " }\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
printer->Print(variables_,
"if (!com.google.protobuf.nano.InternalNano.equals(\n"
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.h b/src/google/protobuf/compiler/javanano/javanano_message_field.h
index 6c615f5e..e074735c 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.h
@@ -58,6 +58,7 @@ class MessageFieldGenerator : public FieldGenerator {
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCodeCode(io::Printer* printer) const;
+ void GenerateFixClonedCode(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
@@ -80,6 +81,7 @@ class MessageOneofFieldGenerator : public FieldGenerator {
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCodeCode(io::Printer* printer) const;
+ void GenerateFixClonedCode(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
@@ -102,6 +104,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCodeCode(io::Printer* printer) const;
+ void GenerateFixClonedCode(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_params.h b/src/google/protobuf/compiler/javanano/javanano_params.h
index 4691f360..e3b4bb93 100644
--- a/src/google/protobuf/compiler/javanano/javanano_params.h
+++ b/src/google/protobuf/compiler/javanano/javanano_params.h
@@ -66,6 +66,8 @@ class Params {
bool parcelable_messages_;
bool reftypes_primitive_enums_;
bool generate_clear_;
+ bool generate_clone_;
+ bool generate_intdefs_;
public:
Params(const string & base_name) :
@@ -81,7 +83,9 @@ class Params {
ignore_services_(false),
parcelable_messages_(false),
reftypes_primitive_enums_(false),
- generate_clear_(true) {
+ generate_clear_(true),
+ generate_clone_(false),
+ generate_intdefs_(false) {
}
const string& base_name() const {
@@ -231,6 +235,20 @@ class Params {
bool generate_clear() const {
return generate_clear_;
}
+
+ void set_generate_clone(bool value) {
+ generate_clone_ = value;
+ }
+ bool generate_clone() const {
+ return generate_clone_;
+ }
+
+ void set_generate_intdefs(bool value) {
+ generate_intdefs_ = value;
+ }
+ bool generate_intdefs() const {
+ return generate_intdefs_;
+ }
};
} // namespace javanano
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
index 41bad0a6..978abf2c 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
@@ -364,6 +364,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
}
+void RepeatedPrimitiveFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n"
+ " cloned.$name$ = this.$name$.clone();\n"
+ "}\n");
+}
+
void PrimitiveFieldGenerator::
GenerateEqualsCode(io::Printer* printer) const {
// We define equality as serialized form equality. If generate_has(),
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
index ca7116ff..a01981dd 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
@@ -131,6 +131,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
void GenerateSerializedSizeCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCodeCode(io::Printer* printer) const;
+ void GenerateFixClonedCode(io::Printer* printer) const;
private:
void GenerateRepeatedDataSizeCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/duration.proto b/src/google/protobuf/duration.proto
index 868c732f..c6dd4adc 100644
--- a/src/google/protobuf/duration.proto
+++ b/src/google/protobuf/duration.proto
@@ -44,7 +44,7 @@ option java_package = "com.google.protobuf";
// two Timestamp values is a Duration and it can be added or subtracted
// from a Timestamp. Range is approximately +-10,000 years.
//
-// Example 1: compute Duration from two Timestamps in pseudo code.
+// Example 1: Compute Duration from two Timestamps in pseudo code.
//
// Timestamp start = ...;
// Timestamp end = ...;
@@ -61,7 +61,7 @@ option java_package = "com.google.protobuf";
// duration.nanos += 1000000000;
// }
//
-// Example 2: compute Timestamp from Timestamp + Duration in pseudo code.
+// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
//
// Timestamp start = ...;
// Duration duration = ...;
@@ -85,9 +85,9 @@ message Duration {
// Signed fractions of a second at nanosecond resolution of the span
// of time. Durations less than one second are represented with a 0
- // seconds field and a positive or negative nanos field. For durations
- // of one second or more, a non-zero value for the nanos field must be
- // of the same sign as the seconds field. Must be from -999,999,999
+ // `seconds` field and a positive or negative `nanos` field. For durations
+ // of one second or more, a non-zero value for the `nanos` field must be
+ // of the same sign as the `seconds` field. Must be from -999,999,999
// to +999,999,999 inclusive.
int32 nanos = 2;
}
diff --git a/src/google/protobuf/empty.proto b/src/google/protobuf/empty.proto
new file mode 100644
index 00000000..46087d59
--- /dev/null
+++ b/src/google/protobuf/empty.proto
@@ -0,0 +1,49 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+syntax = "proto3";
+
+package google.protobuf;
+
+option java_multiple_files = true;
+option java_outer_classname = "EmptyProto";
+option java_package = "com.google.protobuf";
+
+
+// A generic empty message that you can re-use to avoid defining duplicated
+// empty messages in your APIs. A typical example is to use it as the request
+// or the response type of an API method. For instance:
+//
+// service Foo {
+// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
+// }
+//
+message Empty {
+
+}
diff --git a/src/google/protobuf/source_context.proto b/src/google/protobuf/source_context.proto
new file mode 100644
index 00000000..a3874d6a
--- /dev/null
+++ b/src/google/protobuf/source_context.proto
@@ -0,0 +1,45 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+syntax = "proto3";
+
+package google.protobuf;
+
+option java_multiple_files = true;
+option java_outer_classname = "SourceContextProto";
+option java_package = "com.google.protobuf";
+
+
+// `SourceContext` represents information about the source of a
+// protobuf element, like the file in which it is defined.
+message SourceContext {
+ // The path-qualified name of the .proto file that contained the associated
+ // protobuf element. For example: `"google/protobuf/source.proto"`.
+ string file_name = 1;
+}
diff --git a/src/google/protobuf/struct.proto b/src/google/protobuf/struct.proto
index 9f27eb43..3a90ff37 100644
--- a/src/google/protobuf/struct.proto
+++ b/src/google/protobuf/struct.proto
@@ -56,28 +56,33 @@ message Value {
oneof kind {
// Represents a null value.
NullValue null_value = 1;
+
// Represents a double value.
double number_value = 2;
+
// Represents a string value.
string string_value = 3;
+
// Represents a boolean value.
bool bool_value = 4;
+
// Represents a structured value.
Struct struct_value = 5;
+
// Represents a repeated `Value`.
ListValue list_value = 6;
}
}
+// `ListValue` is a wrapper around a repeated field of values.
+message ListValue {
+ // Repeated field of dynamically typed values.
+ repeated Value values = 1;
+}
+
// `NullValue` is a singleton enumeration to represent the null
// value for the `Value` type union.
enum NullValue {
// Null value.
NULL_VALUE = 0;
}
-
-// `ListValue` is a wrapper around a repeated field of values.
-message ListValue {
- // Repeated field of dynamically typed values.
- repeated Value values = 1;
-}
diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto
index ac8e009c..89956229 100644
--- a/src/google/protobuf/timestamp.proto
+++ b/src/google/protobuf/timestamp.proto
@@ -46,15 +46,16 @@ option java_package = "com.google.protobuf";
// table is needed for interpretation. Range is from
// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
// By restricting to that range, we ensure that we can convert to
-// and from RFC 3339 date strings. (See https://www.ietf.org/rfc/rfc3339.txt.)
+// and from RFC 3339 date strings.
+// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
//
-// Example 1: compute Timestamp from POSIX `time()`.
+// Example 1: Compute Timestamp from POSIX `time()`.
//
// Timestamp timestamp;
// timestamp.set_seconds(time(NULL));
// timestamp.set_nanos(0);
//
-// Example 2: compute Timestamp from POSIX `gettimeofday()`.
+// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
//
// struct timeval tv;
// gettimeofday(&tv, NULL);
@@ -63,7 +64,7 @@ option java_package = "com.google.protobuf";
// timestamp.set_seconds(tv.tv_sec);
// timestamp.set_nanos(tv.tv_usec * 1000);
//
-// Example 3: compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
+// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
//
// FILETIME ft;
// GetSystemTimeAsFileTime(&ft);
@@ -75,14 +76,14 @@ option java_package = "com.google.protobuf";
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
//
-// Example 4: compute Timestamp from Java `System.currentTimeMillis()`.
+// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
//
// long millis = System.currentTimeMillis();
//
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
// .setNanos((int) ((millis % 1000) * 1000000)).build();
//
-// Example 5: compute Timestamp from Python `datetime.datetime`.
+// Example 5: Compute Timestamp from Python `datetime.datetime`.
//
// now = datetime.datetime.utcnow()
// seconds = int(time.mktime(now.timetuple()))
diff --git a/src/google/protobuf/type.proto b/src/google/protobuf/type.proto
new file mode 100644
index 00000000..04165c81
--- /dev/null
+++ b/src/google/protobuf/type.proto
@@ -0,0 +1,196 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+syntax = "proto3";
+
+package google.protobuf;
+
+import "google/protobuf/any.proto";
+import "google/protobuf/source_context.proto";
+
+option java_multiple_files = true;
+option java_outer_classname = "TypeProto";
+option java_package = "com.google.protobuf";
+
+
+// A light-weight descriptor for a proto message type.
+message Type {
+ // The fully qualified message name.
+ string name = 1;
+
+ // The list of fields.
+ repeated Field fields = 2;
+
+ // The list of oneof definitions.
+ // The list of oneofs declared in this Type
+ repeated string oneofs = 3;
+
+ // The proto options.
+ repeated Option options = 4;
+
+ // The source context.
+ SourceContext source_context = 5;
+}
+
+// Field represents a single field of a message type.
+message Field {
+ // Kind represents a basic field type.
+ enum Kind {
+ // Field type unknown.
+ TYPE_UNKNOWN = 0;
+
+ // Field type double.
+ TYPE_DOUBLE = 1;
+
+ // Field type float.
+ TYPE_FLOAT = 2;
+
+ // Field type int64.
+ TYPE_INT64 = 3;
+
+ // Field type uint64.
+ TYPE_UINT64 = 4;
+
+ // Field type int32.
+ TYPE_INT32 = 5;
+
+ // Field type fixed64.
+ TYPE_FIXED64 = 6;
+
+ // Field type fixed32.
+ TYPE_FIXED32 = 7;
+
+ // Field type bool.
+ TYPE_BOOL = 8;
+
+ // Field type string.
+ TYPE_STRING = 9;
+
+ // Field type message.
+ TYPE_MESSAGE = 11;
+
+ // Field type bytes.
+ TYPE_BYTES = 12;
+
+ // Field type uint32.
+ TYPE_UINT32 = 13;
+
+ // Field type enum.
+ TYPE_ENUM = 14;
+
+ // Field type sfixed32.
+ TYPE_SFIXED32 = 15;
+
+ // Field type sfixed64.
+ TYPE_SFIXED64 = 16;
+
+ // Field type sint32.
+ TYPE_SINT32 = 17;
+
+ // Field type sint64.
+ TYPE_SINT64 = 18;
+ }
+
+ // Cardinality represents whether a field is optional, required, or
+ // repeated.
+ enum Cardinality {
+ // The field cardinality is unknown. Typically an error condition.
+ CARDINALITY_UNKNOWN = 0;
+
+ // For optional fields.
+ CARDINALITY_OPTIONAL = 1;
+
+ // For required fields. Not used for proto3.
+ CARDINALITY_REQUIRED = 2;
+
+ // For repeated fields.
+ CARDINALITY_REPEATED = 3;
+ }
+
+ // The field kind.
+ Kind kind = 1;
+
+ // The field cardinality, i.e. optional/required/repeated.
+ Cardinality cardinality = 2;
+
+ // The proto field number.
+ int32 number = 3;
+
+ // The field name.
+ string name = 4;
+
+ // The type URL (without the scheme) when the type is MESSAGE or ENUM,
+ // such as `type.googleapis.com/google.protobuf.Empty`.
+ string type_url = 6;
+
+ // Index in Type.oneofs. Starts at 1. Zero means no oneof mapping.
+ int32 oneof_index = 7;
+
+ // Whether to use alternative packed wire representation.
+ bool packed = 8;
+
+ // The proto options.
+ repeated Option options = 9;
+}
+
+// Enum type definition.
+message Enum {
+ // Enum type name.
+ string name = 1;
+
+ // Enum value definitions.
+ repeated EnumValue enumvalue = 2;
+
+ // Proto options for the enum type.
+ repeated Option options = 3;
+
+ // The source context.
+ SourceContext source_context = 4;
+}
+
+// Enum value definition.
+message EnumValue {
+ // Enum value name.
+ string name = 1;
+
+ // Enum value number.
+ int32 number = 2;
+
+ // Proto options for the enum value.
+ repeated Option options = 3;
+}
+
+// Proto option attached to messages/fields/enums etc.
+message Option {
+ // Proto option name.
+ string name = 1;
+
+ // Proto option value.
+ Any value = 2;
+}