diff options
Diffstat (limited to 'src/google/protobuf/compiler/csharp')
31 files changed, 4994 insertions, 0 deletions
diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.cc b/src/google/protobuf/compiler/csharp/csharp_enum.cc new file mode 100644 index 00000000..27643e61 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc @@ -0,0 +1,79 @@ +// 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. + +#include <sstream> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/stubs/strutil.h> + +#include <google/protobuf/compiler/csharp/csharp_enum.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +using google::protobuf::internal::scoped_ptr; + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) : + SourceGeneratorBase(descriptor->file()), + descriptor_(descriptor) { +} + +EnumGenerator::~EnumGenerator() { +} + +void EnumGenerator::Generate(Writer* writer) { + WriteGeneratedCodeAttributes(writer); + writer->WriteLine("$0$ enum $1$ {", + class_access_level(), + descriptor_->name()); + writer->Indent(); + for (int i = 0; i < descriptor_->value_count(); i++) { + writer->WriteLine("$0$ = $1$,", + descriptor_->value(i)->name(), + SimpleItoa(descriptor_->value(i)->number())); + } + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.h b/src/google/protobuf/compiler/csharp/csharp_enum.h new file mode 100644 index 00000000..eaa7a9c5 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_enum.h @@ -0,0 +1,65 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class EnumGenerator : public SourceGeneratorBase { + public: + EnumGenerator(const EnumDescriptor* descriptor); + ~EnumGenerator(); + + void Generate(Writer* writer); + + private: + const EnumDescriptor* descriptor_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc new file mode 100644 index 00000000..34d1c5c6 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc @@ -0,0 +1,199 @@ +// 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. + +#include <sstream> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> + +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_enum_field.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal) + : FieldGeneratorBase(descriptor, fieldOrdinal) { +} + +EnumFieldGenerator::~EnumFieldGenerator() { + +} + +void EnumFieldGenerator::GenerateMembers(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("private bool has$0$;", property_name()); + } + writer->WriteLine("private $0$ $1$_ = $2$;", type_name(), name(), + default_value()); + AddDeprecatedFlag(writer); + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return has$0$; }", property_name()); + writer->WriteLine("}"); + } + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return $0$_; }", name()); + writer->WriteLine("}"); +} + +void EnumFieldGenerator::GenerateBuilderMembers(Writer* writer) { + AddDeprecatedFlag(writer); + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return result.has$0$; }", property_name()); + writer->WriteLine("}"); + } + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return result.$0$; }", property_name()); + writer->WriteLine(" set { Set$0$(value); }", property_name()); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public Builder Set$0$($1$ value) {", property_name(), + type_name()); + writer->WriteLine(" PrepareBuilder();"); + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine(" result.has$0$ = true;", property_name()); + } + writer->WriteLine(" result.$0$_ = value;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine(" result.has$0$ = false;", property_name()); + } + writer->WriteLine(" result.$0$_ = $1$;", name(), default_value()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void EnumFieldGenerator::GenerateMergingCode(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("if (other.Has$0$) {", property_name()); + } else { + writer->WriteLine("if (other.$0$ != $1$) {", property_name(), default_value()); + } + writer->WriteLine(" $0$ = other.$0$;", property_name()); + writer->WriteLine("}"); +} + +void EnumFieldGenerator::GenerateBuildingCode(Writer* writer) { + // Nothing to do here for enum types +} + +void EnumFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine("object unknown;"); + writer->WriteLine("if(input.ReadEnum(ref result.$0$_, out unknown)) {", + name()); + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine(" result.has$0$ = true;", property_name()); + } + writer->WriteLine("} else if(unknown is int) {"); + if (!use_lite_runtime()) { + writer->WriteLine(" if (unknownFields == null) {"); // First unknown field - create builder now + writer->WriteLine( + " unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);"); + writer->WriteLine(" }"); + writer->WriteLine( + " unknownFields.MergeVarintField($0$, (ulong)(int)unknown);", + number()); + } + writer->WriteLine("}"); +} + +void EnumFieldGenerator::GenerateSerializationCode(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("if (has$0$) {", property_name()); + } else { + writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value()); + } + writer->WriteLine( + " output.WriteEnum($0$, field_names[$2$], (int) $1$, $1$);", number(), + property_name(), field_ordinal()); + writer->WriteLine("}"); +} + +void EnumFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("if (has$0$) {", property_name()); + } else { + writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value()); + } + writer->WriteLine( + " size += pb::CodedOutputStream.ComputeEnumSize($0$, (int) $1$);", + number(), property_name()); + writer->WriteLine("}"); +} + +void EnumFieldGenerator::WriteHash(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("if (has$0$) {", property_name()); + } else { + writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value()); + } + writer->WriteLine(" hash ^= $0$_.GetHashCode();", name()); + writer->WriteLine("}"); +} +void EnumFieldGenerator::WriteEquals(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine( + "if (has$0$ != other.has$0$ || (has$0$ && !$1$_.Equals(other.$1$_))) return false;", + property_name(), name()); + } else { + writer->WriteLine( + "if (!$0$_.Equals(other.$0$_)) return false;", name()); + } +} +void EnumFieldGenerator::WriteToString(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("PrintField(\"$0$\", has$1$, $2$_, writer);", + descriptor_->name(), property_name(), name()); + } else { + writer->WriteLine("PrintField(\"$0$\", $1$_, writer);", + descriptor_->name(), name()); + } +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_enum_field.h new file mode 100644 index 00000000..b21fa9dc --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class EnumFieldGenerator : public FieldGeneratorBase { + public: + EnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~EnumFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void GenerateMergingCode(Writer* writer); + virtual void GenerateBuildingCode(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + virtual void GenerateSerializationCode(Writer* writer); + virtual void GenerateSerializedSizeCode(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_extension.cc b/src/google/protobuf/compiler/csharp/csharp_extension.cc new file mode 100644 index 00000000..2bac320d --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_extension.cc @@ -0,0 +1,166 @@ +// 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. + +#include <sstream> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> + +#include <google/protobuf/compiler/csharp/csharp_extension.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +using google::protobuf::internal::scoped_ptr; + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor) + : FieldGeneratorBase(descriptor, 0) { + if (descriptor_->extension_scope()) { + scope_ = GetClassName(descriptor_->extension_scope()); + } else { + scope_ = GetFullUmbrellaClassName(descriptor_->file()); + } + extends_ = GetClassName(descriptor_->containing_type()); +} + +ExtensionGenerator::~ExtensionGenerator() { +} + +void ExtensionGenerator::Generate(Writer* writer) { + writer->WriteLine("public const int $0$ = $1$;", + GetFieldConstantName(descriptor_), + SimpleItoa(descriptor_->number())); + + if (use_lite_runtime()) { + // TODO(jtattermusch): include the following check + //if (Descriptor.MappedType == MappedType.Message && Descriptor.MessageType.Options.MessageSetWireFormat) + //{ + // throw new ArgumentException( + // "option message_set_wire_format = true; is not supported in Lite runtime extensions."); + //} + + writer->Write("$0$ ", class_access_level()); + writer->WriteLine( + "static pb::$3$<$0$, $1$> $2$;", + extends_, + type_name(), + property_name(), + descriptor_->is_repeated() ? + "GeneratedRepeatExtensionLite" : "GeneratedExtensionLite"); + } else if (descriptor_->is_repeated()) { + writer->WriteLine( + "$0$ static pb::GeneratedExtensionBase<scg::IList<$1$>> $2$;", + class_access_level(), type_name(), property_name()); + } else { + writer->WriteLine("$0$ static pb::GeneratedExtensionBase<$1$> $2$;", + class_access_level(), type_name(), property_name()); + } +} + +void ExtensionGenerator::GenerateStaticVariableInitializers(Writer* writer) { + if (use_lite_runtime()) { + writer->WriteLine("$0$.$1$ = ", scope_, property_name()); + writer->Indent(); + writer->WriteLine( + "new pb::$0$<$1$, $2$>(", + descriptor_->is_repeated() ? + "GeneratedRepeatExtensionLite" : "GeneratedExtensionLite", + extends_, type_name()); + writer->Indent(); + writer->WriteLine("\"$0$\",", descriptor_->full_name()); + writer->WriteLine("$0$.DefaultInstance,", extends_); + if (!descriptor_->is_repeated()) { + std::string default_val; + if (descriptor_->has_default_value()) { + default_val = default_value(); + } else { + default_val = is_nullable_type() ? "null" : ("default(" + type_name() + ")"); + } + writer->WriteLine("$0$,", default_val); + } + writer->WriteLine( + "$0$,", + (GetCSharpType(descriptor_->type()) == CSHARPTYPE_MESSAGE) ? + type_name() + ".DefaultInstance" : "null"); + writer->WriteLine( + "$0$,", + (GetCSharpType(descriptor_->type()) == CSHARPTYPE_ENUM) ? + "new EnumLiteMap<" + type_name() + ">()" : "null"); + writer->WriteLine("$0$.$1$FieldNumber,", scope_, + GetPropertyName(descriptor_)); + writer->Write("pbd::FieldType.$0$", capitalized_type_name()); + if (descriptor_->is_repeated()) { + writer->WriteLine(","); + writer->Write(descriptor_->is_packed() ? "true" : "false"); + } + writer->Outdent(); + writer->WriteLine(");"); + writer->Outdent(); + } + else if (descriptor_->is_repeated()) + { + writer->WriteLine( + "$0$.$1$ = pb::GeneratedRepeatExtension<$2$>.CreateInstance($0$.Descriptor.Extensions[$3$]);", + scope_, property_name(), type_name(), SimpleItoa(descriptor_->index())); + } + else + { + writer->WriteLine( + "$0$.$1$ = pb::GeneratedSingleExtension<$2$>.CreateInstance($0$.Descriptor.Extensions[$3$]);", + scope_, property_name(), type_name(), SimpleItoa(descriptor_->index())); + } +} + +void ExtensionGenerator::GenerateExtensionRegistrationCode(Writer* writer) { + writer->WriteLine("registry.Add($0$.$1$);", scope_, property_name()); +} + +void ExtensionGenerator::WriteHash(Writer* writer) { +} + +void ExtensionGenerator::WriteEquals(Writer* writer) { +} + +void ExtensionGenerator::WriteToString(Writer* writer) { +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_extension.h b/src/google/protobuf/compiler/csharp/csharp_extension.h new file mode 100644 index 00000000..203f6e5e --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_extension.h @@ -0,0 +1,80 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_EXTENSION_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_EXTENSION_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class ExtensionGenerator : public FieldGeneratorBase { + public: + ExtensionGenerator(const FieldDescriptor* descriptor); + ~ExtensionGenerator(); + + void GenerateStaticVariableInitializers(Writer* writer); + void GenerateExtensionRegistrationCode(Writer* writer); + void Generate(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + virtual void GenerateMembers(Writer* writer) {}; + virtual void GenerateBuilderMembers(Writer* writer) {}; + virtual void GenerateMergingCode(Writer* writer) {}; + virtual void GenerateBuildingCode(Writer* writer) {}; + virtual void GenerateParsingCode(Writer* writer) {}; + virtual void GenerateSerializationCode(Writer* writer) {}; + virtual void GenerateSerializedSizeCode(Writer* writer) {}; + + private: + std::string scope_; + std::string extends_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_EXTENSION_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc new file mode 100644 index 00000000..145b6743 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc @@ -0,0 +1,380 @@ +// 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. + +#include <limits> +#include <sstream> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/stubs/strutil.h> + +#include <google/protobuf/compiler/csharp/csharp_field_base.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +using google::protobuf::internal::scoped_ptr; + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor, + int fieldOrdinal) + : SourceGeneratorBase(descriptor->file()), + descriptor_(descriptor), + fieldOrdinal_(fieldOrdinal) { +} + +FieldGeneratorBase::~FieldGeneratorBase() { +} + +void FieldGeneratorBase::AddDeprecatedFlag(Writer* writer) { + if (descriptor_->options().deprecated()) + { + writer->WriteLine("[global::System.ObsoleteAttribute()]"); + } +} + +void FieldGeneratorBase::AddNullCheck(Writer* writer) { + AddNullCheck(writer, "value"); +} + +void FieldGeneratorBase::AddNullCheck(Writer* writer, const std::string& name) { + if (is_nullable_type()) { + writer->WriteLine(" pb::ThrowHelper.ThrowIfNull($0$, \"$0$\");", name); + } +} + +void FieldGeneratorBase::AddPublicMemberAttributes(Writer* writer) { + AddDeprecatedFlag(writer); +} + +std::string FieldGeneratorBase::property_name() { + return GetPropertyName(descriptor_); +} + +std::string FieldGeneratorBase::name() { + return UnderscoresToCamelCase(GetFieldName(descriptor_), false); +} + +std::string FieldGeneratorBase::type_name() { + switch (descriptor_->type()) { + case FieldDescriptor::TYPE_ENUM: + return GetClassName(descriptor_->enum_type()); + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + return GetClassName(descriptor_->message_type()); + case FieldDescriptor::TYPE_DOUBLE: + return "double"; + case FieldDescriptor::TYPE_FLOAT: + return "float"; + case FieldDescriptor::TYPE_INT64: + return "long"; + case FieldDescriptor::TYPE_UINT64: + return "ulong"; + case FieldDescriptor::TYPE_INT32: + return "int"; + case FieldDescriptor::TYPE_FIXED64: + return "ulong"; + case FieldDescriptor::TYPE_FIXED32: + return "uint"; + case FieldDescriptor::TYPE_BOOL: + return "bool"; + case FieldDescriptor::TYPE_STRING: + return "string"; + case FieldDescriptor::TYPE_BYTES: + return "pb::ByteString"; + case FieldDescriptor::TYPE_UINT32: + return "uint"; + case FieldDescriptor::TYPE_SFIXED32: + return "int"; + case FieldDescriptor::TYPE_SFIXED64: + return "long"; + case FieldDescriptor::TYPE_SINT32: + return "int"; + case FieldDescriptor::TYPE_SINT64: + return "long"; + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return ""; + } +} + +bool FieldGeneratorBase::has_default_value() { + switch (descriptor_->type()) { + case FieldDescriptor::TYPE_ENUM: + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + return true; + case FieldDescriptor::TYPE_DOUBLE: + return descriptor_->default_value_double() != 0.0; + case FieldDescriptor::TYPE_FLOAT: + return descriptor_->default_value_float() != 0.0; + case FieldDescriptor::TYPE_INT64: + return descriptor_->default_value_int64() != 0L; + case FieldDescriptor::TYPE_UINT64: + return descriptor_->default_value_uint64() != 0L; + case FieldDescriptor::TYPE_INT32: + return descriptor_->default_value_int32() != 0; + case FieldDescriptor::TYPE_FIXED64: + return descriptor_->default_value_uint64() != 0L; + case FieldDescriptor::TYPE_FIXED32: + return descriptor_->default_value_uint32() != 0; + case FieldDescriptor::TYPE_BOOL: + return descriptor_->default_value_bool(); + case FieldDescriptor::TYPE_STRING: + return true; + case FieldDescriptor::TYPE_BYTES: + return true; + case FieldDescriptor::TYPE_UINT32: + return descriptor_->default_value_uint32() != 0; + case FieldDescriptor::TYPE_SFIXED32: + return descriptor_->default_value_int32() != 0; + case FieldDescriptor::TYPE_SFIXED64: + return descriptor_->default_value_int64() != 0L; + case FieldDescriptor::TYPE_SINT32: + return descriptor_->default_value_int32() != 0; + case FieldDescriptor::TYPE_SINT64: + return descriptor_->default_value_int64() != 0L; + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return true; + } +} + +bool FieldGeneratorBase::is_nullable_type() { + switch (descriptor_->type()) { + case FieldDescriptor::TYPE_ENUM: + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_FLOAT: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_BOOL: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SINT64: + return false; + + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + return true; + + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return true; + } +} + +inline bool IsNaN(double value) { + // NaN is never equal to anything, even itself. + return value != value; +} + +bool AllPrintableAscii(const std::string& text) { + for(int i = 0; i < text.size(); i++) { + if (text[i] < 0x20 || text[i] > 0x7e) { + return false; + } + } + return true; +} + +std::string FieldGeneratorBase::GetStringDefaultValueInternal() { + if (!descriptor_->has_default_value()) { + return "\"\""; + } + if (AllPrintableAscii(descriptor_->default_value_string())) { + // All chars are ASCII and printable. In this case we only + // need to escape quotes and backslashes. + std::string temp = descriptor_->default_value_string(); + temp = StringReplace(temp, "\\", "\\\\", true); + temp = StringReplace(temp, "'", "\\'", true); + temp = StringReplace(temp, "\"", "\\\"", true); + return "\"" + temp + "\""; + } + if (use_lite_runtime()) { + return "pb::ByteString.FromBase64(\"" + + StringToBase64(descriptor_->default_value_string()) + + "\").ToStringUtf8()"; + } + return "(string) " + GetClassName(descriptor_->containing_type()) + + ".Descriptor.Fields[" + SimpleItoa(descriptor_->index()) + + "].DefaultValue"; +} + +std::string FieldGeneratorBase::GetBytesDefaultValueInternal() { + if (!descriptor_->has_default_value()) { + return "pb::ByteString.Empty"; + } + if (use_lite_runtime()) { + return "pb::ByteString.FromBase64(\"" + StringToBase64(descriptor_->default_value_string()) + "\")"; + } + return "(pb::ByteString) "+ GetClassName(descriptor_->containing_type()) + + ".Descriptor.Fields[" + SimpleItoa(descriptor_->index()) + "].DefaultValue"; +} + +std::string FieldGeneratorBase::default_value() { + switch (descriptor_->type()) { + case FieldDescriptor::TYPE_ENUM: + return type_name() + "." + descriptor_->default_value_enum()->name(); + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + return type_name() + ".DefaultInstance"; + case FieldDescriptor::TYPE_DOUBLE: { + double value = descriptor_->default_value_double(); + if (value == numeric_limits<double>::infinity()) { + return "double.PositiveInfinity"; + } else if (value == -numeric_limits<double>::infinity()) { + return "double.NegativeInfinity"; + } else if (IsNaN(value)) { + return "double.NaN"; + } + return SimpleDtoa(value) + "D"; + } + case FieldDescriptor::TYPE_FLOAT: { + float value = descriptor_->default_value_float(); + if (value == numeric_limits<float>::infinity()) { + return "float.PositiveInfinity"; + } else if (value == -numeric_limits<float>::infinity()) { + return "float.NegativeInfinity"; + } else if (IsNaN(value)) { + return "float.NaN"; + } + return SimpleFtoa(value) + "F"; + } + case FieldDescriptor::TYPE_INT64: + return SimpleItoa(descriptor_->default_value_int64()) + "L"; + case FieldDescriptor::TYPE_UINT64: + return SimpleItoa(descriptor_->default_value_uint64()) + "UL"; + case FieldDescriptor::TYPE_INT32: + return SimpleItoa(descriptor_->default_value_int32()); + case FieldDescriptor::TYPE_FIXED64: + return SimpleItoa(descriptor_->default_value_uint64()) + "UL"; + case FieldDescriptor::TYPE_FIXED32: + return SimpleItoa(descriptor_->default_value_uint32()); + case FieldDescriptor::TYPE_BOOL: + if (descriptor_->default_value_bool()) { + return "true"; + } else { + return "false"; + } + case FieldDescriptor::TYPE_STRING: + return GetStringDefaultValueInternal(); + case FieldDescriptor::TYPE_BYTES: + return GetBytesDefaultValueInternal(); + case FieldDescriptor::TYPE_UINT32: + return SimpleItoa(descriptor_->default_value_uint32()); + case FieldDescriptor::TYPE_SFIXED32: + return SimpleItoa(descriptor_->default_value_int32()); + case FieldDescriptor::TYPE_SFIXED64: + return SimpleItoa(descriptor_->default_value_int64()) + "L"; + case FieldDescriptor::TYPE_SINT32: + return SimpleItoa(descriptor_->default_value_int32()); + case FieldDescriptor::TYPE_SINT64: + return SimpleItoa(descriptor_->default_value_int64()) + "L"; + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return ""; + } +} + +std::string FieldGeneratorBase::number() { + return SimpleItoa(descriptor_->number()); +} + +std::string FieldGeneratorBase::message_or_group() { + return + (descriptor_->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message"; +} + +std::string FieldGeneratorBase::capitalized_type_name() { + switch (descriptor_->type()) { + case FieldDescriptor::TYPE_ENUM: + return "Enum"; + case FieldDescriptor::TYPE_MESSAGE: + return "Message"; + case FieldDescriptor::TYPE_GROUP: + return "Group"; + case FieldDescriptor::TYPE_DOUBLE: + return "Double"; + case FieldDescriptor::TYPE_FLOAT: + return "Float"; + case FieldDescriptor::TYPE_INT64: + return "Int64"; + case FieldDescriptor::TYPE_UINT64: + return "UInt64"; + case FieldDescriptor::TYPE_INT32: + return "Int32"; + case FieldDescriptor::TYPE_FIXED64: + return "Fixed64"; + case FieldDescriptor::TYPE_FIXED32: + return "Fixed32"; + case FieldDescriptor::TYPE_BOOL: + return "Bool"; + case FieldDescriptor::TYPE_STRING: + return "String"; + case FieldDescriptor::TYPE_BYTES: + return "Bytes"; + case FieldDescriptor::TYPE_UINT32: + return "UInt32"; + case FieldDescriptor::TYPE_SFIXED32: + return "SFixed32"; + case FieldDescriptor::TYPE_SFIXED64: + return "SFixed64"; + case FieldDescriptor::TYPE_SINT32: + return "SInt32"; + case FieldDescriptor::TYPE_SINT64: + return "SInt64"; + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return ""; + } +} + +std::string FieldGeneratorBase::field_ordinal() { + return SimpleItoa(fieldOrdinal_); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h new file mode 100644 index 00000000..311f7a6e --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h @@ -0,0 +1,98 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__ + +#include <string> +#include <google/protobuf/stubs/strutil.h> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class FieldGeneratorBase : public SourceGeneratorBase { + public: + FieldGeneratorBase(const FieldDescriptor* descriptor, int fieldOrdinal); + ~FieldGeneratorBase(); + + virtual void GenerateMembers(Writer* writer) = 0; + virtual void GenerateBuilderMembers(Writer* writer) = 0; + virtual void GenerateMergingCode(Writer* writer) = 0; + virtual void GenerateBuildingCode(Writer* writer) = 0; + virtual void GenerateParsingCode(Writer* writer) = 0; + virtual void GenerateSerializationCode(Writer* writer) = 0; + virtual void GenerateSerializedSizeCode(Writer* writer) = 0; + + virtual void WriteHash(Writer* writer) = 0; + virtual void WriteEquals(Writer* writer) = 0; + virtual void WriteToString(Writer* writer) = 0; + + protected: + const FieldDescriptor* descriptor_; + const int fieldOrdinal_; + + void AddDeprecatedFlag(Writer* writer); + void AddNullCheck(Writer* writer); + void AddNullCheck(Writer* writer, const std::string& name); + + void AddPublicMemberAttributes(Writer* writer); + + std::string property_name(); + std::string name(); + std::string type_name(); + bool has_default_value(); + bool is_nullable_type(); + std::string default_value(); + std::string number(); + std::string message_or_group(); + std::string capitalized_type_name(); + std::string field_ordinal(); + + private: + std::string GetStringDefaultValueInternal(); + std::string GetBytesDefaultValueInternal(); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorBase); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc new file mode 100644 index 00000000..64c4bd7d --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc @@ -0,0 +1,96 @@ +// 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. + +#include <sstream> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> + +#include <google/protobuf/compiler/csharp/csharp_generator.h> +#include <google/protobuf/compiler/csharp/csharp_umbrella_class.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +using google::protobuf::internal::scoped_ptr; + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +std::string GetOutputFile(const google::protobuf::FileDescriptor* file, const std::string file_extension) +{ + return GetFileUmbrellaClassname(file) + file_extension; +} + +void GenerateFile(const google::protobuf::FileDescriptor* file, + Writer* writer) { + UmbrellaClassGenerator umbrellaGenerator(file); + umbrellaGenerator.Generate(writer); +} + +bool Generator::Generate( + const FileDescriptor* file, + const string& parameter, + GeneratorContext* generator_context, + string* error) const { + + vector<pair<string, string> > options; + ParseGeneratorParameter(parameter, &options); + + std::string file_extension = ".cs"; + for (int i = 0; i < options.size(); i++) { + if (options[i].first == "file_extension") { + file_extension = options[i].second; + } else { + *error = "Unknown generator option: " + options[i].first; + return false; + } + } + + std::string filename = GetOutputFile(file, file_extension); + scoped_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(filename)); + io::Printer printer(output.get(), '$'); + Writer writer(&printer); + + GenerateFile(file, &writer); + + return true; +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.h b/src/google/protobuf/compiler/csharp/csharp_generator.h new file mode 100644 index 00000000..9b54e914 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_generator.h @@ -0,0 +1,58 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class LIBPROTOC_EXPORT Generator + : public google::protobuf::compiler::CodeGenerator { + virtual bool Generate( + const FileDescriptor* file, + const string& parameter, + GeneratorContext* generator_context, + string* error) const; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc new file mode 100644 index 00000000..7ef7df42 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc @@ -0,0 +1,54 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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. + +#include <memory> + +#include <google/protobuf/compiler/ruby/ruby_generator.h> +#include <google/protobuf/compiler/command_line_interface.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/io/printer.h> + +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> +#include <google/protobuf/testing/file.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { +namespace { + +// TODO(jtattermusch): add some tests. + +} // namespace +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc new file mode 100644 index 00000000..4580b7be --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc @@ -0,0 +1,409 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <algorithm> +#include <google/protobuf/stubs/hash.h> +#include <limits> +#include <vector> + +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> + +#include <google/protobuf/compiler/csharp/csharp_field_base.h> +#include <google/protobuf/compiler/csharp/csharp_enum_field.h> +#include <google/protobuf/compiler/csharp/csharp_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_primitive_field.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +CSharpType GetCSharpType(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32: + return CSHARPTYPE_INT32; + case FieldDescriptor::TYPE_INT64: + return CSHARPTYPE_INT64; + case FieldDescriptor::TYPE_UINT32: + return CSHARPTYPE_UINT32; + case FieldDescriptor::TYPE_UINT64: + return CSHARPTYPE_UINT32; + case FieldDescriptor::TYPE_SINT32: + return CSHARPTYPE_INT32; + case FieldDescriptor::TYPE_SINT64: + return CSHARPTYPE_INT64; + case FieldDescriptor::TYPE_FIXED32: + return CSHARPTYPE_UINT32; + case FieldDescriptor::TYPE_FIXED64: + return CSHARPTYPE_UINT64; + case FieldDescriptor::TYPE_SFIXED32: + return CSHARPTYPE_INT32; + case FieldDescriptor::TYPE_SFIXED64: + return CSHARPTYPE_INT64; + case FieldDescriptor::TYPE_FLOAT: + return CSHARPTYPE_FLOAT; + case FieldDescriptor::TYPE_DOUBLE: + return CSHARPTYPE_DOUBLE; + case FieldDescriptor::TYPE_BOOL: + return CSHARPTYPE_BOOL; + case FieldDescriptor::TYPE_ENUM: + return CSHARPTYPE_ENUM; + case FieldDescriptor::TYPE_STRING: + return CSHARPTYPE_STRING; + case FieldDescriptor::TYPE_BYTES: + return CSHARPTYPE_BYTESTRING; + case FieldDescriptor::TYPE_GROUP: + return CSHARPTYPE_MESSAGE; + case FieldDescriptor::TYPE_MESSAGE: + return CSHARPTYPE_MESSAGE; + + // No default because we want the compiler to complain if any new + // types are added. + } + GOOGLE_LOG(FATAL)<< "Can't get here."; + return (CSharpType) -1; +} + +std::string StripDotProto(const std::string& proto_file) { + int lastindex = proto_file.find_last_of("."); + return proto_file.substr(0, lastindex); +} + +std::string GetFileNamespace(const FileDescriptor* descriptor) { + if (descriptor->options().has_csharp_namespace()) { + return descriptor->options().csharp_namespace(); + } + return descriptor->package(); +} + +std::string GetUmbrellaClassNameInternal(const std::string& proto_file) { + int lastslash = proto_file.find_last_of("/"); + std::string base = proto_file.substr(lastslash + 1); + return UnderscoresToPascalCase(StripDotProto(base)); +} + +std::string GetFileUmbrellaClassname(const FileDescriptor* descriptor) { + // umbrella_classname can no longer be set using message option. + return GetUmbrellaClassNameInternal(descriptor->name()); +} + +std::string GetFileUmbrellaNamespace(const FileDescriptor* descriptor) { + // TODO(jtattermusch): reintroduce csharp_umbrella_namespace option + bool collision = false; + std::string umbrella_classname = GetFileUmbrellaClassname(descriptor); + for(int i = 0; i < descriptor->message_type_count(); i++) { + if (descriptor->message_type(i)->name() == umbrella_classname) { + collision = true; + break; + } + } + for (int i = 0; i < descriptor->service_count(); i++) { + if (descriptor->service(i)->name() == umbrella_classname) { + collision = true; + break; + } + } + for (int i = 0; i < descriptor->enum_type_count(); i++) { + if (descriptor->enum_type(i)->name() == umbrella_classname) { + collision = true; + break; + } + } + return collision ? "Proto" : ""; +} + +// TODO(jtattermusch): can we reuse a utility function? +std::string UnderscoresToCamelCase(const std::string& input, + bool cap_next_letter) { + string result; + // Note: I distrust ctype.h due to locales. + for (int i = 0; i < input.size(); i++) { + if ('a' <= input[i] && input[i] <= 'z') { + if (cap_next_letter) { + result += input[i] + ('A' - 'a'); + } else { + result += input[i]; + } + cap_next_letter = false; + } else if ('A' <= input[i] && input[i] <= 'Z') { + if (i == 0 && !cap_next_letter) { + // Force first letter to lower-case unless explicitly told to + // capitalize it. + result += input[i] + ('a' - 'A'); + } else { + // Capital letters after the first are left as-is. + result += input[i]; + } + cap_next_letter = false; + } else if ('0' <= input[i] && input[i] <= '9') { + result += input[i]; + cap_next_letter = true; + } else { + cap_next_letter = true; + } + } + // Add a trailing "_" if the name should be altered. + if (input[input.size() - 1] == '#') { + result += '_'; + } + return result; +} + +std::string UnderscoresToPascalCase(const std::string& input) { + return UnderscoresToCamelCase(input, true); +} + +std::string ToCSharpName(const std::string& name, const FileDescriptor* file) { + std::string result = GetFileNamespace(file); + if (result != "") { + result += '.'; + } + string classname; + if (file->package().empty()) { + classname = name; + } else { + // Strip the proto package from full_name since we've replaced it with + // the C# namespace. + classname = name.substr(file->package().size() + 1); + } + result += StringReplace(classname, ".", ".Types.", false); + return "global::" + result; +} + + + +std::string GetFullUmbrellaClassName(const FileDescriptor* descriptor) { + std::string result = GetFileNamespace(descriptor); + if (!result.empty()) { + result += '.'; + } + result += GetQualifiedUmbrellaClassName(descriptor); + return "global::" + result; +} + +std::string GetQualifiedUmbrellaClassName(const FileDescriptor* descriptor) { + std::string umbrellaNamespace = GetFileUmbrellaNamespace(descriptor); + std::string umbrellaClassname = GetFileUmbrellaClassname(descriptor); + + std::string fullName = umbrellaClassname; + if (!umbrellaNamespace.empty()) { + fullName = umbrellaNamespace + "." + umbrellaClassname; + } + return fullName; +} + +std::string GetClassName(const Descriptor* descriptor) { + return ToCSharpName(descriptor->full_name(), descriptor->file()); +} + +std::string GetClassName(const EnumDescriptor* descriptor) { + return ToCSharpName(descriptor->full_name(), descriptor->file()); +} + +// Groups are hacky: The name of the field is just the lower-cased name +// of the group type. In C#, though, we would like to retain the original +// capitalization of the type name. +std::string GetFieldName(const FieldDescriptor* descriptor) { + if (descriptor->type() == FieldDescriptor::TYPE_GROUP) { + return descriptor->message_type()->name(); + } else { + return descriptor->name(); + } +} + +std::string GetFieldConstantName(const FieldDescriptor* field) { + return GetPropertyName(field) + "FieldNumber"; +} + +std::string GetPropertyName(const FieldDescriptor* descriptor) { + // TODO(jtattermusch): consider introducing csharp_property_name field option + std::string property_name = UnderscoresToPascalCase(GetFieldName(descriptor)); + if (property_name == descriptor->containing_type()->name()) { + property_name += "_"; + } + return property_name; +} + +// TODO: c&p from Java protoc plugin +// For encodings with fixed sizes, returns that size in bytes. Otherwise +// returns -1. +int GetFixedSize(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32 : return -1; + case FieldDescriptor::TYPE_INT64 : return -1; + case FieldDescriptor::TYPE_UINT32 : return -1; + case FieldDescriptor::TYPE_UINT64 : return -1; + case FieldDescriptor::TYPE_SINT32 : return -1; + case FieldDescriptor::TYPE_SINT64 : return -1; + case FieldDescriptor::TYPE_FIXED32 : return internal::WireFormatLite::kFixed32Size; + case FieldDescriptor::TYPE_FIXED64 : return internal::WireFormatLite::kFixed64Size; + case FieldDescriptor::TYPE_SFIXED32: return internal::WireFormatLite::kSFixed32Size; + case FieldDescriptor::TYPE_SFIXED64: return internal::WireFormatLite::kSFixed64Size; + case FieldDescriptor::TYPE_FLOAT : return internal::WireFormatLite::kFloatSize; + case FieldDescriptor::TYPE_DOUBLE : return internal::WireFormatLite::kDoubleSize; + + case FieldDescriptor::TYPE_BOOL : return internal::WireFormatLite::kBoolSize; + case FieldDescriptor::TYPE_ENUM : return -1; + + case FieldDescriptor::TYPE_STRING : return -1; + case FieldDescriptor::TYPE_BYTES : return -1; + case FieldDescriptor::TYPE_GROUP : return -1; + case FieldDescriptor::TYPE_MESSAGE : return -1; + + // No default because we want the compiler to complain if any new + // types are added. + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return -1; +} + +static const char base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +std::string StringToBase64(const std::string& input) { + std::string result; + size_t remaining = input.size(); + const unsigned char *src = (const unsigned char*) input.c_str(); + while (remaining > 2) { + result += base64_chars[src[0] >> 2]; + result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)]; + result += base64_chars[((src[1] & 0xf) << 2) | (src[2] >> 6)]; + result += base64_chars[src[2] & 0x3f]; + remaining -= 3; + src += 3; + } + switch (remaining) { + case 2: + result += base64_chars[src[0] >> 2]; + result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)]; + result += base64_chars[(src[1] & 0xf) << 2]; + result += '='; + src += 2; + break; + case 1: + result += base64_chars[src[0] >> 2]; + result += base64_chars[((src[0] & 0x3) << 4)]; + result += '='; + result += '='; + src += 1; + break; + } + return result; +} + +std::string FileDescriptorToBase64(const FileDescriptor* descriptor) { + std::string fdp_bytes; + FileDescriptorProto fdp; + descriptor->CopyTo(&fdp); + fdp.SerializeToString(&fdp_bytes); + return StringToBase64(fdp_bytes); +} + +FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal) { + switch (descriptor->type()) { + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + if (descriptor->is_repeated()) { + return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal); + } else { + return new MessageFieldGenerator(descriptor, fieldOrdinal); + } + case FieldDescriptor::TYPE_ENUM: + if (descriptor->is_repeated()) { + return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal); + } else { + return new EnumFieldGenerator(descriptor, fieldOrdinal); + } + default: + if (descriptor->is_repeated()) { + return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal); + } else { + return new PrimitiveFieldGenerator(descriptor, fieldOrdinal); + } + } +} + +bool HasRequiredFields(const Descriptor* descriptor, std::set<const Descriptor*>* already_seen) { + if (already_seen->find(descriptor) != already_seen->end()) { + // The type is already in cache. This means that either: + // a. The type has no required fields. + // b. We are in the midst of checking if the type has required fields, + // somewhere up the stack. In this case, we know that if the type + // has any required fields, they'll be found when we return to it, + // and the whole call to HasRequiredFields() will return true. + // Therefore, we don't have to check if this type has required fields + // here. + return false; + } + already_seen->insert(descriptor); + + // If the type has extensions, an extension with message type could contain + // required fields, so we have to be conservative and assume such an + // extension exists. + if (descriptor->extension_count() > 0) { + return true; + } + + for (int i = 0; i < descriptor->field_count(); i++) { + const FieldDescriptor* field = descriptor->field(i); + if (field->is_required()) { + return true; + } + if (GetCSharpType(field->type()) == CSHARPTYPE_MESSAGE) { + if (HasRequiredFields(field->message_type(), already_seen)) { + return true; + } + } + } + return false; +} + +bool HasRequiredFields(const Descriptor* descriptor) { + std::set<const Descriptor*> already_seen; + return HasRequiredFields(descriptor, &already_seen); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h new file mode 100644 index 00000000..bc77f43a --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h @@ -0,0 +1,112 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__ + +#include <string> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class FieldGeneratorBase; + +// TODO: start using this enum. +enum CSharpType { + CSHARPTYPE_INT32 = 1, + CSHARPTYPE_INT64 = 2, + CSHARPTYPE_UINT32 = 3, + CSHARPTYPE_UINT64 = 4, + CSHARPTYPE_FLOAT = 5, + CSHARPTYPE_DOUBLE = 6, + CSHARPTYPE_BOOL = 7, + CSHARPTYPE_STRING = 8, + CSHARPTYPE_BYTESTRING = 9, + CSHARPTYPE_MESSAGE = 10, + CSHARPTYPE_ENUM = 11, + MAX_CSHARPTYPE = 11 +}; + +// Converts field type to corresponding C# type. +CSharpType GetCSharpType(FieldDescriptor::Type type); + +std::string StripDotProto(const std::string& proto_file); + +std::string GetFileNamespace(const FileDescriptor* descriptor); +std::string GetFileUmbrellaClassname(const FileDescriptor* descriptor); +std::string GetFileUmbrellaNamespace(const FileDescriptor* descriptor); + +std::string GetFullUmbrellaClassName(const FileDescriptor* descriptor); + +std::string GetQualifiedUmbrellaClassName(const FileDescriptor* descriptor); + +std::string GetClassName(const Descriptor* descriptor); +std::string GetClassName(const EnumDescriptor* descriptor); + +std::string GetFieldName(const FieldDescriptor* descriptor); + +std::string GetFieldConstantName(const FieldDescriptor* field); + +std::string GetPropertyName(const FieldDescriptor* descriptor); + +int GetFixedSize(FieldDescriptor::Type type); + +std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter); + +std::string UnderscoresToPascalCase(const std::string& input); + +// TODO(jtattermusch): perhaps we could move this to strutil +std::string StringToBase64(const std::string& input); + +std::string FileDescriptorToBase64(const FileDescriptor* descriptor); + +FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + +bool HasRequiredFields(const Descriptor* descriptor); + +inline bool SupportFieldPresence(const FileDescriptor* file) { + return file->syntax() != FileDescriptor::SYNTAX_PROTO3; +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__ diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc new file mode 100644 index 00000000..96f7c17c --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_message.cc @@ -0,0 +1,894 @@ +// 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. + +#include <sstream> +#include <algorithm> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/wire_format_lite.h> + +#include <google/protobuf/compiler/csharp/csharp_enum.h> +#include <google/protobuf/compiler/csharp/csharp_extension.h> +#include <google/protobuf/compiler/csharp/csharp_message.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +using google::protobuf::internal::scoped_ptr; + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) { + return d1->number() < d2->number(); +} + +MessageGenerator::MessageGenerator(const Descriptor* descriptor) + : SourceGeneratorBase(descriptor->file()), + descriptor_(descriptor) { + + // sorted field names + for (int i = 0; i < descriptor_->field_count(); i++) { + field_names_.push_back(descriptor_->field(i)->name()); + } + std::sort(field_names_.begin(), field_names_.end()); + + // fields by number + for (int i = 0; i < descriptor_->field_count(); i++) { + fields_by_number_.push_back(descriptor_->field(i)); + } + std::sort(fields_by_number_.begin(), fields_by_number_.end(), + CompareFieldNumbers); +} + +MessageGenerator::~MessageGenerator() { +} + +std::string MessageGenerator::class_name() { + return descriptor_->name(); +} + +std::string MessageGenerator::full_class_name() { + return GetClassName(descriptor_); +} + +const std::vector<std::string>& MessageGenerator::field_names() { + return field_names_; +} + +const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() { + return fields_by_number_; +} + +/// Get an identifier that uniquely identifies this type within the file. +/// This is used to declare static variables related to this type at the +/// outermost file scope. +std::string GetUniqueFileScopeIdentifier(const Descriptor* descriptor) { + std::string result = descriptor->full_name(); + std::replace(result.begin(), result.end(), '.', '_'); + return "static_" + result; +} + +void MessageGenerator::GenerateStaticVariables(Writer* writer) { + // Because descriptor.proto (Google.ProtocolBuffers.DescriptorProtos) is + // used in the construction of descriptors, we have a tricky bootstrapping + // problem. To help control static initialization order, we make sure all + // descriptors and other static data that depends on them are members of + // the proto-descriptor class. This way, they will be initialized in + // a deterministic order. + + std::string identifier = GetUniqueFileScopeIdentifier(descriptor_); + + if (!use_lite_runtime()) { + // The descriptor for this type. + std::string access = "internal"; + writer->WriteLine( + "$0$ static pbd::MessageDescriptor internal__$1$__Descriptor;", access, + identifier); + writer->WriteLine( + "$0$ static pb::FieldAccess.FieldAccessorTable<$1$, $1$.Builder> internal__$2$__FieldAccessorTable;", + access, full_class_name(), identifier); + } + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + MessageGenerator messageGenerator(descriptor_->nested_type(i)); + messageGenerator.GenerateStaticVariables(writer); + } +} + +void MessageGenerator::GenerateStaticVariableInitializers(Writer* writer) { + std::string identifier = GetUniqueFileScopeIdentifier(descriptor_); + + if (!use_lite_runtime()) { + writer->Write("internal__$0$__Descriptor = ", identifier); + + if (!descriptor_->containing_type()) { + writer->WriteLine("Descriptor.MessageTypes[$0$];", + SimpleItoa(descriptor_->index())); + } else { + writer->WriteLine( + "internal__$0$__Descriptor.NestedTypes[$1$];", + GetUniqueFileScopeIdentifier(descriptor_->containing_type()), + SimpleItoa(descriptor_->index())); + } + + writer->WriteLine("internal__$0$__FieldAccessorTable = ", identifier); + writer->WriteLine( + " new pb::FieldAccess.FieldAccessorTable<$1$, $1$.Builder>(internal__$0$__Descriptor,", + identifier, full_class_name()); + writer->Write(" new string[] { "); + for (int i = 0; i < descriptor_->field_count(); i++) { + writer->Write("\"$0$\", ", GetPropertyName(descriptor_->field(i))); + } + writer->WriteLine("});"); + } + + // Generate static member initializers for all nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + MessageGenerator messageGenerator(descriptor_->nested_type(i)); + messageGenerator.GenerateStaticVariableInitializers(writer); + } + + for (int i = 0; i < descriptor_->extension_count(); i++) { + ExtensionGenerator extensionGenerator(descriptor_->extension(i)); + extensionGenerator.GenerateStaticVariableInitializers(writer); + } +} + +void MessageGenerator::Generate(Writer* writer) { + writer->WriteLine( + "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]"); + WriteGeneratedCodeAttributes(writer); + writer->WriteLine( + "$0$ sealed partial class $1$ : pb::$2$Message$3$<$1$, $1$.Builder> {", + class_access_level(), class_name(), + descriptor_->extension_range_count() > 0 ? "Extendable" : "Generated", + runtime_suffix()); + writer->Indent(); + writer->WriteLine("private $0$() { }", class_name()); // Private ctor. + // Must call MakeReadOnly() to make sure all lists are made read-only + writer->WriteLine( + "private static readonly $0$ defaultInstance = new $0$().MakeReadOnly();", + class_name()); + + if (optimize_speed()) { + writer->WriteLine( + "private static readonly string[] _$0$FieldNames = new string[] { $2$$1$$2$ };", + UnderscoresToCamelCase(class_name(), false), + JoinStrings(field_names(), "\", \""), + field_names().size() > 0 ? "\"" : ""); + std::vector<std::string> tags; + for (int i = 0; i < field_names().size(); i++) { + uint32 tag = internal::WireFormat::MakeTag( + descriptor_->FindFieldByName(field_names()[i])); + tags.push_back(SimpleItoa(tag)); + } + writer->WriteLine( + "private static readonly uint[] _$0$FieldTags = new uint[] { $1$ };", + UnderscoresToCamelCase(class_name(), false), JoinStrings(tags, ", ")); + } + writer->WriteLine("public static $0$ DefaultInstance {", class_name()); + writer->WriteLine(" get { return defaultInstance; }"); + writer->WriteLine("}"); + writer->WriteLine(); + writer->WriteLine("public override $0$ DefaultInstanceForType {", + class_name()); + writer->WriteLine(" get { return DefaultInstance; }"); + writer->WriteLine("}"); + writer->WriteLine(); + writer->WriteLine("protected override $0$ ThisMessage {", class_name()); + writer->WriteLine(" get { return this; }"); + writer->WriteLine("}"); + writer->WriteLine(); + if (!use_lite_runtime()) { + writer->WriteLine("public static pbd::MessageDescriptor Descriptor {"); + writer->WriteLine(" get { return $0$.internal__$1$__Descriptor; }", + GetFullUmbrellaClassName(descriptor_->file()), + GetUniqueFileScopeIdentifier(descriptor_)); + writer->WriteLine("}"); + writer->WriteLine(); + writer->WriteLine( + "protected override pb::FieldAccess.FieldAccessorTable<$0$, $0$.Builder> InternalFieldAccessors {", + class_name()); + writer->WriteLine(" get { return $0$.internal__$1$__FieldAccessorTable; }", + GetFullUmbrellaClassName(descriptor_->file()), + GetUniqueFileScopeIdentifier(descriptor_)); + writer->WriteLine("}"); + writer->WriteLine(); + } + + // Extensions don't need to go in an extra nested type + for (int i = 0; i < descriptor_->extension_count(); i++) { + ExtensionGenerator extensionGenerator(descriptor_->extension(i)); + extensionGenerator.Generate(writer); + } + + if (descriptor_->enum_type_count() + descriptor_->nested_type_count() > 0) { + writer->WriteLine("#region Nested types"); + writer->WriteLine( + "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]"); + WriteGeneratedCodeAttributes(writer); + writer->WriteLine("public static partial class Types {"); + writer->Indent(); + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + EnumGenerator enumGenerator(descriptor_->enum_type(i)); + enumGenerator.Generate(writer); + } + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + MessageGenerator messageGenerator(descriptor_->nested_type(i)); + messageGenerator.Generate(writer); + } + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine("#endregion"); + writer->WriteLine(); + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* fieldDescriptor = descriptor_->field(i); + + // Rats: we lose the debug comment here :( + writer->WriteLine("public const int $0$ = $1$;", + GetFieldConstantName(fieldDescriptor), + SimpleItoa(fieldDescriptor->number())); + scoped_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(fieldDescriptor)); + generator->GenerateMembers(writer); + writer->WriteLine(); + } + + if (optimize_speed()) { + if (SupportFieldPresence(descriptor_->file())) { + GenerateIsInitialized(writer); + } + GenerateMessageSerializationMethods(writer); + } + if (use_lite_runtime()) { + GenerateLiteRuntimeMethods(writer); + } + + GenerateParseFromMethods(writer); + GenerateBuilder(writer); + + // Force the static initialization code for the file to run, since it may + // initialize static variables declared in this class. + writer->WriteLine("static $0$() {", class_name()); + // We call object.ReferenceEquals() just to make it a valid statement on its own. + // Another option would be GetType(), but that causes problems in DescriptorProtoFile, + // where the bootstrapping is somewhat recursive - type initializers call + // each other, effectively. We temporarily see Descriptor as null. + writer->WriteLine(" object.ReferenceEquals($0$.Descriptor, null);", + GetFullUmbrellaClassName(descriptor_->file())); + writer->WriteLine("}"); + + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); + +} + +void MessageGenerator::GenerateLiteRuntimeMethods(Writer* writer) { + bool callbase = descriptor_->extension_range_count() > 0; + writer->WriteLine("#region Lite runtime methods"); + writer->WriteLine("public override int GetHashCode() {"); + writer->Indent(); + writer->WriteLine("int hash = GetType().GetHashCode();"); + for (int i = 0; i < descriptor_->field_count(); i++) { + scoped_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(descriptor_->field(i))); + generator->WriteHash(writer); + } + if (callbase) { + writer->WriteLine("hash ^= base.GetHashCode();"); + } + writer->WriteLine("return hash;"); + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); + + writer->WriteLine("public override bool Equals(object obj) {"); + writer->Indent(); + writer->WriteLine("$0$ other = obj as $0$;", class_name()); + writer->WriteLine("if (other == null) return false;"); + for (int i = 0; i < descriptor_->field_count(); i++) { + scoped_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(descriptor_->field(i))); + generator->WriteEquals(writer); + } + if (callbase) { + writer->WriteLine("if (!base.Equals(other)) return false;"); + } + writer->WriteLine("return true;"); + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); + + writer->WriteLine( + "public override void PrintTo(global::System.IO.TextWriter writer) {"); + writer->Indent(); + + for (int i = 0; i < fields_by_number().size(); i++) { + scoped_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(fields_by_number()[i])); + generator->WriteToString(writer); + } + + if (callbase) { + writer->WriteLine("base.PrintTo(writer);"); + } + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine("#endregion"); + writer->WriteLine(); +} + +bool CompareExtensionRangesStart(const Descriptor::ExtensionRange* r1, + const Descriptor::ExtensionRange* r2) { + return r1->start < r2->start; +} + +void MessageGenerator::GenerateMessageSerializationMethods(Writer* writer) { + std::vector<const Descriptor::ExtensionRange*> extension_ranges_sorted; + for (int i = 0; i < descriptor_->extension_range_count(); i++) { + extension_ranges_sorted.push_back(descriptor_->extension_range(i)); + } + std::sort(extension_ranges_sorted.begin(), extension_ranges_sorted.end(), + CompareExtensionRangesStart); + + writer->WriteLine( + "public override void WriteTo(pb::ICodedOutputStream output) {"); + writer->Indent(); + // Make sure we've computed the serialized length, so that packed fields are generated correctly. + writer->WriteLine("CalcSerializedSize();"); + writer->WriteLine("string[] field_names = _$0$FieldNames;", + UnderscoresToCamelCase(class_name(), false)); + if (descriptor_->extension_range_count()) { + writer->WriteLine( + "pb::ExtendableMessage$1$<$0$, $0$.Builder>.ExtensionWriter extensionWriter = CreateExtensionWriter(this);", + class_name(), runtime_suffix()); + } + + // Merge the fields and the extension ranges, both sorted by field number. + for (int i = 0, j = 0; + i < fields_by_number().size() || j < extension_ranges_sorted.size();) { + if (i == fields_by_number().size()) { + GenerateSerializeOneExtensionRange(writer, extension_ranges_sorted[j++]); + } else if (j == extension_ranges_sorted.size()) { + GenerateSerializeOneField(writer, fields_by_number()[i++]); + } else if (fields_by_number()[i]->number() + < extension_ranges_sorted[j]->start) { + GenerateSerializeOneField(writer, fields_by_number()[i++]); + } else { + GenerateSerializeOneExtensionRange(writer, extension_ranges_sorted[j++]); + } + } + + if (!use_lite_runtime()) { + if (descriptor_->options().message_set_wire_format()) + { + writer->WriteLine("UnknownFields.WriteAsMessageSetTo(output);"); + } else { + writer->WriteLine("UnknownFields.WriteTo(output);"); + } + } + + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); + writer->WriteLine("private int memoizedSerializedSize = -1;"); + writer->WriteLine("public override int SerializedSize {"); + writer->Indent(); + writer->WriteLine("get {"); + writer->Indent(); + writer->WriteLine("int size = memoizedSerializedSize;"); + writer->WriteLine("if (size != -1) return size;"); + writer->WriteLine("return CalcSerializedSize();"); + writer->Outdent(); + writer->WriteLine("}"); + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); + + writer->WriteLine("private int CalcSerializedSize() {"); + writer->Indent(); + writer->WriteLine("int size = memoizedSerializedSize;"); + writer->WriteLine("if (size != -1) return size;"); + writer->WriteLine(); + writer->WriteLine("size = 0;"); + for (int i = 0; i < descriptor_->field_count(); i++) { + scoped_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(descriptor_->field(i))); + generator->GenerateSerializedSizeCode(writer); + } + if (descriptor_->extension_range_count() > 0) { + writer->WriteLine("size += ExtensionsSerializedSize;"); + } + + if (!use_lite_runtime()) { + if (descriptor_->options().message_set_wire_format()) { + writer->WriteLine("size += UnknownFields.SerializedSizeAsMessageSet;"); + } else { + writer->WriteLine("size += UnknownFields.SerializedSize;"); + } + } + writer->WriteLine("memoizedSerializedSize = size;"); + writer->WriteLine("return size;"); + writer->Outdent(); + writer->WriteLine("}"); +} + +void MessageGenerator::GenerateSerializeOneField( + Writer* writer, const FieldDescriptor* fieldDescriptor) { + scoped_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(fieldDescriptor)); + generator->GenerateSerializationCode(writer); +} + +void MessageGenerator::GenerateSerializeOneExtensionRange( + Writer* writer, const Descriptor::ExtensionRange* extensionRange) { + writer->WriteLine("extensionWriter.WriteUntil($0$, output);", + SimpleItoa(extensionRange->end)); +} + +void MessageGenerator::GenerateParseFromMethods(Writer* writer) { + // Note: These are separate from GenerateMessageSerializationMethods() + // because they need to be generated even for messages that are optimized + // for code size. + + writer->WriteLine("public static $0$ ParseFrom(pb::ByteString data) {", + class_name()); + writer->WriteLine( + " return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();"); + writer->WriteLine("}"); + writer->WriteLine( + "public static $0$ ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {", + class_name()); + writer->WriteLine( + " return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();"); + writer->WriteLine("}"); + writer->WriteLine("public static $0$ ParseFrom(byte[] data) {", class_name()); + writer->WriteLine( + " return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();"); + writer->WriteLine("}"); + writer->WriteLine( + "public static $0$ ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {", + class_name()); + writer->WriteLine( + " return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();"); + writer->WriteLine("}"); + writer->WriteLine( + "public static $0$ ParseFrom(global::System.IO.Stream input) {", + class_name()); + writer->WriteLine( + " return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();"); + writer->WriteLine("}"); + writer->WriteLine( + "public static $0$ ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {", + class_name()); + writer->WriteLine( + " return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();"); + writer->WriteLine("}"); + writer->WriteLine( + "public static $0$ ParseDelimitedFrom(global::System.IO.Stream input) {", + class_name()); + writer->WriteLine( + " return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();"); + writer->WriteLine("}"); + writer->WriteLine( + "public static $0$ ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {", + class_name()); + writer->WriteLine( + " return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();"); + writer->WriteLine("}"); + writer->WriteLine( + "public static $0$ ParseFrom(pb::ICodedInputStream input) {", + class_name()); + writer->WriteLine( + " return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();"); + writer->WriteLine("}"); + writer->WriteLine( + "public static $0$ ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {", + class_name()); + writer->WriteLine( + " return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();"); + writer->WriteLine("}"); +} + +void MessageGenerator::GenerateBuilder(Writer* writer) { + writer->WriteLine("private $0$ MakeReadOnly() {", class_name()); + writer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + scoped_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(descriptor_->field(i))); + generator->GenerateBuildingCode(writer); + } + writer->WriteLine("return this;"); + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); + + writer->WriteLine( + "public static Builder CreateBuilder() { return new Builder(); }"); + writer->WriteLine( + "public override Builder ToBuilder() { return CreateBuilder(this); }"); + writer->WriteLine( + "public override Builder CreateBuilderForType() { return new Builder(); }"); + writer->WriteLine("public static Builder CreateBuilder($0$ prototype) {", + class_name()); + writer->WriteLine(" return new Builder(prototype);"); + writer->WriteLine("}"); + writer->WriteLine(); + writer->WriteLine( + "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]"); + WriteGeneratedCodeAttributes(writer); + writer->WriteLine( + "$0$ sealed partial class Builder : pb::$2$Builder$3$<$1$, Builder> {", + class_access_level(), class_name(), + descriptor_->extension_range_count() > 0 ? "Extendable" : "Generated", + runtime_suffix()); + writer->Indent(); + writer->WriteLine("protected override Builder ThisBuilder {"); + writer->WriteLine(" get { return this; }"); + writer->WriteLine("}"); + GenerateCommonBuilderMethods(writer); + if (optimize_speed()) { + GenerateBuilderParsingMethods(writer); + } + for (int i = 0; i < descriptor_->field_count(); i++) { + scoped_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(descriptor_->field(i))); + writer->WriteLine(); + // No field comment :( + generator->GenerateBuilderMembers(writer); + } + writer->Outdent(); + writer->WriteLine("}"); +} + +void MessageGenerator::GenerateCommonBuilderMethods(Writer* writer) { + //default constructor + writer->WriteLine("public Builder() {"); + //Durring static initialization of message, DefaultInstance is expected to return null. + writer->WriteLine(" result = DefaultInstance;"); + writer->WriteLine(" resultIsReadOnly = true;"); + writer->WriteLine("}"); + //clone constructor + writer->WriteLine("internal Builder($0$ cloneFrom) {", class_name()); + writer->WriteLine(" result = cloneFrom;"); + writer->WriteLine(" resultIsReadOnly = true;"); + writer->WriteLine("}"); + writer->WriteLine(); + writer->WriteLine("private bool resultIsReadOnly;"); + writer->WriteLine("private $0$ result;", class_name()); + writer->WriteLine(); + writer->WriteLine("private $0$ PrepareBuilder() {", class_name()); + writer->WriteLine(" if (resultIsReadOnly) {"); + writer->WriteLine(" $0$ original = result;", class_name()); + writer->WriteLine(" result = new $0$();", class_name()); + writer->WriteLine(" resultIsReadOnly = false;"); + writer->WriteLine(" MergeFrom(original);"); + writer->WriteLine(" }"); + writer->WriteLine(" return result;"); + writer->WriteLine("}"); + writer->WriteLine(); + writer->WriteLine("public override bool IsInitialized {"); + writer->WriteLine(" get { return result.IsInitialized; }"); + writer->WriteLine("}"); + writer->WriteLine(); + writer->WriteLine("protected override $0$ MessageBeingBuilt {", class_name()); + writer->WriteLine(" get { return PrepareBuilder(); }"); + writer->WriteLine("}"); + writer->WriteLine(); + //Not actually expecting that DefaultInstance would ever be null here; however, we will ensure it does not break + writer->WriteLine("public override Builder Clear() {"); + writer->WriteLine(" result = DefaultInstance;"); + writer->WriteLine(" resultIsReadOnly = true;"); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + writer->WriteLine(); + writer->WriteLine("public override Builder Clone() {"); + writer->WriteLine(" if (resultIsReadOnly) {"); + writer->WriteLine(" return new Builder(result);"); + writer->WriteLine(" } else {"); + writer->WriteLine(" return new Builder().MergeFrom(result);"); + writer->WriteLine(" }"); + writer->WriteLine("}"); + writer->WriteLine(); + if (!use_lite_runtime()) { + writer->WriteLine( + "public override pbd::MessageDescriptor DescriptorForType {"); + writer->WriteLine(" get { return $0$.Descriptor; }", full_class_name()); + writer->WriteLine("}"); + writer->WriteLine(); + } + writer->WriteLine("public override $0$ DefaultInstanceForType {", + class_name()); + writer->WriteLine(" get { return $0$.DefaultInstance; }", full_class_name()); + writer->WriteLine("}"); + writer->WriteLine(); + + writer->WriteLine("public override $0$ BuildPartial() {", class_name()); + writer->Indent(); + writer->WriteLine("if (resultIsReadOnly) {"); + writer->WriteLine(" return result;"); + writer->WriteLine("}"); + writer->WriteLine("resultIsReadOnly = true;"); + writer->WriteLine("return result.MakeReadOnly();"); + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); + + if (optimize_speed()) { + writer->WriteLine( + "public override Builder MergeFrom(pb::IMessage$0$ other) {", + runtime_suffix()); + writer->WriteLine(" if (other is $0$) {", class_name()); + writer->WriteLine(" return MergeFrom(($0$) other);", class_name()); + writer->WriteLine(" } else {"); + writer->WriteLine(" base.MergeFrom(other);"); + writer->WriteLine(" return this;"); + writer->WriteLine(" }"); + writer->WriteLine("}"); + writer->WriteLine(); + writer->WriteLine("public override Builder MergeFrom($0$ other) {", + class_name()); + // Optimization: If other is the default instance, we know none of its + // fields are set so we can skip the merge. + writer->Indent(); + writer->WriteLine("if (other == $0$.DefaultInstance) return this;", + full_class_name()); + writer->WriteLine("PrepareBuilder();"); + for (int i = 0; i < descriptor_->field_count(); i++) { + scoped_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(descriptor_->field(i))); + generator->GenerateMergingCode(writer); + } + // if message type has extensions + if (descriptor_->extension_range_count() > 0) { + writer->WriteLine(" this.MergeExtensionFields(other);"); + } + if (!use_lite_runtime()) { + writer->WriteLine("this.MergeUnknownFields(other.UnknownFields);"); + } + writer->WriteLine("return this;"); + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); + } + +} + +void MessageGenerator::GenerateBuilderParsingMethods(Writer* writer) { + writer->WriteLine( + "public override Builder MergeFrom(pb::ICodedInputStream input) {"); + writer->WriteLine(" return MergeFrom(input, pb::ExtensionRegistry.Empty);"); + writer->WriteLine("}"); + writer->WriteLine(); + writer->WriteLine( + "public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {"); + writer->Indent(); + writer->WriteLine("PrepareBuilder();"); + if (!use_lite_runtime()) { + writer->WriteLine("pb::UnknownFieldSet.Builder unknownFields = null;"); + } + writer->WriteLine("uint tag;"); + writer->WriteLine("string field_name;"); + writer->WriteLine("while (input.ReadTag(out tag, out field_name)) {"); + writer->Indent(); + writer->WriteLine("if(tag == 0 && field_name != null) {"); + writer->Indent(); + //if you change from StringComparer.Ordinal, the array sort in FieldNames { get; } must also change + writer->WriteLine( + "int field_ordinal = global::System.Array.BinarySearch(_$0$FieldNames, field_name, global::System.StringComparer.Ordinal);", + UnderscoresToCamelCase(class_name(), false)); + writer->WriteLine("if(field_ordinal >= 0)"); + writer->WriteLine(" tag = _$0$FieldTags[field_ordinal];", + UnderscoresToCamelCase(class_name(), false)); + writer->WriteLine("else {"); + if (!use_lite_runtime()) { + writer->WriteLine(" if (unknownFields == null) {"); // First unknown field - create builder now + writer->WriteLine( + " unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);"); + writer->WriteLine(" }"); + } + writer->WriteLine( + " ParseUnknownField(input, $0$extensionRegistry, tag, field_name);", + use_lite_runtime() ? "" : "unknownFields, "); + writer->WriteLine(" continue;"); + writer->WriteLine("}"); + writer->Outdent(); + writer->WriteLine("}"); + + writer->WriteLine("switch (tag) {"); + writer->Indent(); + writer->WriteLine("case 0: {"); // 0 signals EOF / limit reached + writer->WriteLine(" throw pb::InvalidProtocolBufferException.InvalidTag();"); + writer->WriteLine("}"); + writer->WriteLine("default: {"); + writer->WriteLine(" if (pb::WireFormat.IsEndGroupTag(tag)) {"); + if (!use_lite_runtime()) { + writer->WriteLine(" if (unknownFields != null) {"); + writer->WriteLine(" this.UnknownFields = unknownFields.Build();"); + writer->WriteLine(" }"); + } + writer->WriteLine(" return this;"); // it's an endgroup tag + writer->WriteLine(" }"); + if (!use_lite_runtime()) { + writer->WriteLine(" if (unknownFields == null) {"); // First unknown field - create builder now + writer->WriteLine( + " unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);"); + writer->WriteLine(" }"); + } + writer->WriteLine( + " ParseUnknownField(input, $0$extensionRegistry, tag, field_name);", + use_lite_runtime() ? "" : "unknownFields, "); + writer->WriteLine(" break;"); + writer->WriteLine("}"); + + for (int i = 0; i < fields_by_number().size(); i++) { + const FieldDescriptor* field = fields_by_number()[i]; + internal::WireFormatLite::WireType wt = + internal::WireFormat::WireTypeForFieldType(field->type()); + uint32 tag = internal::WireFormatLite::MakeTag(field->number(), wt); + if (field->is_repeated() + && (wt == internal::WireFormatLite::WIRETYPE_VARINT + || wt == internal::WireFormatLite::WIRETYPE_FIXED32 + || wt == internal::WireFormatLite::WIRETYPE_FIXED64)) { + writer->WriteLine( + "case $0$:", + SimpleItoa( + internal::WireFormatLite::MakeTag( + field->number(), + internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED))); + } + + writer->WriteLine("case $0$: {", SimpleItoa(tag)); + writer->Indent(); + scoped_ptr<FieldGeneratorBase> generator( + CreateFieldGeneratorInternal(field)); + generator->GenerateParsingCode(writer); + writer->WriteLine("break;"); + writer->Outdent(); + writer->WriteLine("}"); + } + + writer->Outdent(); + writer->WriteLine("}"); + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); + if (!use_lite_runtime()) { + writer->WriteLine("if (unknownFields != null) {"); + writer->WriteLine(" this.UnknownFields = unknownFields.Build();"); + writer->WriteLine("}"); + } + writer->WriteLine("return this;"); + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); +} + +void MessageGenerator::GenerateIsInitialized(Writer* writer) { + writer->WriteLine("public override bool IsInitialized {"); + writer->Indent(); + writer->WriteLine("get {"); + writer->Indent(); + + // Check that all required fields in this message are set. + // TODO(kenton): We can optimize this when we switch to putting all the + // "has" fields into a single bitfield. + for (int i = 0; i < descriptor_->field_count(); i++) { + if (descriptor_->field(i)->is_required()) { + writer->WriteLine("if (!has$0$) return false;", + GetPropertyName(descriptor_->field(i))); + } + } + + // Now check that all embedded messages are initialized. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + if (field->type() != FieldDescriptor::TYPE_MESSAGE || + !HasRequiredFields(field->message_type())) + { + continue; + } + // TODO(jtattermusch): shouldn't we use GetPropertyName here? + string propertyName = UnderscoresToPascalCase(GetFieldName(field)); + if (field->is_repeated()) + { + writer->WriteLine("foreach ($0$ element in $1$List) {", + GetClassName(field->message_type()), + propertyName); + writer->WriteLine(" if (!element.IsInitialized) return false;"); + writer->WriteLine("}"); + } + else if (field->is_optional()) + { + writer->WriteLine("if (Has$0$) {", propertyName); + writer->WriteLine(" if (!$0$.IsInitialized) return false;", propertyName); + writer->WriteLine("}"); + } + else + { + writer->WriteLine("if (!$0$.IsInitialized) return false;", propertyName); + } + } + + if (descriptor_->extension_range_count() > 0) { + writer->WriteLine("if (!ExtensionsAreInitialized) return false;"); + } + writer->WriteLine("return true;"); + writer->Outdent(); + writer->WriteLine("}"); + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); +} + +void MessageGenerator::GenerateExtensionRegistrationCode(Writer* writer) { + for (int i = 0; i < descriptor_->extension_count(); i++) { + ExtensionGenerator extensionGenerator(descriptor_->extension(i)); + extensionGenerator.GenerateExtensionRegistrationCode(writer); + } + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + MessageGenerator messageGenerator(descriptor_->nested_type(i)); + messageGenerator.GenerateExtensionRegistrationCode(writer); + } +} + +int MessageGenerator::GetFieldOrdinal(const FieldDescriptor* descriptor) { + for (int i = 0; i < field_names().size(); i++) { + if (field_names()[i] == descriptor->name()) { + return i; + } + } + GOOGLE_LOG(DFATAL)<< "Could not find ordinal for field " << descriptor->name(); + return -1; +} + +FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal( + const FieldDescriptor* descriptor) { + return CreateFieldGenerator(descriptor, GetFieldOrdinal(descriptor)); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_message.h b/src/google/protobuf/compiler/csharp/csharp_message.h new file mode 100644 index 00000000..b8d15df0 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_message.h @@ -0,0 +1,98 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__ + +#include <string> +#include <vector> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; +class FieldGeneratorBase; + +class MessageGenerator : public SourceGeneratorBase { + public: + MessageGenerator(const Descriptor* descriptor); + ~MessageGenerator(); + + void GenerateStaticVariables(Writer* printer); + void GenerateStaticVariableInitializers(Writer* printer); + void GenerateExtensionRegistrationCode(Writer* printer); + void Generate(Writer* printer); + + private: + const Descriptor* descriptor_; + std::vector<std::string> field_names_; + std::vector<const FieldDescriptor*> fields_by_number_; + + void GenerateLiteRuntimeMethods(Writer* writer); + void GenerateMessageSerializationMethods(Writer* writer); + void GenerateSerializeOneField(Writer* writer, + const FieldDescriptor* fieldDescriptor); + void GenerateSerializeOneExtensionRange( + Writer* writer, const Descriptor::ExtensionRange* extendsionRange); + void GenerateParseFromMethods(Writer* writer); + void GenerateBuilder(Writer* writer); + void GenerateCommonBuilderMethods(Writer* writer); + void GenerateBuilderParsingMethods(Writer* writer); + void GenerateIsInitialized(Writer* writer); + + int GetFieldOrdinal(const FieldDescriptor* descriptor); + FieldGeneratorBase* CreateFieldGeneratorInternal( + const FieldDescriptor* descriptor); + + std::string class_name(); + std::string full_class_name(); + + // field names sorted alphabetically + const std::vector<std::string>& field_names(); + + // field descriptors sorted by number + const std::vector<const FieldDescriptor*>& fields_by_number(); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc new file mode 100644 index 00000000..10464c4b --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc @@ -0,0 +1,183 @@ +// 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. + +#include <sstream> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/stubs/strutil.h> + +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal) + : FieldGeneratorBase(descriptor, fieldOrdinal) { +} + +MessageFieldGenerator::~MessageFieldGenerator() { + +} + +void MessageFieldGenerator::GenerateMembers(Writer* writer) { + writer->WriteLine("private bool has$0$;", property_name()); + writer->WriteLine("private $0$ $1$_;", type_name(), name()); + AddDeprecatedFlag(writer); + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return has$0$; }", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return $0$_ ?? $1$; }", name(), default_value()); + writer->WriteLine("}"); +} + +void MessageFieldGenerator::GenerateBuilderMembers(Writer* writer) { + AddDeprecatedFlag(writer); + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return result.has$0$; }", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return result.$0$; }", property_name()); + writer->WriteLine(" set { Set$0$(value); }", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Set$0$($1$ value) {", property_name(), + type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.has$0$ = true;", property_name()); + writer->WriteLine(" result.$0$_ = value;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Set$0$($1$.Builder builderForValue) {", + property_name(), type_name()); + AddNullCheck(writer, "builderForValue"); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.has$0$ = true;", property_name()); + writer->WriteLine(" result.$0$_ = builderForValue.Build();", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Merge$0$($1$ value) {", property_name(), + type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" if (result.has$0$ &&", property_name()); + writer->WriteLine(" result.$0$_ != $1$) {", name(), default_value()); + writer->WriteLine( + " result.$0$_ = $1$.CreateBuilder(result.$0$_).MergeFrom(value).BuildPartial();", + name(), type_name()); + writer->WriteLine(" } else {"); + writer->WriteLine(" result.$0$_ = value;", name()); + writer->WriteLine(" }"); + writer->WriteLine(" result.has$0$ = true;", property_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.has$0$ = false;", property_name()); + writer->WriteLine(" result.$0$_ = null;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void MessageFieldGenerator::GenerateMergingCode(Writer* writer) { + writer->WriteLine("if (other.Has$0$) {", property_name()); + writer->WriteLine(" Merge$0$(other.$0$);", property_name()); + writer->WriteLine("}"); +} + +void MessageFieldGenerator::GenerateBuildingCode(Writer* writer) { + // Nothing to do for singular fields +} + +void MessageFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine("$0$.Builder subBuilder = $0$.CreateBuilder();", + type_name()); + writer->WriteLine("if (result.has$0$) {", property_name()); + writer->WriteLine(" subBuilder.MergeFrom($0$);", property_name()); + writer->WriteLine("}"); + + if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + writer->WriteLine("input.ReadGroup($0$, subBuilder, extensionRegistry);", + number()); + } else { + writer->WriteLine("input.ReadMessage(subBuilder, extensionRegistry);"); + } + writer->WriteLine("$0$ = subBuilder.BuildPartial();", property_name()); +} + +void MessageFieldGenerator::GenerateSerializationCode(Writer* writer) { + writer->WriteLine("if (has$0$) {", property_name()); + writer->WriteLine(" output.Write$0$($1$, field_names[$3$], $2$);", + message_or_group(), number(), property_name(), + field_ordinal()); + writer->WriteLine("}"); +} + +void MessageFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { + writer->WriteLine("if (has$0$) {", property_name()); + writer->WriteLine(" size += pb::CodedOutputStream.Compute$0$Size($1$, $2$);", + message_or_group(), number(), property_name()); + writer->WriteLine("}"); +} + +void MessageFieldGenerator::WriteHash(Writer* writer) { + writer->WriteLine("if (has$0$) hash ^= $1$_.GetHashCode();", property_name(), + name()); +} +void MessageFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine( + "if (has$0$ != other.has$0$ || (has$0$ && !$1$_.Equals(other.$1$_))) return false;", + property_name(), name()); +} +void MessageFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$2$\", has$0$, $1$_, writer);", + property_name(), name(), GetFieldName(descriptor_)); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.h b/src/google/protobuf/compiler/csharp/csharp_message_field.h new file mode 100644 index 00000000..48bf8be5 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class MessageFieldGenerator : public FieldGeneratorBase { + public: + MessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~MessageFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void GenerateMergingCode(Writer* writer); + virtual void GenerateBuildingCode(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + virtual void GenerateSerializationCode(Writer* writer); + virtual void GenerateSerializedSizeCode(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc new file mode 100644 index 00000000..a193afda --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc @@ -0,0 +1,190 @@ +// 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. + +#include <sstream> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/stubs/strutil.h> + +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_primitive_field.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +PrimitiveFieldGenerator::PrimitiveFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal) + : FieldGeneratorBase(descriptor, fieldOrdinal) { +} + +PrimitiveFieldGenerator::~PrimitiveFieldGenerator() { + +} + +void PrimitiveFieldGenerator::GenerateMembers(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("private bool has$0$;", property_name()); + } + writer->WriteLine("private $0$ $1$_$2$;", type_name(), name(), + has_default_value() ? " = " + default_value() : ""); + AddDeprecatedFlag(writer); + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return has$0$; }", property_name()); + writer->WriteLine("}"); + } + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return $0$_; }", name()); + writer->WriteLine("}"); +} + +void PrimitiveFieldGenerator::GenerateBuilderMembers(Writer* writer) { + AddDeprecatedFlag(writer); + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return result.has$0$; }", property_name()); + writer->WriteLine("}"); + } + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return result.$0$; }", property_name()); + writer->WriteLine(" set { Set$0$(value); }", property_name()); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public Builder Set$0$($1$ value) {", property_name(), + type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine(" result.has$0$ = true;", property_name()); + } + writer->WriteLine(" result.$0$_ = value;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine(" result.has$0$ = false;", property_name()); + } + writer->WriteLine(" result.$0$_ = $1$;", name(), default_value()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void PrimitiveFieldGenerator::GenerateMergingCode(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("if (other.Has$0$) {", property_name()); + } else { + writer->WriteLine("if (other.$0$ != $1$) {", property_name(), default_value()); + } + writer->WriteLine(" $0$ = other.$0$;", property_name()); + writer->WriteLine("}"); +} + +void PrimitiveFieldGenerator::GenerateBuildingCode(Writer* writer) { + // Nothing to do here for primitive types +} + +void PrimitiveFieldGenerator::GenerateParsingCode(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("result.has$0$ = input.Read$1$(ref result.$2$_);", + property_name(), capitalized_type_name(), name()); + } else { + writer->WriteLine("input.Read$0$(ref result.$1$_);", + capitalized_type_name(), name()); + } +} + +void PrimitiveFieldGenerator::GenerateSerializationCode(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("if (has$0$) {", property_name()); + } else { + writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value()); + } + writer->WriteLine(" output.Write$0$($1$, field_names[$3$], $2$);", + capitalized_type_name(), number(), property_name(), + field_ordinal()); + writer->WriteLine("}"); +} + +void PrimitiveFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("if (has$0$) {", property_name()); + } else { + writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value()); + } + writer->WriteLine(" size += pb::CodedOutputStream.Compute$0$Size($1$, $2$);", + capitalized_type_name(), number(), property_name()); + writer->WriteLine("}"); +} + +void PrimitiveFieldGenerator::WriteHash(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("if (has$0$) {", property_name()); + } else { + writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value()); + } + writer->WriteLine(" hash ^= $0$_.GetHashCode();", name()); + writer->WriteLine("}"); +} +void PrimitiveFieldGenerator::WriteEquals(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine( + "if (has$0$ != other.has$0$ || (has$0$ && !$1$_.Equals(other.$1$_))) return false;", + property_name(), name()); + } else { + writer->WriteLine( + "if (!$0$_.Equals(other.$0$_)) return false;", name()); + } +} +void PrimitiveFieldGenerator::WriteToString(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("PrintField(\"$0$\", has$1$, $2$_, writer);", + descriptor_->name(), property_name(), name()); + } else { + writer->WriteLine("PrintField(\"$0$\", $1$_, writer);", + descriptor_->name(), name()); + } +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h new file mode 100644 index 00000000..fb27ab43 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class PrimitiveFieldGenerator : public FieldGeneratorBase { + public: + PrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~PrimitiveFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void GenerateMergingCode(Writer* writer); + virtual void GenerateBuildingCode(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + virtual void GenerateSerializationCode(Writer* writer); + virtual void GenerateSerializedSizeCode(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc new file mode 100644 index 00000000..cc8745ae --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc @@ -0,0 +1,226 @@ +// 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. + +#include <sstream> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/wire_format.h> + +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal) + : FieldGeneratorBase(descriptor, fieldOrdinal) { +} + +RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() { + +} + +void RepeatedEnumFieldGenerator::GenerateMembers(Writer* writer) { + if (descriptor_->is_packed() && optimize_speed()) { + writer->WriteLine("private int $0$MemoizedSerializedSize;", name()); + } + writer->WriteLine( + "private pbc::PopsicleList<$0$> $1$_ = new pbc::PopsicleList<$0$>();", + type_name(), name()); + AddDeprecatedFlag(writer); + writer->WriteLine("public scg::IList<$0$> $1$List {", type_name(), + property_name()); + writer->WriteLine(" get { return pbc::Lists.AsReadOnly($0$_); }", name()); + writer->WriteLine("}"); + + // TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option. + AddDeprecatedFlag(writer); + writer->WriteLine("public int $0$Count {", property_name()); + writer->WriteLine(" get { return $0$_.Count; }", name()); + writer->WriteLine("}"); + + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ Get$1$(int index) {", type_name(), + property_name()); + writer->WriteLine(" return $0$_[index];", name()); + writer->WriteLine("}"); +} + +void RepeatedEnumFieldGenerator::GenerateBuilderMembers(Writer* writer) { + // Note: We can return the original list here, because we make it unmodifiable when we build + // We return it via IPopsicleList so that collection initializers work more pleasantly. + AddDeprecatedFlag(writer); + writer->WriteLine("public pbc::IPopsicleList<$0$> $1$List {", type_name(), + property_name()); + writer->WriteLine(" get { return PrepareBuilder().$0$_; }", name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public int $0$Count {", property_name()); + writer->WriteLine(" get { return result.$0$Count; }", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ Get$1$(int index) {", type_name(), + property_name()); + writer->WriteLine(" return result.Get$0$(index);", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Set$0$(int index, $1$ value) {", + property_name(), type_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_[index] = value;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Add$0$($1$ value) {", property_name(), + type_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(value);", name(), type_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine( + "public Builder AddRange$0$(scg::IEnumerable<$1$> values) {", + property_name(), type_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(values);", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Clear();", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void RepeatedEnumFieldGenerator::GenerateMergingCode(Writer* writer) { + writer->WriteLine("if (other.$0$_.Count != 0) {", name()); + writer->WriteLine(" result.$0$_.Add(other.$0$_);", name()); + writer->WriteLine("}"); +} + +void RepeatedEnumFieldGenerator::GenerateBuildingCode(Writer* writer) { + writer->WriteLine("$0$_.MakeReadOnly();", name()); +} + +void RepeatedEnumFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine("scg::ICollection<object> unknownItems;"); + writer->WriteLine( + "input.ReadEnumArray<$0$>(tag, field_name, result.$1$_, out unknownItems);", + type_name(), name()); + if (!use_lite_runtime()) { + writer->WriteLine("if (unknownItems != null) {"); + writer->WriteLine(" if (unknownFields == null) {"); + writer->WriteLine( + " unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);"); + writer->WriteLine(" }"); + writer->WriteLine(" foreach (object rawValue in unknownItems)"); + writer->WriteLine(" if (rawValue is int)"); + writer->WriteLine( + " unknownFields.MergeVarintField($0$, (ulong)(int)rawValue);", + number()); + writer->WriteLine("}"); + } +} + +void RepeatedEnumFieldGenerator::GenerateSerializationCode(Writer* writer) { + writer->WriteLine("if ($0$_.Count > 0) {", name()); + writer->Indent(); + if (descriptor_->is_packed()) { + writer->WriteLine( + "output.WritePackedEnumArray($0$, field_names[$2$], $1$MemoizedSerializedSize, $1$_);", + number(), name(), field_ordinal()); + } else { + writer->WriteLine("output.WriteEnumArray($0$, field_names[$2$], $1$_);", + number(), name(), field_ordinal()); + } + writer->Outdent(); + writer->WriteLine("}"); +} + +void RepeatedEnumFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { + writer->WriteLine("{"); + writer->Indent(); + writer->WriteLine("int dataSize = 0;"); + writer->WriteLine("if ($0$_.Count > 0) {", name()); + writer->Indent(); + writer->WriteLine("foreach ($0$ element in $1$_) {", type_name(), name()); + writer->WriteLine( + " dataSize += pb::CodedOutputStream.ComputeEnumSizeNoTag((int) element);"); + writer->WriteLine("}"); + writer->WriteLine("size += dataSize;"); + int tagSize = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type()); + if (descriptor_->is_packed()) { + writer->WriteLine("size += $0$;", SimpleItoa(tagSize)); + writer->WriteLine( + "size += pb::CodedOutputStream.ComputeRawVarint32Size((uint) dataSize);"); + } else { + writer->WriteLine("size += $0$ * $1$_.Count;", SimpleItoa(tagSize), name()); + } + writer->Outdent(); + writer->WriteLine("}"); + // cache the data size for packed fields. + if (descriptor_->is_packed()) { + writer->WriteLine("$0$MemoizedSerializedSize = dataSize;", name()); + } + writer->Outdent(); + writer->WriteLine("}"); +} + +void RepeatedEnumFieldGenerator::WriteHash(Writer* writer) { + writer->WriteLine("foreach($0$ i in $1$_)", type_name(), name()); + writer->WriteLine(" hash ^= i.GetHashCode();"); +} + +void RepeatedEnumFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine("if($0$_.Count != other.$0$_.Count) return false;", name()); + writer->WriteLine("for(int ix=0; ix < $0$_.Count; ix++)", name()); + writer->WriteLine(" if(!$0$_[ix].Equals(other.$0$_[ix])) return false;", + name()); +} + +void RepeatedEnumFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", $1$_, writer);", descriptor_->name(), + name()); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h new file mode 100644 index 00000000..c872131c --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class RepeatedEnumFieldGenerator : public FieldGeneratorBase { + public: + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~RepeatedEnumFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void GenerateMergingCode(Writer* writer); + virtual void GenerateBuildingCode(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + virtual void GenerateSerializationCode(Writer* writer); + virtual void GenerateSerializedSizeCode(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc new file mode 100644 index 00000000..2dfcd402 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc @@ -0,0 +1,201 @@ +// 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. + +#include <sstream> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> + +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal) + : FieldGeneratorBase(descriptor, fieldOrdinal) { +} + +RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() { + +} + +void RepeatedMessageFieldGenerator::GenerateMembers(Writer* writer) { + writer->WriteLine( + "private pbc::PopsicleList<$0$> $1$_ = new pbc::PopsicleList<$0$>();", + type_name(), name()); + AddDeprecatedFlag(writer); + writer->WriteLine("public scg::IList<$0$> $1$List {", type_name(), + property_name()); + writer->WriteLine(" get { return $0$_; }", name()); + writer->WriteLine("}"); + + // TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option. + AddDeprecatedFlag(writer); + writer->WriteLine("public int $0$Count {", property_name()); + writer->WriteLine(" get { return $0$_.Count; }", name()); + writer->WriteLine("}"); + + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ Get$1$(int index) {", type_name(), + property_name()); + writer->WriteLine(" return $0$_[index];", name()); + writer->WriteLine("}"); +} + +void RepeatedMessageFieldGenerator::GenerateBuilderMembers(Writer* writer) { + // Note: We can return the original list here, because we make it unmodifiable when we build + // We return it via IPopsicleList so that collection initializers work more pleasantly. + AddDeprecatedFlag(writer); + writer->WriteLine("public pbc::IPopsicleList<$0$> $1$List {", type_name(), + property_name()); + writer->WriteLine(" get { return PrepareBuilder().$0$_; }", name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public int $0$Count {", property_name()); + writer->WriteLine(" get { return result.$0$Count; }", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ Get$1$(int index) {", type_name(), + property_name()); + writer->WriteLine(" return result.Get$0$(index);", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Set$0$(int index, $1$ value) {", + property_name(), type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_[index] = value;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + // Extra overload for builder (just on messages) + AddDeprecatedFlag(writer); + writer->WriteLine( + "public Builder Set$0$(int index, $1$.Builder builderForValue) {", + property_name(), type_name()); + AddNullCheck(writer, "builderForValue"); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_[index] = builderForValue.Build();", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Add$0$($1$ value) {", property_name(), + type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(value);", name(), type_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + // Extra overload for builder (just on messages) + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Add$0$($1$.Builder builderForValue) {", + property_name(), type_name()); + AddNullCheck(writer, "builderForValue"); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(builderForValue.Build());", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine( + "public Builder AddRange$0$(scg::IEnumerable<$1$> values) {", + property_name(), type_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(values);", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Clear();", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void RepeatedMessageFieldGenerator::GenerateMergingCode(Writer* writer) { + writer->WriteLine("if (other.$0$_.Count != 0) {", name()); + writer->WriteLine(" result.$0$_.Add(other.$0$_);", name()); + writer->WriteLine("}"); +} + +void RepeatedMessageFieldGenerator::GenerateBuildingCode(Writer* writer) { + writer->WriteLine("$0$_.MakeReadOnly();", name()); +} + +void RepeatedMessageFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine( + "input.Read$0$Array(tag, field_name, result.$1$_, $2$.DefaultInstance, extensionRegistry);", + message_or_group(), name(), type_name()); +} + +void RepeatedMessageFieldGenerator::GenerateSerializationCode(Writer* writer) { + writer->WriteLine("if ($0$_.Count > 0) {", name()); + writer->Indent(); + writer->WriteLine("output.Write$0$Array($1$, field_names[$3$], $2$_);", + message_or_group(), number(), name(), field_ordinal()); + writer->Outdent(); + writer->WriteLine("}"); +} + +void RepeatedMessageFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { + writer->WriteLine("foreach ($0$ element in $1$List) {", type_name(), + property_name()); + writer->WriteLine( + " size += pb::CodedOutputStream.Compute$0$Size($1$, element);", + message_or_group(), number()); + writer->WriteLine("}"); +} + +void RepeatedMessageFieldGenerator::WriteHash(Writer* writer) { + writer->WriteLine("foreach($0$ i in $1$_)", type_name(), name()); + writer->WriteLine(" hash ^= i.GetHashCode();"); +} +void RepeatedMessageFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine("if($0$_.Count != other.$0$_.Count) return false;", name()); + writer->WriteLine("for(int ix=0; ix < $0$_.Count; ix++)", name()); + writer->WriteLine(" if(!$0$_[ix].Equals(other.$0$_[ix])) return false;", + name()); +} +void RepeatedMessageFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", $1$_, writer);", + GetFieldName(descriptor_), name()); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h new file mode 100644 index 00000000..104274cb --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class RepeatedMessageFieldGenerator : public FieldGeneratorBase { + public: + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~RepeatedMessageFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void GenerateMergingCode(Writer* writer); + virtual void GenerateBuildingCode(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + virtual void GenerateSerializationCode(Writer* writer); + virtual void GenerateSerializedSizeCode(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc new file mode 100644 index 00000000..8b285468 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc @@ -0,0 +1,219 @@ +// 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. + +#include <sstream> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/wire_format.h> + +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal) + : FieldGeneratorBase(descriptor, fieldOrdinal) { +} + +RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() { + +} + +void RepeatedPrimitiveFieldGenerator::GenerateMembers(Writer* writer) { + if (descriptor_->is_packed() && optimize_speed()) { + writer->WriteLine("private int $0$MemoizedSerializedSize;", name()); + } + writer->WriteLine( + "private pbc::PopsicleList<$0$> $1$_ = new pbc::PopsicleList<$0$>();", + type_name(), name()); + AddPublicMemberAttributes(writer); + writer->WriteLine("public scg::IList<$0$> $1$List {", type_name(), + property_name()); + writer->WriteLine(" get { return pbc::Lists.AsReadOnly($0$_); }", name()); + writer->WriteLine("}"); + + // TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option. + AddDeprecatedFlag(writer); + writer->WriteLine("public int $0$Count {", property_name()); + writer->WriteLine(" get { return $0$_.Count; }", name()); + writer->WriteLine("}"); + + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ Get$1$(int index) {", type_name(), + property_name()); + writer->WriteLine(" return $0$_[index];", name()); + writer->WriteLine("}"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateBuilderMembers(Writer* writer) { + // Note: We can return the original list here, because we make it unmodifiable when we build + // We return it via IPopsicleList so that collection initializers work more pleasantly. + AddPublicMemberAttributes(writer); + writer->WriteLine("public pbc::IPopsicleList<$0$> $1$List {", type_name(), + property_name()); + writer->WriteLine(" get { return PrepareBuilder().$0$_; }", name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public int $0$Count {", property_name()); + writer->WriteLine(" get { return result.$0$Count; }", property_name()); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ Get$1$(int index) {", type_name(), + property_name()); + writer->WriteLine(" return result.Get$0$(index);", property_name()); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public Builder Set$0$(int index, $1$ value) {", + property_name(), type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_[index] = value;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public Builder Add$0$($1$ value) {", property_name(), + type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(value);", name(), type_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine( + "public Builder AddRange$0$(scg::IEnumerable<$1$> values) {", + property_name(), type_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(values);", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Clear();", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateMergingCode(Writer* writer) { + writer->WriteLine("if (other.$0$_.Count != 0) {", name()); + writer->WriteLine(" result.$0$_.Add(other.$0$_);", name()); + writer->WriteLine("}"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateBuildingCode(Writer* writer) { + writer->WriteLine("$0$_.MakeReadOnly();", name()); +} + +void RepeatedPrimitiveFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine("input.Read$0$Array(tag, field_name, result.$1$_);", + capitalized_type_name(), name()); +} + +void RepeatedPrimitiveFieldGenerator::GenerateSerializationCode( + Writer* writer) { + writer->WriteLine("if ($0$_.Count > 0) {", name()); + writer->Indent(); + if (descriptor_->is_packed()) { + writer->WriteLine( + "output.WritePacked$0$Array($1$, field_names[$3$], $2$MemoizedSerializedSize, $2$_);", + capitalized_type_name(), number(), name(), field_ordinal()); + } else { + writer->WriteLine("output.Write$0$Array($1$, field_names[$3$], $2$_);", + capitalized_type_name(), number(), name(), + field_ordinal()); + } + writer->Outdent(); + writer->WriteLine("}"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateSerializedSizeCode( + Writer* writer) { + writer->WriteLine("{"); + writer->Indent(); + writer->WriteLine("int dataSize = 0;"); + int fixedSize = GetFixedSize(descriptor_->type()); + if (fixedSize == -1) { + writer->WriteLine("foreach ($0$ element in $1$List) {", type_name(), + property_name()); + writer->WriteLine( + " dataSize += pb::CodedOutputStream.Compute$0$SizeNoTag(element);", + capitalized_type_name(), number()); + writer->WriteLine("}"); + } else { + writer->WriteLine("dataSize = $0$ * $1$_.Count;", SimpleItoa(fixedSize), name()); + } + writer->WriteLine("size += dataSize;"); + int tagSize = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type()); + if (descriptor_->is_packed()) { + writer->WriteLine("if ($0$_.Count != 0) {", name()); + writer->WriteLine( + " size += $0$ + pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);", + SimpleItoa(tagSize)); + writer->WriteLine("}"); + } else { + writer->WriteLine("size += $0$ * $1$_.Count;", SimpleItoa(tagSize), name()); + } + // cache the data size for packed fields. + if (descriptor_->is_packed()) { + writer->WriteLine("$0$MemoizedSerializedSize = dataSize;", name()); + } + writer->Outdent(); + writer->WriteLine("}"); +} + +void RepeatedPrimitiveFieldGenerator::WriteHash(Writer* writer) { + writer->WriteLine("foreach($0$ i in $1$_)", type_name(), name()); + writer->WriteLine(" hash ^= i.GetHashCode();"); +} +void RepeatedPrimitiveFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine("if($0$_.Count != other.$0$_.Count) return false;", name()); + writer->WriteLine("for(int ix=0; ix < $0$_.Count; ix++)", name()); + writer->WriteLine(" if(!$0$_[ix].Equals(other.$0$_[ix])) return false;", + name()); +} +void RepeatedPrimitiveFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", $1$_, writer);", descriptor_->name(), + name()); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h new file mode 100644 index 00000000..07b12015 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class RepeatedPrimitiveFieldGenerator : public FieldGeneratorBase { + public: + RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~RepeatedPrimitiveFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void GenerateMergingCode(Writer* writer); + virtual void GenerateBuildingCode(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + virtual void GenerateSerializationCode(Writer* writer); + virtual void GenerateSerializedSizeCode(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc new file mode 100644 index 00000000..8dfb41d4 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc @@ -0,0 +1,75 @@ +// 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. + +#include <sstream> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> + +#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +SourceGeneratorBase::SourceGeneratorBase(const FileDescriptor* descriptor) + : descriptor_(descriptor) { + optimizeSize_ = (descriptor->options().optimize_for() + == FileOptions::CODE_SIZE); + optimizeSpeed_ = (descriptor->options().optimize_for() == FileOptions::SPEED); + useLiteRuntime_ = (descriptor->options().optimize_for() + == FileOptions::LITE_RUNTIME); + + optimizeSpeed_ |= useLiteRuntime_; + runtimeSuffix_ = useLiteRuntime_ ? "Lite" : ""; +} + +SourceGeneratorBase::~SourceGeneratorBase() { +} + +void SourceGeneratorBase::WriteGeneratedCodeAttributes(Writer* writer) { + // This hook can be used to reintroduce generated code attributes in the future. +} + +std::string SourceGeneratorBase::class_access_level() { + return "public"; // public_classes is always on. +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h new file mode 100644 index 00000000..1955394e --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h @@ -0,0 +1,83 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class SourceGeneratorBase { + protected: + SourceGeneratorBase(const FileDescriptor* descriptor); + virtual ~SourceGeneratorBase(); + + std::string class_access_level(); + + bool optimize_size() { + return optimizeSize_; + } + bool optimize_speed() { + return optimizeSpeed_; + } + bool use_lite_runtime() { + return useLiteRuntime_; + } + std::string runtime_suffix() { + return runtimeSuffix_; + } + + void WriteGeneratedCodeAttributes(Writer* writer); + + private: + const FileDescriptor* descriptor_; + bool optimizeSize_; + bool optimizeSpeed_; + bool useLiteRuntime_; + std::string runtimeSuffix_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceGeneratorBase); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc new file mode 100644 index 00000000..358cfa4f --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc @@ -0,0 +1,286 @@ +// 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. + +#include <sstream> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> + +#include <google/protobuf/compiler/csharp/csharp_umbrella_class.h> +#include <google/protobuf/compiler/csharp/csharp_enum.h> +#include <google/protobuf/compiler/csharp/csharp_extension.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_message.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +UmbrellaClassGenerator::UmbrellaClassGenerator(const FileDescriptor* file) + : SourceGeneratorBase(file), + file_(file) { + namespace_ = GetFileNamespace(file); + umbrellaClassname_ = GetFileUmbrellaClassname(file); + umbrellaNamespace_ = GetFileUmbrellaNamespace(file); +} + +UmbrellaClassGenerator::~UmbrellaClassGenerator() { +} + +void UmbrellaClassGenerator::Generate(Writer* writer) { + WriteIntroduction(writer); + WriteExtensionRegistration(writer); + + // write children: Extensions + if (file_->extension_count() > 0) { + writer->WriteLine("#region Extensions"); + for (int i = 0; i < file_->extension_count(); i++) { + ExtensionGenerator extensionGenerator(file_->extension(i)); + extensionGenerator.Generate(writer); + } + writer->WriteLine("#endregion"); + writer->WriteLine(); + } + + writer->WriteLine("#region Static variables"); + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator messageGenerator(file_->message_type(i)); + messageGenerator.GenerateStaticVariables(writer); + } + writer->WriteLine("#endregion"); + if (!use_lite_runtime()) { + WriteDescriptor(writer); + } else { + WriteLiteExtensions(writer); + } + // Close the class declaration. + writer->Outdent(); + writer->WriteLine("}"); + + // Close the namespace around the umbrella class if defined + if (!umbrellaNamespace_.empty()) { + writer->Outdent(); + writer->WriteLine("}"); + } + + // write children: Enums + if (file_->enum_type_count() > 0) { + writer->WriteLine("#region Enums"); + for (int i = 0; i < file_->enum_type_count(); i++) { + EnumGenerator enumGenerator(file_->enum_type(i)); + enumGenerator.Generate(writer); + } + writer->WriteLine("#endregion"); + writer->WriteLine(); + } + + // write children: Messages + if (file_->message_type_count() > 0) { + writer->WriteLine("#region Messages"); + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator messageGenerator(file_->message_type(i)); + messageGenerator.Generate(writer); + } + writer->WriteLine("#endregion"); + writer->WriteLine(); + } + + // TODO(jtattermusch): add insertion point for services. + + if (!namespace_.empty()) { + writer->Outdent(); + writer->WriteLine("}"); + } + writer->WriteLine(); + writer->WriteLine("#endregion Designer generated code"); +} + +void UmbrellaClassGenerator::WriteIntroduction(Writer* writer) { + writer->WriteLine( + "// Generated by the protocol buffer compiler. DO NOT EDIT!"); + writer->WriteLine("// source: $0$", file_->name()); + writer->WriteLine("#pragma warning disable 1591, 0612, 3021"); + writer->WriteLine("#region Designer generated code"); + + writer->WriteLine(); + writer->WriteLine("using pb = global::Google.ProtocolBuffers;"); + writer->WriteLine("using pbc = global::Google.ProtocolBuffers.Collections;"); + writer->WriteLine("using pbd = global::Google.ProtocolBuffers.Descriptors;"); + writer->WriteLine("using scg = global::System.Collections.Generic;"); + + if (!namespace_.empty()) { + writer->WriteLine("namespace $0$ {", namespace_); + writer->Indent(); + writer->WriteLine(); + } + + // Add the namespace around the umbrella class if defined + if (!umbrellaNamespace_.empty()) { + writer->WriteLine("namespace $0$ {", umbrellaNamespace_); + writer->Indent(); + writer->WriteLine(); + } + + writer->WriteLine( + "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]"); + WriteGeneratedCodeAttributes(writer); + writer->WriteLine("$0$ static partial class $1$ {", class_access_level(), + umbrellaClassname_); + writer->WriteLine(); + writer->Indent(); +} + +void UmbrellaClassGenerator::WriteExtensionRegistration(Writer* writer) { + writer->WriteLine("#region Extension registration"); + writer->WriteLine( + "public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {"); + writer->Indent(); + for (int i = 0; i < file_->extension_count(); i++) { + ExtensionGenerator extensionGenerator(file_->extension(i)); + extensionGenerator.GenerateExtensionRegistrationCode(writer); + } + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator messageGenerator(file_->message_type(i)); + messageGenerator.GenerateExtensionRegistrationCode(writer); + } + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine("#endregion"); +} + +void UmbrellaClassGenerator::WriteDescriptor(Writer* writer) { + writer->WriteLine("#region Descriptor"); + + writer->WriteLine("public static pbd::FileDescriptor Descriptor {"); + writer->WriteLine(" get { return descriptor; }"); + writer->WriteLine("}"); + writer->WriteLine("private static pbd::FileDescriptor descriptor;"); + writer->WriteLine(); + writer->WriteLine("static $0$() {", umbrellaClassname_); + writer->Indent(); + writer->WriteLine( + "byte[] descriptorData = global::System.Convert.FromBase64String("); + writer->Indent(); + writer->Indent(); + writer->WriteLine("string.Concat("); + writer->Indent(); + + // TODO(jonskeet): Consider a C#-escaping format here instead of just Base64. + std::string base64 = FileDescriptorToBase64(file_); + while (base64.size() > 60) { + writer->WriteLine("\"$0$\", ", base64.substr(0, 60)); + base64 = base64.substr(60); + } + writer->Outdent(); + writer->WriteLine("\"$0$\"));", base64); + writer->Outdent(); + writer->Outdent(); + writer->WriteLine( + "pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {"); + writer->Indent(); + writer->WriteLine("descriptor = root;"); + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator messageGenerator(file_->message_type(i)); + messageGenerator.GenerateStaticVariableInitializers(writer); + } + for (int i = 0; i < file_->extension_count(); i++) { + ExtensionGenerator extensionGenerator(file_->extension(i)); + extensionGenerator.GenerateStaticVariableInitializers(writer); + } + + if (uses_extensions()) { + // Must construct an ExtensionRegistry containing all possible extensions + // and return it. + writer->WriteLine( + "pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance();"); + writer->WriteLine("RegisterAllExtensions(registry);"); + for (int i = 0; i < file_->dependency_count(); i++) { + writer->WriteLine("$0$.RegisterAllExtensions(registry);", + GetFullUmbrellaClassName(file_->dependency(i))); + } + writer->WriteLine("return registry;"); + } else { + writer->WriteLine("return null;"); + } + writer->Outdent(); + writer->WriteLine("};"); + + // ----------------------------------------------------------------- + // Invoke internalBuildGeneratedFileFrom() to build the file. + writer->WriteLine( + "pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,"); + writer->WriteLine(" new pbd::FileDescriptor[] {"); + for (int i = 0; i < file_->dependency_count(); i++) { + writer->WriteLine(" $0$.Descriptor, ", + GetFullUmbrellaClassName(file_->dependency(i))); + } + writer->WriteLine(" }, assigner);"); + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine("#endregion"); + writer->WriteLine(); +} + +void UmbrellaClassGenerator::WriteLiteExtensions(Writer* writer) { + writer->WriteLine("#region Extensions"); + writer->WriteLine("internal static readonly object Descriptor;"); + writer->WriteLine("static $0$() {", umbrellaClassname_); + writer->Indent(); + writer->WriteLine("Descriptor = null;"); + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator messageGenerator(file_->message_type(i)); + messageGenerator.GenerateStaticVariableInitializers(writer); + } + for (int i = 0; i < file_->extension_count(); i++) { + ExtensionGenerator extensionGenerator(file_->extension(i)); + extensionGenerator.GenerateStaticVariableInitializers(writer); + } + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine("#endregion"); + writer->WriteLine(); +} + +bool UmbrellaClassGenerator::uses_extensions() { + // TODO(jtattermusch): implement recursive descent that looks for extensions. + // For now, we conservatively assume that extensions are used. + return true; +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h new file mode 100644 index 00000000..757f8f91 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h @@ -0,0 +1,76 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class UmbrellaClassGenerator : public SourceGeneratorBase { + public: + UmbrellaClassGenerator(const FileDescriptor* file); + ~UmbrellaClassGenerator(); + + void Generate(Writer* write); + + private: + const FileDescriptor* file_; + + std::string namespace_; + std::string umbrellaClassname_; + std::string umbrellaNamespace_; + + void WriteIntroduction(Writer* writer); + void WriteExtensionRegistration(Writer* writer); + void WriteDescriptor(Writer* writer); + void WriteLiteExtensions(Writer* write); + + bool uses_extensions(); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UmbrellaClassGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_writer.cc b/src/google/protobuf/compiler/csharp/csharp_writer.cc new file mode 100644 index 00000000..2bcafde5 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_writer.cc @@ -0,0 +1,136 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <algorithm> +#include <google/protobuf/stubs/hash.h> +#include <limits> +#include <vector> + +#include <google/protobuf/compiler/csharp/csharp_writer.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> + +#include <google/protobuf/compiler/csharp/csharp_field_base.h> +#include <google/protobuf/compiler/csharp/csharp_enum_field.h> +#include <google/protobuf/compiler/csharp/csharp_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_primitive_field.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +Writer::Writer(google::protobuf::io::Printer* printer) + : printer_(printer), + newline_("\n") { + // TODO(jtattermusch): make newline customizable. +} + +Writer::~Writer() { +} + +void Writer::Indent() { + printer_->Indent(); +} + +void Writer::Outdent() { + printer_->Outdent(); +} + +void Writer::Write(const char* text) { + printer_->Print(text); +} + +void Writer::Write(const char* text, const string& value0) { + printer_->Print(text, "0", value0); +} + +void Writer::Write(const char* text, const string& value0, + const string& value1) { + printer_->Print(text, "0", value0, "1", value1); +} + +void Writer::Write(const char* text, const string& value0, const string& value1, + const string& value2) { + printer_->Print(text, "0", value0, "1", value1, "2", value2); +} + +void Writer::Write(const char* text, const string& value0, const string& value1, + const string& value2, const string& value3) { + printer_->Print(text, "0", value0, "1", value1, "2", value2, "3", value3); +} + +void Writer::WriteLine() { + printer_->Print(newline_); +} + +void Writer::WriteLine(const char* text) { + Write(text); + WriteLine(); +} + +void Writer::WriteLine(const char* text, const string& value0) { + Write(text, value0); + WriteLine(); +} + +void Writer::WriteLine(const char* text, const string& value0, + const string& value1) { + Write(text, value0, value1); + WriteLine(); +} + +void Writer::WriteLine(const char* text, const string& value0, + const string& value1, const string& value2) { + Write(text, value0, value1, value2); + WriteLine(); +} + +void Writer::WriteLine(const char* text, const string& value0, + const string& value1, const string& value2, + const string& value3) { + Write(text, value0, value1, value2, value3); + WriteLine(); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_writer.h b/src/google/protobuf/compiler/csharp/csharp_writer.h new file mode 100644 index 00000000..26c59b31 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_writer.h @@ -0,0 +1,93 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_WRITER_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_WRITER_H__ + +#include <string> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +// Simple wrapper around Printer that supports customizable line endings +// and number-based variables (e.g. $0$). +class Writer { + public: + Writer(io::Printer* printer); + ~Writer(); + + void Indent(); + void Outdent(); + + void Write(const char* text); + + void Write(const char* text, const string& value0); + + void Write(const char* text, const string& value0, const string& value1); + + void Write(const char* text, const string& value0, const string& value1, + const string& value2); + + void Write(const char* text, const string& value0, const string& value1, + const string& value2, const string& value3); + + void WriteLine(); + + void WriteLine(const char* text); + + void WriteLine(const char* text, const string& value0); + + void WriteLine(const char* text, const string& value0, const string& value1); + + void WriteLine(const char* text, const string& value0, const string& value1, + const string& value2); + + void WriteLine(const char* text, const string& value0, const string& value1, + const string& value2, const string& value3); + private: + io::Printer* printer_; + const char* newline_; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_WRITER_H__ |