aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJon Skeet <jonskeet@google.com>2015-07-16 17:03:06 +0100
committerJon Skeet <jonskeet@google.com>2015-07-16 17:03:06 +0100
commit8a0312b20156aa4df092cb6b3c665ef48cb6fa54 (patch)
tree8a5864fa5e8481ed8b04a25404cf51bc1818a37e /src
parent8d47ec4f3e3368c5f4e7ac195f20978abc8a692f (diff)
downloadprotobuf-8a0312b20156aa4df092cb6b3c665ef48cb6fa54.tar.gz
protobuf-8a0312b20156aa4df092cb6b3c665ef48cb6fa54.tar.bz2
protobuf-8a0312b20156aa4df092cb6b3c665ef48cb6fa54.zip
First pass at wrapper types.
- We do still generate the message types, as otherwise reflection breaks, even though it doesn't actually use those types. - JSON handling hasn't been implemented yet
Diffstat (limited to 'src')
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_field_base.cc41
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_field_base.h1
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_map_field.cc3
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc15
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc83
-rw-r--r--src/google/protobuf/unittest_well_known_types.proto20
6 files changed, 93 insertions, 70 deletions
diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
index f36e6fde..1f583e08 100644
--- a/src/google/protobuf/compiler/csharp/csharp_field_base.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
@@ -309,14 +309,23 @@ std::string FieldGeneratorBase::GetBytesDefaultValueInternal() {
}
std::string FieldGeneratorBase::default_value() {
- switch (descriptor_->type()) {
+ return default_value(descriptor_);
+}
+
+std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) {
+ switch (descriptor->type()) {
case FieldDescriptor::TYPE_ENUM:
- return type_name() + "." + descriptor_->default_value_enum()->name();
+ return type_name() + "." + descriptor->default_value_enum()->name();
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
- return type_name() + ".DefaultInstance";
+ if (IsWrapperType(descriptor)) {
+ const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
+ return default_value(wrapped_field);
+ } else {
+ return "null";
+ }
case FieldDescriptor::TYPE_DOUBLE: {
- double value = descriptor_->default_value_double();
+ double value = descriptor->default_value_double();
if (value == numeric_limits<double>::infinity()) {
return "double.PositiveInfinity";
} else if (value == -numeric_limits<double>::infinity()) {
@@ -327,7 +336,7 @@ std::string FieldGeneratorBase::default_value() {
return SimpleDtoa(value) + "D";
}
case FieldDescriptor::TYPE_FLOAT: {
- float value = descriptor_->default_value_float();
+ float value = descriptor->default_value_float();
if (value == numeric_limits<float>::infinity()) {
return "float.PositiveInfinity";
} else if (value == -numeric_limits<float>::infinity()) {
@@ -338,17 +347,17 @@ std::string FieldGeneratorBase::default_value() {
return SimpleFtoa(value) + "F";
}
case FieldDescriptor::TYPE_INT64:
- return SimpleItoa(descriptor_->default_value_int64()) + "L";
+ return SimpleItoa(descriptor->default_value_int64()) + "L";
case FieldDescriptor::TYPE_UINT64:
- return SimpleItoa(descriptor_->default_value_uint64()) + "UL";
+ return SimpleItoa(descriptor->default_value_uint64()) + "UL";
case FieldDescriptor::TYPE_INT32:
- return SimpleItoa(descriptor_->default_value_int32());
+ return SimpleItoa(descriptor->default_value_int32());
case FieldDescriptor::TYPE_FIXED64:
- return SimpleItoa(descriptor_->default_value_uint64()) + "UL";
+ return SimpleItoa(descriptor->default_value_uint64()) + "UL";
case FieldDescriptor::TYPE_FIXED32:
- return SimpleItoa(descriptor_->default_value_uint32());
+ return SimpleItoa(descriptor->default_value_uint32());
case FieldDescriptor::TYPE_BOOL:
- if (descriptor_->default_value_bool()) {
+ if (descriptor->default_value_bool()) {
return "true";
} else {
return "false";
@@ -358,15 +367,15 @@ std::string FieldGeneratorBase::default_value() {
case FieldDescriptor::TYPE_BYTES:
return GetBytesDefaultValueInternal();
case FieldDescriptor::TYPE_UINT32:
- return SimpleItoa(descriptor_->default_value_uint32());
+ return SimpleItoa(descriptor->default_value_uint32());
case FieldDescriptor::TYPE_SFIXED32:
- return SimpleItoa(descriptor_->default_value_int32());
+ return SimpleItoa(descriptor->default_value_int32());
case FieldDescriptor::TYPE_SFIXED64:
- return SimpleItoa(descriptor_->default_value_int64()) + "L";
+ return SimpleItoa(descriptor->default_value_int64()) + "L";
case FieldDescriptor::TYPE_SINT32:
- return SimpleItoa(descriptor_->default_value_int32());
+ return SimpleItoa(descriptor->default_value_int32());
case FieldDescriptor::TYPE_SINT64:
- return SimpleItoa(descriptor_->default_value_int64()) + "L";
+ return SimpleItoa(descriptor->default_value_int64()) + "L";
default:
GOOGLE_LOG(FATAL)<< "Unknown field type.";
return "";
diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h
index bffa2062..4761dc49 100644
--- a/src/google/protobuf/compiler/csharp/csharp_field_base.h
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h
@@ -82,6 +82,7 @@ class FieldGeneratorBase : public SourceGeneratorBase {
bool has_default_value();
bool is_nullable_type();
std::string default_value();
+ std::string default_value(const FieldDescriptor* descriptor);
std::string number();
std::string capitalized_type_name();
std::string field_ordinal();
diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.cc b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
index 32c05232..cba24a59 100644
--- a/src/google/protobuf/compiler/csharp/csharp_map_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
@@ -61,6 +61,7 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
descriptor_->message_type()->FindFieldByName("value");
variables_["key_type_name"] = type_name(key_descriptor);
variables_["value_type_name"] = type_name(value_descriptor);
+ variables_["true_for_wrappers"] = IsWrapperType(value_descriptor) ? "true" : "";
scoped_ptr<FieldGeneratorBase> key_generator(CreateFieldGenerator(key_descriptor, 1));
scoped_ptr<FieldGeneratorBase> value_generator(CreateFieldGenerator(value_descriptor, 2));
@@ -74,7 +75,7 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
printer->Print(
variables_,
", $tag$);\n"
- "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>();\n");
+ "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>($true_for_wrappers$);\n");
AddDeprecatedFlag(printer);
printer->Print(
variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
index 6d4e6984..d939fc79 100644
--- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
@@ -39,6 +39,8 @@
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
namespace google {
namespace protobuf {
@@ -58,7 +60,18 @@ void RepeatedMessageFieldGenerator::GenerateMembers(io::Printer* printer) {
printer->Print(
variables_,
"private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n"
- " = pb::FieldCodec.ForMessage($tag$, $type_name$.Parser);\n");
+ " = ");
+ // Don't want to duplicate the codec code here... maybe we should have a
+ // "create single field generator for this repeated field"
+ // function, but it doesn't seem worth it for just this.
+ if (IsWrapperType(descriptor_)) {
+ scoped_ptr<FieldGeneratorBase> single_generator(new WrapperFieldGenerator(descriptor_, fieldOrdinal_));
+ single_generator->GenerateCodecCode(printer);
+ } else {
+ scoped_ptr<FieldGeneratorBase> single_generator(new MessageFieldGenerator(descriptor_, fieldOrdinal_));
+ single_generator->GenerateCodecCode(printer);
+ }
+ printer->Print(";\n");
printer->Print(
variables_,
"private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
index eb3791ec..75ef5e50 100644
--- a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
@@ -50,35 +50,34 @@ WrapperFieldGenerator::WrapperFieldGenerator(const FieldDescriptor* descriptor,
: FieldGeneratorBase(descriptor, fieldOrdinal) {
variables_["has_property_check"] = name() + "_ != null";
variables_["has_not_property_check"] = name() + "_ == null";
- variables_["message_type_name"] = GetClassName(descriptor->message_type());
const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
is_value_type = wrapped_field->type() != FieldDescriptor::TYPE_STRING &&
wrapped_field->type() != FieldDescriptor::TYPE_BYTES;
- variables_["deref"] = is_value_type ? ".Value" : "";
- // This will always be a single byte, because it's always field 1.
- variables_["message_tag_bytes"] = SimpleItoa(FixedMakeTag(wrapped_field));
+ if (is_value_type) {
+ variables_["nonnullable_type_name"] = type_name(wrapped_field);
+ }
}
WrapperFieldGenerator::~WrapperFieldGenerator() {
}
void WrapperFieldGenerator::GenerateMembers(io::Printer* printer) {
- // Back the underlying property with an underlying message. This isn't efficient,
- // but it makes it easier to be compliant with what platforms which don't support wrapper
- // types would do. Currently, each time the value is changed, we create a new instance.
- // With suitable care to avoid aliasing, we could probably check whether or not we've already
- // got an instance, and simply mutate the existing one.
+ printer->Print(
+ variables_,
+ "private static readonly pb::FieldCodec<$type_name$> _single_$name$_codec = ");
+ GenerateCodecCode(printer);
printer->Print(
variables_,
- "private $message_type_name$ $name$_;\n");
+ ";\n"
+ "private $type_name$ $name$_;\n");
AddDeprecatedFlag(printer);
printer->Print(
variables_,
"$access_level$ $type_name$ $property_name$ {\n"
- " get { return $name$_ == null ? ($type_name$) null : $name$_.Value; }\n"
+ " get { return $name$_; }\n"
" set {\n"
" pb::Freezable.CheckMutable(this);\n"
- " $name$_ = value == null ? null : new $message_type_name$ { Value = value$deref$ };\n"
+ " $name$_ = value;\n"
" }\n"
"}\n");
}
@@ -87,28 +86,26 @@ void WrapperFieldGenerator::GenerateMergingCode(io::Printer* printer) {
printer->Print(
variables_,
"if (other.$has_property_check$) {\n"
- " if ($has_not_property_check$) {\n"
- " $name$_ = new $message_type_name$();\n"
+ " if ($has_not_property_check$ || other.$property_name$ != $default_value$) {\n"
+ " $property_name$ = other.$property_name$;\n"
" }\n"
- " $name$_.MergeFrom(other.$name$_);\n"
"}\n");
}
void WrapperFieldGenerator::GenerateParsingCode(io::Printer* printer) {
printer->Print(
variables_,
- "if ($has_not_property_check$) {\n"
- " $name$_ = new $message_type_name$();\n"
- "}\n"
- "input.ReadMessage($name$_);\n"); // No need to support TYPE_GROUP...
+ "$type_name$ value = _single_$name$_codec.Read(input);\n"
+ "if ($has_not_property_check$ || value != $default_value$) {\n"
+ " $property_name$ = value;\n"
+ "}\n");
}
void WrapperFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
printer->Print(
variables_,
"if ($has_property_check$) {\n"
- " output.WriteRawTag($tag_bytes$);\n"
- " output.WriteMessage($name$_);\n"
+ " _single_$name$_codec.WriteTagAndValue(output, $property_name$);\n"
"}\n");
}
@@ -116,7 +113,7 @@ void WrapperFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
printer->Print(
variables_,
"if ($has_property_check$) {\n"
- " size += $tag_size$ + pb::CodedOutputStream.ComputeMessageSize($name$_);\n"
+ " size += _single_$name$_codec.CalculateSizeWithTag($property_name$);\n"
"}\n");
}
@@ -137,16 +134,20 @@ void WrapperFieldGenerator::WriteToString(io::Printer* printer) {
}
void WrapperFieldGenerator::GenerateCloningCode(io::Printer* printer) {
- // This will effectively perform a deep clone - it will create a new
- // underlying message if necessary
printer->Print(variables_,
"$property_name$ = other.$property_name$;\n");
}
void WrapperFieldGenerator::GenerateCodecCode(io::Printer* printer) {
- printer->Print(
- variables_,
- "pb::FieldCodec.ForWrapperType<$type_name$, $message_type_name$>($tag$, $message_type_name$.Parser)");
+ if (is_value_type) {
+ printer->Print(
+ variables_,
+ "pb::FieldCodec.ForStructWrapper<$nonnullable_type_name$>($tag$)");
+ } else {
+ printer->Print(
+ variables_,
+ "pb::FieldCodec.ForClassWrapper<$type_name$>($tag$)");
+ }
}
WrapperOneofFieldGenerator::WrapperOneofFieldGenerator(const FieldDescriptor* descriptor,
@@ -159,48 +160,46 @@ WrapperOneofFieldGenerator::~WrapperOneofFieldGenerator() {
}
void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+ // Note: deliberately _oneof_$name$_codec, not _$oneof_name$_codec... we have one codec per field.
+ printer->Print(
+ variables_,
+ "private static readonly pb::FieldCodec<$type_name$> _oneof_$name$_codec = ");
+ GenerateCodecCode(printer);
+ printer->Print(";\n");
AddDeprecatedFlag(printer);
printer->Print(
variables_,
"$access_level$ $type_name$ $property_name$ {\n"
- " get { return $has_property_check$ ? (($message_type_name$) $oneof_name$_).Value : ($type_name$) null; }\n"
+ " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : ($type_name$) null; }\n"
" set {\n"
" pb::Freezable.CheckMutable(this);\n"
- " $oneof_name$_ = value == null ? null : new $message_type_name$ { Value = value$deref$ };\n"
+ " $oneof_name$_ = value;\n"
" $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n"
" }\n"
"}\n");
}
-
-
void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
printer->Print(
variables_,
- "$message_type_name$ subBuilder = new $message_type_name$();\n"
- "if ($has_property_check$) {\n"
- " subBuilder.MergeFrom(($message_type_name$) $oneof_name$_);\n"
- "}\n"
- "input.ReadMessage(subBuilder);\n"
- // Don't set the property, which would create a new and equivalent message; just set the two fields.
- "$oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n"
- "$oneof_name$_ = subBuilder;\n");
+ "$property_name$ = _oneof_$name$_codec.Read(input);\n");
}
void WrapperOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+ // TODO: I suspect this is wrong...
printer->Print(
variables_,
"if ($has_property_check$) {\n"
- " output.WriteRawTag($tag_bytes$);\n"
- " output.WriteMessage(($message_type_name$) $oneof_name$_);\n"
+ " _oneof_$name$_codec.WriteTagAndValue(output, ($type_name$) $oneof_name$_);\n"
"}\n");
}
void WrapperOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+ // TODO: I suspect this is wrong...
printer->Print(
variables_,
"if ($has_property_check$) {\n"
- " size += $tag_size$ + pb::CodedOutputStream.ComputeMessageSize((($message_type_name$) $oneof_name$_));\n"
+ " size += _oneof_$name$_codec.CalculateSizeWithTag($property_name$);\n"
"}\n");
}
diff --git a/src/google/protobuf/unittest_well_known_types.proto b/src/google/protobuf/unittest_well_known_types.proto
index 4771c094..2cb7775c 100644
--- a/src/google/protobuf/unittest_well_known_types.proto
+++ b/src/google/protobuf/unittest_well_known_types.proto
@@ -52,16 +52,16 @@ message RepeatedWellKnownTypes {
repeated google.protobuf.Struct struct_field = 7;
repeated google.protobuf.Timestamp timestamp_field = 8;
repeated google.protobuf.Type type_field = 9;
- // TODO: Do these even make sense? Should they be prohibited?
-// repeated google.protobuf.DoubleValue double_field = 10;
-// repeated google.protobuf.FloatValue float_field = 11;
-// repeated google.protobuf.Int64Value int64_field = 12;
-// repeated google.protobuf.UInt64Value uint64_field = 13;
-// repeated google.protobuf.Int32Value int32_field = 14;
-// repeated google.protobuf.UInt32Value uint32_field = 15;
-// repeated google.protobuf.BoolValue bool_field = 16;
-// repeated google.protobuf.StringValue string_field = 17;
-// repeated google.protobuf.BytesValue bytes_field = 18;
+ // These don't actually make a lot of sense, but they're not prohibited...
+ repeated google.protobuf.DoubleValue double_field = 10;
+ repeated google.protobuf.FloatValue float_field = 11;
+ repeated google.protobuf.Int64Value int64_field = 12;
+ repeated google.protobuf.UInt64Value uint64_field = 13;
+ repeated google.protobuf.Int32Value int32_field = 14;
+ repeated google.protobuf.UInt32Value uint32_field = 15;
+ repeated google.protobuf.BoolValue bool_field = 16;
+ repeated google.protobuf.StringValue string_field = 17;
+ repeated google.protobuf.BytesValue bytes_field = 18;
}
message OneofWellKnownTypes {