diff options
Diffstat (limited to 'src')
8 files changed, 260 insertions, 101 deletions
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc index 5d3511bd..6a18834d 100644 --- a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc +++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc @@ -71,9 +71,35 @@ void SetEnumVariables(const Params& params, (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( internal::WireFormat::TagSize(descriptor->number(), descriptor->type())); + (*variables)["non_packed_tag"] = SimpleItoa( + internal::WireFormatLite::MakeTag(descriptor->number(), + internal::WireFormat::WireTypeForFieldType(descriptor->type()))); (*variables)["message_name"] = descriptor->containing_type()->name(); } +void LoadEnumValues(const Params& params, + const EnumDescriptor* enum_descriptor, vector<string>* canonical_values) { + string enum_class_name = ClassName(params, enum_descriptor); + for (int i = 0; i < enum_descriptor->value_count(); i++) { + const EnumValueDescriptor* value = enum_descriptor->value(i); + const EnumValueDescriptor* canonical_value = + enum_descriptor->FindValueByNumber(value->number()); + if (value == canonical_value) { + canonical_values->push_back( + enum_class_name + "." + RenameJavaKeywords(value->name())); + } + } +} + +void PrintCaseLabels( + io::Printer* printer, const vector<string>& canonical_values) { + for (int i = 0; i < canonical_values.size(); i++) { + printer->Print( + " case $value$:\n", + "value", canonical_values[i]); + } +} + } // namespace // =================================================================== @@ -82,6 +108,7 @@ EnumFieldGenerator:: EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params) : FieldGenerator(params), descriptor_(descriptor) { SetEnumVariables(params, descriptor, &variables_); + LoadEnumValues(params, descriptor->enum_type(), &canonical_values_); } EnumFieldGenerator::~EnumFieldGenerator() {} @@ -111,17 +138,27 @@ GenerateClearCode(io::Printer* printer) const { void EnumFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, - "this.$name$ = input.readInt32();\n"); - + "int value = input.readInt32();\n" + "switch (value) {\n"); + PrintCaseLabels(printer, canonical_values_); + printer->Print(variables_, + " this.$name$ = value;\n"); if (params_.generate_has()) { printer->Print(variables_, - "has$capitalized_name$ = true;\n"); + " has$capitalized_name$ = true;\n"); } + printer->Print( + " break;\n" + "}\n"); + // No default case: in case of invalid value from the wire, preserve old + // field value. Also we are not storing the invalid value into the unknown + // fields, because there is no way to get the value out. } void EnumFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { - if (descriptor_->is_required()) { + if (descriptor_->is_required() && !params_.generate_has()) { + // Always serialize a required field if we don't have the 'has' signal. printer->Print(variables_, "output.writeInt32($number$, this.$name$);\n"); } else { @@ -140,7 +177,7 @@ GenerateSerializationCode(io::Printer* printer) const { void EnumFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { - if (descriptor_->is_required()) { + if (descriptor_->is_required() && !params_.generate_has()) { printer->Print(variables_, "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" " .computeInt32Size($number$, this.$name$);\n"); @@ -208,6 +245,7 @@ AccessorEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params, int has_bit_index) : FieldGenerator(params), descriptor_(descriptor) { SetEnumVariables(params, descriptor, &variables_); + LoadEnumValues(params, descriptor->enum_type(), &canonical_values_); SetBitOperationVariables("has", has_bit_index, &variables_); } @@ -244,8 +282,17 @@ GenerateClearCode(io::Printer* printer) const { void AccessorEnumFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, - "$name$_ = input.readInt32();\n" - "$set_has$;\n"); + "int value = input.readInt32();\n" + "switch (value) {\n"); + PrintCaseLabels(printer, canonical_values_); + printer->Print(variables_, + " $name$_ = value;\n" + " $set_has$;\n" + " break;\n" + "}\n"); + // No default case: in case of invalid value from the wire, preserve old + // field value. Also we are not storing the invalid value into the unknown + // fields, because there is no way to get the value out. } void AccessorEnumFieldGenerator:: @@ -286,6 +333,7 @@ RepeatedEnumFieldGenerator:: RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params) : FieldGenerator(params), descriptor_(descriptor) { SetEnumVariables(params, descriptor, &variables_); + LoadEnumValues(params, descriptor->enum_type(), &canonical_values_); } RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} @@ -304,46 +352,82 @@ GenerateClearCode(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { - // First, figure out the length of the array, then parse. + // First, figure out the maximum length of the array, then parse, + // and finally copy the valid values to the field. printer->Print(variables_, - "int arrayLength = com.google.protobuf.nano.WireFormatNano\n" - " .getRepeatedFieldArrayLength(input, $tag$);\n" - "int i = this.$name$ == null ? 0 : this.$name$.length;\n" - "int[] newArray = new int[i + arrayLength];\n" - "if (i != 0) {\n" - " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n" - "}\n" - "for (; i < newArray.length - 1; i++) {\n" - " newArray[i] = input.readInt32();\n" - " input.readTag();\n" + "int length = com.google.protobuf.nano.WireFormatNano\n" + " .getRepeatedFieldArrayLength(input, $non_packed_tag$);\n" + "int[] validValues = new int[length];\n" + "int validCount = 0;\n" + "for (int i = 0; i < length; i++) {\n" + " if (i != 0) { // tag for first value already consumed.\n" + " input.readTag();\n" + " }\n" + " int value = input.readInt32();\n" + " switch (value) {\n"); + printer->Indent(); + PrintCaseLabels(printer, canonical_values_); + printer->Outdent(); + printer->Print(variables_, + " validValues[validCount++] = value;\n" + " break;\n" + " }\n" "}\n" - "// Last one without readTag.\n" - "newArray[i] = input.readInt32();\n" - "this.$name$ = newArray;\n"); + "if (validCount != 0) {\n" + " int i = this.$name$ == null ? 0 : this.$name$.length;\n" + " if (i == 0 && validCount == validValues.length) {\n" + " this.$name$ = validValues;\n" + " } else {\n" + " int[] newArray = new int[i + validCount];\n" + " if (i != 0) {\n" + " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n" + " }\n" + " java.lang.System.arraycopy(validValues, 0, newArray, i, validCount);\n" + " this.$name$ = newArray;\n" + " }\n" + "}\n"); } void RepeatedEnumFieldGenerator:: GenerateMergingCodeFromPacked(io::Printer* printer) const { printer->Print(variables_, - "int length = input.readRawVarint32();\n" - "int limit = input.pushLimit(length);\n" + "int bytes = input.readRawVarint32();\n" + "int limit = input.pushLimit(bytes);\n" "// First pass to compute array length.\n" "int arrayLength = 0;\n" "int startPos = input.getPosition();\n" "while (input.getBytesUntilLimit() > 0) {\n" - " input.readInt32();\n" - " arrayLength++;\n" - "}\n" - "input.rewindToPosition(startPos);\n" - "int i = this.$name$ == null ? 0 : this.$name$.length;\n" - "int[] newArray = new int[i + arrayLength];\n" - "if (i != 0) {\n" - " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n" + " switch (input.readInt32()) {\n"); + printer->Indent(); + PrintCaseLabels(printer, canonical_values_); + printer->Outdent(); + printer->Print(variables_, + " arrayLength++;\n" + " break;\n" + " }\n" "}\n" - "for (; i < newArray.length; i++) {\n" - " newArray[i] = input.readInt32();\n" + "if (arrayLength != 0) {\n" + " input.rewindToPosition(startPos);\n" + " int i = this.$name$ == null ? 0 : this.$name$.length;\n" + " int[] newArray = new int[i + arrayLength];\n" + " if (i != 0) {\n" + " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n" + " }\n" + " while (input.getBytesUntilLimit() > 0) {\n" + " int value = input.readInt32();\n" + " switch (value) {\n"); + printer->Indent(); + printer->Indent(); + PrintCaseLabels(printer, canonical_values_); + printer->Outdent(); + printer->Outdent(); + printer->Print(variables_, + " newArray[i++] = value;\n" + " break;\n" + " }\n" + " }\n" + " this.$name$ = newArray;\n" "}\n" - "this.$name$ = newArray;\n" "input.popLimit(limit);\n"); } diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.h b/src/google/protobuf/compiler/javanano/javanano_enum_field.h index c477af25..55bf6356 100644 --- a/src/google/protobuf/compiler/javanano/javanano_enum_field.h +++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.h @@ -37,6 +37,7 @@ #include <map> #include <string> +#include <vector> #include <google/protobuf/compiler/javanano/javanano_field.h> namespace google { @@ -62,6 +63,7 @@ class EnumFieldGenerator : public FieldGenerator { private: const FieldDescriptor* descriptor_; map<string, string> variables_; + vector<string> canonical_values_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); }; @@ -84,6 +86,7 @@ class AccessorEnumFieldGenerator : public FieldGenerator { private: const FieldDescriptor* descriptor_; map<string, string> variables_; + vector<string> canonical_values_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AccessorEnumFieldGenerator); }; @@ -109,6 +112,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { const FieldDescriptor* descriptor_; map<string, string> variables_; + vector<string> canonical_values_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); }; diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc index 5c8bcb60..d514dd86 100644 --- a/src/google/protobuf/compiler/javanano/javanano_generator.cc +++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc @@ -46,6 +46,19 @@ namespace protobuf { namespace compiler { namespace javanano { +namespace { + +string TrimString(const string& s) { + string::size_type start = s.find_first_not_of(" \n\r\t"); + if (start == string::npos) { + return ""; + } + string::size_type end = s.find_last_not_of(" \n\r\t") + 1; + return s.substr(start, end - start); +} + +} // namespace + void UpdateParamsRecursively(Params& params, const FileDescriptor* file) { // Add any parameters for this file @@ -93,42 +106,44 @@ bool JavaNanoGenerator::Generate(const FileDescriptor* file, // Replace any existing options with ones from command line for (int i = 0; i < options.size(); i++) { - if (options[i].first == "output_list_file") { - output_list_file = options[i].second; - } else if (options[i].first == "java_package") { + string option_name = TrimString(options[i].first); + string option_value = TrimString(options[i].second); + if (option_name == "output_list_file") { + output_list_file = option_value; + } else if (option_name == "java_package") { vector<string> parts; - SplitStringUsing(options[i].second, "|", &parts); + SplitStringUsing(option_value, "|", &parts); if (parts.size() != 2) { *error = "Bad java_package, expecting filename|PackageName found '" - + options[i].second + "'"; + + option_value + "'"; return false; } params.set_java_package(parts[0], parts[1]); - } else if (options[i].first == "java_outer_classname") { + } else if (option_name == "java_outer_classname") { vector<string> parts; - SplitStringUsing(options[i].second, "|", &parts); + SplitStringUsing(option_value, "|", &parts); if (parts.size() != 2) { *error = "Bad java_outer_classname, " "expecting filename|ClassName found '" - + options[i].second + "'"; + + option_value + "'"; return false; } params.set_java_outer_classname(parts[0], parts[1]); - } else if (options[i].first == "store_unknown_fields") { - params.set_store_unknown_fields(options[i].second == "true"); - } else if (options[i].first == "java_multiple_files") { - params.set_override_java_multiple_files(options[i].second == "true"); - } else if (options[i].first == "java_nano_generate_has") { - params.set_generate_has(options[i].second == "true"); - } else if (options[i].first == "enum_style") { - params.set_java_enum_style(options[i].second == "java"); - } else if (options[i].first == "optional_field_style") { - params.set_optional_field_accessors(options[i].second == "accessors"); - params.set_use_reference_types_for_primitives(options[i].second == "reftypes"); - } else if (options[i].first == "generate_equals") { - params.set_generate_equals(options[i].second == "true"); + } else if (option_name == "store_unknown_fields") { + params.set_store_unknown_fields(option_value == "true"); + } else if (option_name == "java_multiple_files") { + params.set_override_java_multiple_files(option_value == "true"); + } else if (option_name == "java_nano_generate_has") { + params.set_generate_has(option_value == "true"); + } else if (option_name == "enum_style") { + params.set_java_enum_style(option_value == "java"); + } else if (option_name == "optional_field_style") { + params.set_optional_field_accessors(option_value == "accessors"); + params.set_use_reference_types_for_primitives(option_value == "reftypes"); + } else if (option_name == "generate_equals") { + params.set_generate_equals(option_value == "true"); } else { - *error = "Ignore unknown javanano generator option: " + options[i].first; + *error = "Ignore unknown javanano generator option: " + option_name; } } diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc index 893cdde8..e8326a42 100644 --- a/src/google/protobuf/compiler/javanano/javanano_helpers.cc +++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc @@ -448,7 +448,7 @@ string DefaultValue(const Params& params, const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_ENUM: return ClassName(params, field->enum_type()) + "." + - field->default_value_enum()->name(); + RenameJavaKeywords(field->default_value_enum()->name()); case FieldDescriptor::CPPTYPE_MESSAGE: return "null"; diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc index 06c0b8b2..a3bc3a84 100644 --- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc +++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc @@ -155,38 +155,6 @@ int FixedSize(FieldDescriptor::Type type) { return -1; } -// Returns true if the field has a default value equal to NaN. -bool IsDefaultNaN(const FieldDescriptor* field) { - switch (field->type()) { - case FieldDescriptor::TYPE_INT32 : return false; - case FieldDescriptor::TYPE_UINT32 : return false; - case FieldDescriptor::TYPE_SINT32 : return false; - case FieldDescriptor::TYPE_FIXED32 : return false; - case FieldDescriptor::TYPE_SFIXED32: return false; - case FieldDescriptor::TYPE_INT64 : return false; - case FieldDescriptor::TYPE_UINT64 : return false; - case FieldDescriptor::TYPE_SINT64 : return false; - case FieldDescriptor::TYPE_FIXED64 : return false; - case FieldDescriptor::TYPE_SFIXED64: return false; - case FieldDescriptor::TYPE_FLOAT : - return isnan(field->default_value_float()); - case FieldDescriptor::TYPE_DOUBLE : - return isnan(field->default_value_double()); - case FieldDescriptor::TYPE_BOOL : return false; - case FieldDescriptor::TYPE_STRING : return false; - case FieldDescriptor::TYPE_BYTES : return false; - case FieldDescriptor::TYPE_ENUM : return false; - case FieldDescriptor::TYPE_GROUP : return false; - case FieldDescriptor::TYPE_MESSAGE : return false; - - // No default because we want the compiler to complain if any new - // types are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return false; -} - // Return true if the type is a that has variable length // for instance String's. bool IsVariableLenType(JavaType type) { @@ -273,6 +241,9 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params param (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( WireFormat::TagSize(descriptor->number(), descriptor->type())); + (*variables)["non_packed_tag"] = SimpleItoa( + internal::WireFormatLite::MakeTag(descriptor->number(), + internal::WireFormat::WireTypeForFieldType(descriptor->type()))); int fixed_size = FixedSize(descriptor->type()); if (fixed_size != -1) { (*variables)["fixed_size"] = SimpleItoa(fixed_size); @@ -322,7 +293,7 @@ GenerateMembers(io::Printer* printer, bool lazy_init) const { if (params_.generate_has()) { printer->Print(variables_, - "public boolean has$capitalized_name$ = false;\n"); + "public boolean has$capitalized_name$;\n"); } } @@ -364,15 +335,21 @@ GenerateSerializationConditional(io::Printer* printer) const { printer->Print(variables_, "if ("); } - if (IsArrayType(GetJavaType(descriptor_))) { + JavaType java_type = GetJavaType(descriptor_); + if (IsArrayType(java_type)) { printer->Print(variables_, "!java.util.Arrays.equals(this.$name$, $default$)) {\n"); - } else if (IsReferenceType(GetJavaType(descriptor_))) { + } else if (IsReferenceType(java_type)) { printer->Print(variables_, "!this.$name$.equals($default$)) {\n"); - } else if (IsDefaultNaN(descriptor_)) { + } else if (java_type == JAVATYPE_FLOAT) { printer->Print(variables_, - "!$capitalized_type$.isNaN(this.$name$)) {\n"); + "java.lang.Float.floatToIntBits(this.$name$)\n" + " != java.lang.Float.floatToIntBits($default$)) {\n"); + } else if (java_type == JAVATYPE_DOUBLE) { + printer->Print(variables_, + "java.lang.Double.doubleToLongBits(this.$name$)\n" + " != java.lang.Double.doubleToLongBits($default$)) {\n"); } else { printer->Print(variables_, "this.$name$ != $default$) {\n"); @@ -381,7 +358,8 @@ GenerateSerializationConditional(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { - if (descriptor_->is_required()) { + if (descriptor_->is_required() && !params_.generate_has()) { + // Always serialize a required field if we don't have the 'has' signal. printer->Print(variables_, "output.write$capitalized_type$($number$, this.$name$);\n"); } else { @@ -394,7 +372,7 @@ GenerateSerializationCode(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { - if (descriptor_->is_required()) { + if (descriptor_->is_required() && !params_.generate_has()) { printer->Print(variables_, "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" " .compute$capitalized_type$Size($number$, this.$name$);\n"); @@ -443,6 +421,36 @@ GenerateEqualsCode(io::Printer* printer) const { printer->Print(") {\n" " return false;\n" "}\n"); + } else if (java_type == JAVATYPE_FLOAT) { + printer->Print(variables_, + "{\n" + " int bits = java.lang.Float.floatToIntBits(this.$name$);\n" + " if (bits != java.lang.Float.floatToIntBits(other.$name$)"); + if (params_.generate_has()) { + printer->Print(variables_, + "\n" + " || (bits == java.lang.Float.floatToIntBits($default$)\n" + " && this.has$capitalized_name$ != other.has$capitalized_name$)"); + } + printer->Print(") {\n" + " return false;\n" + " }\n" + "}\n"); + } else if (java_type == JAVATYPE_DOUBLE) { + printer->Print(variables_, + "{\n" + " long bits = java.lang.Double.doubleToLongBits(this.$name$);\n" + " if (bits != java.lang.Double.doubleToLongBits(other.$name$)"); + if (params_.generate_has()) { + printer->Print(variables_, + "\n" + " || (bits == java.lang.Double.doubleToLongBits($default$)\n" + " && this.has$capitalized_name$ != other.has$capitalized_name$)"); + } + printer->Print(") {\n" + " return false;\n" + " }\n" + "}\n"); } else { printer->Print(variables_, "if (this.$name$ != other.$name$"); @@ -602,12 +610,26 @@ GenerateSerializedSizeCode(io::Printer* printer) const { void AccessorPrimitiveFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { switch (GetJavaType(descriptor_)) { - // For all Java primitive types below, the hash codes match the - // results of BoxedType.valueOf(primitiveValue).hashCode(). - case JAVATYPE_INT: - case JAVATYPE_LONG: + // For all Java primitive types below, the equality checks match the + // results of BoxedType.valueOf(primitiveValue).equals(otherValue). case JAVATYPE_FLOAT: + printer->Print(variables_, + "if ($different_has$\n" + " || java.lang.Float.floatToIntBits($name$_)\n" + " != java.lang.Float.floatToIntBits(other.$name$_)) {\n" + " return false;\n" + "}\n"); + break; case JAVATYPE_DOUBLE: + printer->Print(variables_, + "if ($different_has$\n" + " || java.lang.Double.doubleToLongBits($name$_)\n" + " != java.lang.Double.doubleToLongBits(other.$name$_)) {\n" + " return false;\n" + "}\n"); + break; + case JAVATYPE_INT: + case JAVATYPE_LONG: case JAVATYPE_BOOLEAN: printer->Print(variables_, "if ($different_has$\n" @@ -709,7 +731,7 @@ GenerateMergingCode(io::Printer* printer) const { // First, figure out the length of the array, then parse. printer->Print(variables_, "int arrayLength = com.google.protobuf.nano.WireFormatNano\n" - " .getRepeatedFieldArrayLength(input, $tag$);\n" + " .getRepeatedFieldArrayLength(input, $non_packed_tag$);\n" "int i = this.$name$ == null ? 0 : this.$name$.length;\n"); if (GetJavaType(descriptor_) == JAVATYPE_BYTES) { diff --git a/src/google/protobuf/unittest_accessors_nano.proto b/src/google/protobuf/unittest_accessors_nano.proto index 875af25c..f1d4d343 100644 --- a/src/google/protobuf/unittest_accessors_nano.proto +++ b/src/google/protobuf/unittest_accessors_nano.proto @@ -49,6 +49,8 @@ message TestNanoAccessors { // Singular optional int32 optional_int32 = 1; + optional float optional_float = 11; + optional double optional_double = 12; optional string optional_string = 14; optional bytes optional_bytes = 15; diff --git a/src/google/protobuf/unittest_enum_validity_nano.proto b/src/google/protobuf/unittest_enum_validity_nano.proto new file mode 100644 index 00000000..f7f57427 --- /dev/null +++ b/src/google/protobuf/unittest_enum_validity_nano.proto @@ -0,0 +1,28 @@ +package protobuf_unittest; + +option java_package = "com.google.protobuf.nano"; +option java_outer_classname = "EnumValidity"; + +enum E { + default = 1; // test java keyword renaming + FOO = 2; + BAR = 3; + BAZ = 4; +} + +message M { + optional E optional_e = 1; + optional E default_e = 2 [ default = BAZ ]; + repeated E repeated_e = 3; + repeated E packed_e = 4 [ packed = true ]; + repeated E repeated_e2 = 5; + repeated E packed_e2 = 6 [ packed = true ]; + repeated E repeated_e3 = 7; + repeated E packed_e3 = 8 [ packed = true ]; +} + +message Alt { + optional E repeated_e2_as_optional = 5; + repeated E packed_e2_as_non_packed = 6; + repeated E non_packed_e3_as_packed = 7 [ packed = true ]; +} diff --git a/src/google/protobuf/unittest_has_nano.proto b/src/google/protobuf/unittest_has_nano.proto index 3a1e5b5d..289d08ae 100644 --- a/src/google/protobuf/unittest_has_nano.proto +++ b/src/google/protobuf/unittest_has_nano.proto @@ -49,6 +49,8 @@ message TestAllTypesNanoHas { // Singular optional int32 optional_int32 = 1; + optional float optional_float = 11; + optional double optional_double = 12; optional string optional_string = 14; optional bytes optional_bytes = 15; @@ -75,4 +77,6 @@ message TestAllTypesNanoHas { optional NestedEnum default_nested_enum = 81 [default = BAR]; required int32 id = 86; + required NestedEnum required_enum = 87; + } |