aboutsummaryrefslogtreecommitdiff
path: root/src/ProtoGen/MessageGenerator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ProtoGen/MessageGenerator.cs')
-rw-r--r--src/ProtoGen/MessageGenerator.cs85
1 files changed, 66 insertions, 19 deletions
diff --git a/src/ProtoGen/MessageGenerator.cs b/src/ProtoGen/MessageGenerator.cs
index 01d47ce2..e9a037bf 100644
--- a/src/ProtoGen/MessageGenerator.cs
+++ b/src/ProtoGen/MessageGenerator.cs
@@ -165,9 +165,13 @@ namespace Google.ProtocolBuffers.ProtoGen
{
return SourceGenerators.CreateFieldGenerator(fieldDescriptor, FieldOrdinal(fieldDescriptor));
}
-
+
public void Generate(TextGenerator writer)
{
+ if (Descriptor.File.CSharpOptions.AddSerializable)
+ {
+ writer.WriteLine("[global::System.SerializableAttribute()]");
+ }
writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
writer.WriteLine("[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]");
writer.WriteLine("[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"{0}\", \"{1}\")]",
@@ -177,8 +181,9 @@ namespace Google.ProtocolBuffers.ProtoGen
Descriptor.Proto.ExtensionRangeCount > 0 ? "Extendable" : "Generated",
RuntimeSuffix);
writer.Indent();
+ writer.WriteLine("private {0}() {{ }}", ClassName);
// Must call BuildPartial() to make sure all lists are made read-only
- writer.WriteLine("private static readonly {0} defaultInstance = new Builder().BuildPartial();", ClassName);
+ writer.WriteLine("private static readonly {0} defaultInstance = new {0}().MakeReadOnly();", ClassName);
if (OptimizeSpeed)
{
@@ -199,7 +204,7 @@ namespace Google.ProtocolBuffers.ProtoGen
writer.WriteLine("}");
writer.WriteLine();
writer.WriteLine("public override {0} DefaultInstanceForType {{", ClassName);
- writer.WriteLine(" get { return defaultInstance; }");
+ writer.WriteLine(" get { return DefaultInstance; }");
writer.WriteLine("}");
writer.WriteLine();
writer.WriteLine("protected override {0} ThisMessage {{", ClassName);
@@ -547,13 +552,28 @@ namespace Google.ProtocolBuffers.ProtoGen
private void GenerateBuilder(TextGenerator writer)
{
+ writer.WriteLine("private {0} MakeReadOnly() {{", ClassName);
+ writer.Indent();
+ foreach (FieldDescriptor field in Descriptor.Fields)
+ {
+ CreateFieldGenerator(field).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) {{", ClassName);
- writer.WriteLine(" return (Builder) new Builder().MergeFrom(prototype);");
+ writer.WriteLine(" return new Builder(prototype);");
writer.WriteLine("}");
writer.WriteLine();
+ if (Descriptor.File.CSharpOptions.AddSerializable)
+ {
+ writer.WriteLine("[global::System.SerializableAttribute()]");
+ }
writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
writer.WriteLine("[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]");
writer.WriteLine("[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"{0}\", \"{1}\")]",
@@ -582,21 +602,52 @@ namespace Google.ProtocolBuffers.ProtoGen
private void GenerateCommonBuilderMethods(TextGenerator writer)
{
- writer.WriteLine("public Builder() {{}}", ClassAccessLevel);
+ //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) {{", ClassName);
+ writer.WriteLine(" result = cloneFrom;");
+ writer.WriteLine(" resultIsReadOnly = true;");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine("private bool resultIsReadOnly;");
+ writer.WriteLine("private {0} result;", ClassName);
writer.WriteLine();
- writer.WriteLine("{0} result = new {0}();", ClassName);
+ writer.WriteLine("private {0} PrepareBuilder() {{", ClassName);
+ writer.WriteLine(" if (resultIsReadOnly) {");
+ writer.WriteLine(" {0} original = result;", ClassName);
+ writer.WriteLine(" result = new {0}();", ClassName);
+ 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 {{", ClassName);
- writer.WriteLine(" get { return result; }");
+ 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 = new {0}();", ClassName);
+ writer.WriteLine(" result = DefaultInstance;", ClassName);
+ writer.WriteLine(" resultIsReadOnly = true;");
writer.WriteLine(" return this;");
writer.WriteLine("}");
writer.WriteLine();
writer.WriteLine("public override Builder Clone() {");
- writer.WriteLine(" return new Builder().MergeFrom(result);");
+ 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 (!UseLiteRuntime)
@@ -613,17 +664,11 @@ namespace Google.ProtocolBuffers.ProtoGen
writer.WriteLine("public override {0} BuildPartial() {{", ClassName);
writer.Indent();
- writer.WriteLine("if (result == null) {");
- writer.WriteLine(
- " throw new global::System.InvalidOperationException(\"build() has already been called on this Builder\");");
+ writer.WriteLine("if (resultIsReadOnly) {");
+ writer.WriteLine(" return result;");
writer.WriteLine("}");
- foreach (FieldDescriptor field in Descriptor.Fields)
- {
- CreateFieldGenerator(field).GenerateBuildingCode(writer);
- }
- writer.WriteLine("{0} returnMe = result;", ClassName);
- writer.WriteLine("result = null;");
- writer.WriteLine("return returnMe;");
+ writer.WriteLine("resultIsReadOnly = true;");
+ writer.WriteLine("return result.MakeReadOnly();");
writer.Outdent();
writer.WriteLine("}");
writer.WriteLine();
@@ -644,6 +689,7 @@ namespace Google.ProtocolBuffers.ProtoGen
// fields are set so we can skip the merge.
writer.Indent();
writer.WriteLine("if (other == {0}.DefaultInstance) return this;", FullClassName);
+ writer.WriteLine("PrepareBuilder();");
foreach (FieldDescriptor field in Descriptor.Fields)
{
CreateFieldGenerator(field).GenerateMergingCode(writer);
@@ -676,6 +722,7 @@ namespace Google.ProtocolBuffers.ProtoGen
writer.WriteLine(
"public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {");
writer.Indent();
+ writer.WriteLine("PrepareBuilder();");
if (!UseLiteRuntime)
{
writer.WriteLine("pb::UnknownFieldSet.Builder unknownFields = null;");