Commit 0bf2ad14 authored by Jon Skeet's avatar Jon Skeet

Implemented popsicle immutability for lists. Modified MessageStreamIterator to be singly generic.

parent ad6903fe
using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
namespace Google.ProtocolBuffers.Collections {
[TestFixture]
public class PopsicleListTest {
[Test]
public void MutatingOperationsOnFrozenList() {
PopsicleList<string> list = new PopsicleList<string>();
list.MakeReadOnly();
AssertNotSupported(() => list.Add(""));
AssertNotSupported(() => list.Clear());
AssertNotSupported(() => list.Insert(0, ""));
AssertNotSupported(() => list.Remove(""));
AssertNotSupported(() => list.RemoveAt(0));
}
[Test]
public void NonMutatingOperationsOnFrozenList() {
PopsicleList<string> list = new PopsicleList<string>();
list.MakeReadOnly();
Assert.IsFalse(list.Contains(""));
Assert.AreEqual(0, list.Count);
list.CopyTo(new string[5], 0);
list.GetEnumerator();
Assert.AreEqual(-1, list.IndexOf(""));
Assert.IsTrue(list.IsReadOnly);
}
[Test]
public void MutatingOperationsOnFluidList() {
PopsicleList<string> list = new PopsicleList<string>();
list.Add("");
list.Clear();
list.Insert(0, "");
list.Remove("");
list.Add("x"); // Just to make the next call valid
list.RemoveAt(0);
}
[Test]
public void NonMutatingOperationsOnFluidList() {
PopsicleList<string> list = new PopsicleList<string>();
Assert.IsFalse(list.Contains(""));
Assert.AreEqual(0, list.Count);
list.CopyTo(new string[5], 0);
list.GetEnumerator();
Assert.AreEqual(-1, list.IndexOf(""));
Assert.IsFalse(list.IsReadOnly);
}
private static void AssertNotSupported(Action action) {
try {
action();
Assert.Fail("Expected NotSupportedException");
} catch (NotSupportedException) {
// Expected
}
}
}
}
......@@ -13,6 +13,8 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using Google.ProtocolBuffers.Descriptors;
using Google.ProtocolBuffers.TestProtos;
using NUnit.Framework;
......@@ -28,7 +30,50 @@ namespace Google.ProtocolBuffers {
reflectionTester = ReflectionTester.CreateTestAllTypesInstance();
extensionsReflectionTester = ReflectionTester.CreateTestAllExtensionsInstance();
}
[Test]
public void RepeatedAddPrimitiveBeforeBuild() {
TestAllTypes message = new TestAllTypes.Builder { RepeatedInt32List = { 1, 2, 3 } }.Build();
TestUtil.AssertEqual(new int[]{1, 2, 3}, message.RepeatedInt32List);
}
[Test]
public void AddPrimitiveFailsAfterBuild() {
TestAllTypes.Builder builder = new TestAllTypes.Builder();
IList<int> list = builder.RepeatedInt32List;
list.Add(1); // Fine
builder.Build();
try {
list.Add(2);
Assert.Fail("List should be frozen");
} catch (NotSupportedException) {
// Expected
}
}
[Test]
public void RepeatedAddMessageBeforeBuild() {
TestAllTypes message = new TestAllTypes.Builder {
RepeatedNestedMessageList = { new TestAllTypes.Types.NestedMessage.Builder { Bb = 10 }.Build() } }.Build();
Assert.AreEqual(1, message.RepeatedNestedMessageCount);
Assert.AreEqual(10, message.RepeatedNestedMessageList[0].Bb);
}
[Test]
public void AddMessageFailsAfterBuild() {
TestAllTypes.Builder builder = new TestAllTypes.Builder();
IList<TestAllTypes.Types.NestedMessage> list = builder.RepeatedNestedMessageList;
builder.Build();
try {
list.Add(new TestAllTypes.Types.NestedMessage.Builder { Bb = 10 }.Build());
Assert.Fail("List should be frozen");
} catch (NotSupportedException) {
// Expected
}
}
[Test]
public void DefaultInstance() {
Assert.AreSame(TestAllTypes.DefaultInstance, TestAllTypes.DefaultInstance.DefaultInstanceForType);
......
......@@ -11,7 +11,7 @@ namespace Google.ProtocolBuffers {
[Test]
public void ThreeMessagesInMemory() {
MemoryStream stream = new MemoryStream(MessageStreamWriterTest.ThreeMessageData);
IEnumerable<NestedMessage> iterator = MessageStreamIterator.FromStreamProvider<NestedMessage>(() => stream);
IEnumerable<NestedMessage> iterator = MessageStreamIterator<NestedMessage>.FromStreamProvider(() => stream);
List<NestedMessage> messages = new List<NestedMessage>(iterator);
Assert.AreEqual(3, messages.Count);
......
......@@ -50,6 +50,7 @@
<Compile Include="ByteStringTest.cs" />
<Compile Include="CodedInputStreamTest.cs" />
<Compile Include="CodedOutputStreamTest.cs" />
<Compile Include="Collections\PopsicleListTest.cs" />
<Compile Include="DescriptorsTest.cs" />
<Compile Include="DynamicMessageTest.cs" />
<Compile Include="GeneratedMessageTest.cs" />
......
......@@ -7,7 +7,7 @@ using scg = global::System.Collections.Generic;
namespace Google.ProtocolBuffers.TestProtos {
public sealed partial class MessageWithNoOuter : pb::GeneratedMessage<MessageWithNoOuter, MessageWithNoOuter.Builder> {
private static readonly MessageWithNoOuter defaultInstance = new MessageWithNoOuter();
private static readonly MessageWithNoOuter defaultInstance = new Builder().BuildPartial();
public static MessageWithNoOuter DefaultInstance {
get { return defaultInstance; }
}
......@@ -35,7 +35,7 @@ namespace Google.ProtocolBuffers.TestProtos {
}
public sealed partial class NestedMessage : pb::GeneratedMessage<NestedMessage, NestedMessage.Builder> {
private static readonly NestedMessage defaultInstance = new NestedMessage();
private static readonly NestedMessage defaultInstance = new Builder().BuildPartial();
public static NestedMessage DefaultInstance {
get { return defaultInstance; }
}
......@@ -179,7 +179,7 @@ namespace Google.ProtocolBuffers.TestProtos {
}
// repeated .protobuf_unittest.TestAllTypes foreign = 2;
private scg::IList<global::Google.ProtocolBuffers.TestProtos.TestAllTypes> foreign_ = pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestAllTypes>.Empty;
private pbc::PopsicleList<global::Google.ProtocolBuffers.TestProtos.TestAllTypes> foreign_ = new pbc::PopsicleList<global::Google.ProtocolBuffers.TestProtos.TestAllTypes>();
public scg::IList<global::Google.ProtocolBuffers.TestProtos.TestAllTypes> ForeignList {
get { return foreign_; }
}
......@@ -278,9 +278,7 @@ namespace Google.ProtocolBuffers.TestProtos {
}
public override global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter BuildPartial() {
if (result.foreign_ != pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestAllTypes>.Empty) {
result.foreign_ = pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestAllTypes>.AsReadOnly(result.foreign_);
}
result.foreign_.MakeReadOnly();
global::Google.ProtocolBuffers.TestProtos.MessageWithNoOuter returnMe = result;
result = null;
return returnMe;
......@@ -324,7 +322,7 @@ namespace Google.ProtocolBuffers.TestProtos {
// repeated .protobuf_unittest.TestAllTypes foreign = 2;
public scg::IList<global::Google.ProtocolBuffers.TestProtos.TestAllTypes> ForeignList {
get { return pbc::Lists.AsReadOnly(result.foreign_); }
get { return result.foreign_; }
}
public int ForeignCount {
get { return result.ForeignCount; }
......@@ -341,28 +339,19 @@ namespace Google.ProtocolBuffers.TestProtos {
return this;
}
public Builder AddForeign(global::Google.ProtocolBuffers.TestProtos.TestAllTypes value) {
if (result.foreign_ == pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestAllTypes>.Empty) {
result.foreign_ = new scg::List<global::Google.ProtocolBuffers.TestProtos.TestAllTypes>();
}
result.foreign_.Add(value);
return this;
}
public Builder AddForeign(global::Google.ProtocolBuffers.TestProtos.TestAllTypes.Builder builderForValue) {
if (result.foreign_ == pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestAllTypes>.Empty) {
result.foreign_ = new scg::List<global::Google.ProtocolBuffers.TestProtos.TestAllTypes>();
}
result.foreign_.Add(builderForValue.Build());
return this;
}
public Builder AddRangeForeign(scg::IEnumerable<global::Google.ProtocolBuffers.TestProtos.TestAllTypes> values) {
if (result.foreign_ == pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestAllTypes>.Empty) {
result.foreign_ = new scg::List<global::Google.ProtocolBuffers.TestProtos.TestAllTypes>();
}
base.AddRange(values, result.foreign_);
return this;
}
public Builder ClearForeign() {
result.foreign_ = pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestAllTypes>.Empty;
result.foreign_.Clear();
return this;
}
......
......@@ -55,7 +55,7 @@ namespace Google.ProtocolBuffers.TestProtos {
#region Messages
public sealed partial class TestEmbedOptimizedForSize : pb::GeneratedMessage<TestEmbedOptimizedForSize, TestEmbedOptimizedForSize.Builder> {
private static readonly TestEmbedOptimizedForSize defaultInstance = new TestEmbedOptimizedForSize();
private static readonly TestEmbedOptimizedForSize defaultInstance = new Builder().BuildPartial();
public static TestEmbedOptimizedForSize DefaultInstance {
get { return defaultInstance; }
}
......@@ -87,7 +87,7 @@ namespace Google.ProtocolBuffers.TestProtos {
}
// repeated .protobuf_unittest.TestOptimizedForSize repeated_message = 2;
private scg::IList<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize> repeatedMessage_ = pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize>.Empty;
private pbc::PopsicleList<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize> repeatedMessage_ = new pbc::PopsicleList<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize>();
public scg::IList<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize> RepeatedMessageList {
get { return repeatedMessage_; }
}
......@@ -211,9 +211,7 @@ namespace Google.ProtocolBuffers.TestProtos {
}
public override global::Google.ProtocolBuffers.TestProtos.TestEmbedOptimizedForSize BuildPartial() {
if (result.repeatedMessage_ != pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize>.Empty) {
result.repeatedMessage_ = pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize>.AsReadOnly(result.repeatedMessage_);
}
result.repeatedMessage_.MakeReadOnly();
global::Google.ProtocolBuffers.TestProtos.TestEmbedOptimizedForSize returnMe = result;
result = null;
return returnMe;
......@@ -234,9 +232,6 @@ namespace Google.ProtocolBuffers.TestProtos {
MergeOptionalMessage(other.OptionalMessage);
}
if (other.repeatedMessage_.Count != 0) {
if (result.repeatedMessage_.Count == 0) {
result.repeatedMessage_ = new scg::List<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize>();
}
base.AddRange(other.repeatedMessage_, result.repeatedMessage_);
}
this.MergeUnknownFields(other.UnknownFields);
......@@ -321,7 +316,7 @@ namespace Google.ProtocolBuffers.TestProtos {
// repeated .protobuf_unittest.TestOptimizedForSize repeated_message = 2;
public scg::IList<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize> RepeatedMessageList {
get { return pbc::Lists.AsReadOnly(result.repeatedMessage_); }
get { return result.repeatedMessage_; }
}
public int RepeatedMessageCount {
get { return result.RepeatedMessageCount; }
......@@ -338,28 +333,19 @@ namespace Google.ProtocolBuffers.TestProtos {
return this;
}
public Builder AddRepeatedMessage(global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize value) {
if (result.repeatedMessage_ == pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize>.Empty) {
result.repeatedMessage_ = new scg::List<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize>();
}
result.repeatedMessage_.Add(value);
return this;
}
public Builder AddRepeatedMessage(global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize.Builder builderForValue) {
if (result.repeatedMessage_ == pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize>.Empty) {
result.repeatedMessage_ = new scg::List<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize>();
}
result.repeatedMessage_.Add(builderForValue.Build());
return this;
}
public Builder AddRangeRepeatedMessage(scg::IEnumerable<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize> values) {
if (result.repeatedMessage_ == pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize>.Empty) {
result.repeatedMessage_ = new scg::List<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize>();
}
base.AddRange(values, result.repeatedMessage_);
return this;
}
public Builder ClearRepeatedMessage() {
result.repeatedMessage_ = pbc::Lists<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize>.Empty;
result.repeatedMessage_.Clear();
return this;
}
}
......
......@@ -55,7 +55,7 @@ namespace Google.ProtocolBuffers.TestProtos {
#region Messages
public sealed partial class ImportMessage : pb::GeneratedMessage<ImportMessage, ImportMessage.Builder> {
private static readonly ImportMessage defaultInstance = new ImportMessage();
private static readonly ImportMessage defaultInstance = new Builder().BuildPartial();
public static ImportMessage DefaultInstance {
get { return defaultInstance; }
}
......
......@@ -95,7 +95,7 @@ namespace Google.ProtocolBuffers.TestProtos {
#region Messages
public sealed partial class TestMessageSet : pb::ExtendableMessage<TestMessageSet, TestMessageSet.Builder> {
private static readonly TestMessageSet defaultInstance = new TestMessageSet();
private static readonly TestMessageSet defaultInstance = new Builder().BuildPartial();
public static TestMessageSet DefaultInstance {
get { return defaultInstance; }
}
......@@ -264,7 +264,7 @@ namespace Google.ProtocolBuffers.TestProtos {
}
public sealed partial class TestMessageSetContainer : pb::GeneratedMessage<TestMessageSetContainer, TestMessageSetContainer.Builder> {
private static readonly TestMessageSetContainer defaultInstance = new TestMessageSetContainer();
private static readonly TestMessageSetContainer defaultInstance = new Builder().BuildPartial();
public static TestMessageSetContainer DefaultInstance {
get { return defaultInstance; }
}
......@@ -495,7 +495,7 @@ namespace Google.ProtocolBuffers.TestProtos {
}
public sealed partial class TestMessageSetExtension1 : pb::GeneratedMessage<TestMessageSetExtension1, TestMessageSetExtension1.Builder> {
private static readonly TestMessageSetExtension1 defaultInstance = new TestMessageSetExtension1();
private static readonly TestMessageSetExtension1 defaultInstance = new Builder().BuildPartial();
public static TestMessageSetExtension1 DefaultInstance {
get { return defaultInstance; }
}
......@@ -709,7 +709,7 @@ namespace Google.ProtocolBuffers.TestProtos {
}
public sealed partial class TestMessageSetExtension2 : pb::GeneratedMessage<TestMessageSetExtension2, TestMessageSetExtension2.Builder> {
private static readonly TestMessageSetExtension2 defaultInstance = new TestMessageSetExtension2();
private static readonly TestMessageSetExtension2 defaultInstance = new Builder().BuildPartial();
public static TestMessageSetExtension2 DefaultInstance {
get { return defaultInstance; }
}
......@@ -923,7 +923,7 @@ namespace Google.ProtocolBuffers.TestProtos {
}
public sealed partial class RawMessageSet : pb::GeneratedMessage<RawMessageSet, RawMessageSet.Builder> {
private static readonly RawMessageSet defaultInstance = new RawMessageSet();
private static readonly RawMessageSet defaultInstance = new Builder().BuildPartial();
public static RawMessageSet DefaultInstance {
get { return defaultInstance; }
}
......@@ -947,7 +947,7 @@ namespace Google.ProtocolBuffers.TestProtos {
#region Nested types
public static class Types {
public sealed partial class Item : pb::GeneratedMessage<Item, Item.Builder> {
private static readonly Item defaultInstance = new Item();
private static readonly Item defaultInstance = new Builder().BuildPartial();
public static Item DefaultInstance {
get { return defaultInstance; }
}
......@@ -1201,7 +1201,7 @@ namespace Google.ProtocolBuffers.TestProtos {
#endregion
// repeated group Item = 1 {
private scg::IList<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item> item_ = pbc::Lists<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item>.Empty;
private pbc::PopsicleList<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item> item_ = new pbc::PopsicleList<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item>();
public scg::IList<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item> ItemList {
get { return item_; }
}
......@@ -1316,9 +1316,7 @@ namespace Google.ProtocolBuffers.TestProtos {
}
public override global::Google.ProtocolBuffers.TestProtos.RawMessageSet BuildPartial() {
if (result.item_ != pbc::Lists<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item>.Empty) {
result.item_ = pbc::Lists<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item>.AsReadOnly(result.item_);
}
result.item_.MakeReadOnly();
global::Google.ProtocolBuffers.TestProtos.RawMessageSet returnMe = result;
result = null;
return returnMe;
......@@ -1336,9 +1334,6 @@ namespace Google.ProtocolBuffers.TestProtos {
public override Builder MergeFrom(global::Google.ProtocolBuffers.TestProtos.RawMessageSet other) {
if (other == global::Google.ProtocolBuffers.TestProtos.RawMessageSet.DefaultInstance) return this;
if (other.item_.Count != 0) {
if (result.item_.Count == 0) {
result.item_ = new scg::List<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item>();
}
base.AddRange(other.item_, result.item_);
}
this.MergeUnknownFields(other.UnknownFields);
......@@ -1379,7 +1374,7 @@ namespace Google.ProtocolBuffers.TestProtos {
// repeated group Item = 1 {
public scg::IList<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item> ItemList {
get { return pbc::Lists.AsReadOnly(result.item_); }
get { return result.item_; }
}
public int ItemCount {
get { return result.ItemCount; }
......@@ -1396,28 +1391,19 @@ namespace Google.ProtocolBuffers.TestProtos {
return this;
}
public Builder AddItem(global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item value) {
if (result.item_ == pbc::Lists<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item>.Empty) {
result.item_ = new scg::List<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item>();
}
result.item_.Add(value);
return this;
}
public Builder AddItem(global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item.Builder builderForValue) {
if (result.item_ == pbc::Lists<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item>.Empty) {
result.item_ = new scg::List<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item>();
}
result.item_.Add(builderForValue.Build());
return this;
}
public Builder AddRangeItem(scg::IEnumerable<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item> values) {
if (result.item_ == pbc::Lists<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item>.Empty) {
result.item_ = new scg::List<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item>();
}
base.AddRange(values, result.item_);
return this;
}
public Builder ClearItem() {
result.item_ = pbc::Lists<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item>.Empty;
result.item_.Clear();
return this;
}
}
......
......@@ -54,7 +54,7 @@ namespace Google.ProtocolBuffers.TestProtos {
#region Messages
public sealed partial class TestOptimizedForSize : pb::ExtendableMessage<TestOptimizedForSize, TestOptimizedForSize.Builder> {
private static readonly TestOptimizedForSize defaultInstance = new TestOptimizedForSize();
private static readonly TestOptimizedForSize defaultInstance = new Builder().BuildPartial();
public static TestOptimizedForSize DefaultInstance {
get { return defaultInstance; }
}
......
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace Google.ProtocolBuffers.Collections {
/// <summary>
/// Proxies calls to a <see cref="List{T}" />, but allows the list
/// to be made read-only (with the <see cref="MakeReadOnly" /> method),
/// after which any modifying methods throw <see cref="NotSupportedException" />.
/// </summary>
public sealed class PopsicleList<T> : IList<T> {
private readonly List<T> items = new List<T>();
private bool readOnly = false;
/// <summary>
/// Makes this list read-only ("freezes the popsicle"). From this
/// point on, mutating methods (Clear, Add etc) will throw a
/// NotSupportedException. There is no way of "defrosting" the list afterwards.
/// </summary>
public void MakeReadOnly() {
readOnly = true;
}
public int IndexOf(T item) {
return items.IndexOf(item);
}
public void Insert(int index, T item) {
ValidateModification();
items.Insert(index, item);
}
public void RemoveAt(int index) {
ValidateModification();
items.RemoveAt(index);
}
public T this[int index] {
get {
return items[index];
}
set {
ValidateModification();
items[index] = value;
}
}
public void Add(T item) {
ValidateModification();
items.Add(item);
}
public void Clear() {
ValidateModification();
items.Clear();
}
public bool Contains(T item) {
return items.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex) {
items.CopyTo(array, arrayIndex);
}
public int Count {
get { return items.Count; }
}
public bool IsReadOnly {
get { return readOnly; }
}
public bool Remove(T item) {
ValidateModification();
return items.Remove(item);
}
public IEnumerator<T> GetEnumerator() {
return items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
private void ValidateModification() {
if (readOnly) {
throw new NotSupportedException("List is read-only");
}
}
}
}
using System.IO;
namespace Google.ProtocolBuffers {
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.
// http://code.google.com/p/protobuf/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.IO;
namespace Google.ProtocolBuffers {
/// <summary>
/// Delegate to return a stream when asked, used by MessageStreamIterator.
/// </summary>
public delegate Stream StreamProvider();
// These delegate declarations mirror the ones in .NET 3.5 for the sake of familiarity.
internal delegate TResult Func<TResult>();
internal delegate TResult Func<T, TResult>(T arg);
internal delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
internal delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
internal delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
internal delegate void Action();
internal delegate void Action<T1, T2>(T1 arg1, T2 arg2);
}
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.
// http://code.google.com/p/protobuf/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Google.ProtocolBuffers.FieldAccess {
// These delegate declarations mirror the ones in .NET 3.5 for the sake of familiarity.
internal delegate TResult Func<TResult>();
internal delegate TResult Func<T, TResult>(T arg);
internal delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
internal delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
internal delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
internal delegate void Action<T1, T2>(T1 arg1, T2 arg2);
}
......@@ -41,6 +41,7 @@
<Compile Include="AbstractBuilder.cs" />
<Compile Include="AbstractMessage.cs" />
<Compile Include="ByteString.cs" />
<Compile Include="Collections\PopsicleList.cs" />
<Compile Include="Delegates.cs" />
<Compile Include="CodedInputStream.cs" />
<Compile Include="CodedOutputStream.cs" />
......@@ -72,7 +73,6 @@
<Compile Include="ExtendableMessage.cs" />
<Compile Include="ExtensionInfo.cs" />
<Compile Include="ExtensionRegistry.cs" />
<Compile Include="FieldAccess\Delegates.cs" />
<Compile Include="FieldAccess\ReflectionUtil.cs" />
<Compile Include="FieldAccess\SingleEnumAccessor.cs" />
<Compile Include="FieldAccess\SingleMessageAccessor.cs" />
......
......@@ -212,7 +212,8 @@ void MessageGenerator::Generate(io::Printer* printer) {
}
printer->Indent();
printer->Print(
"private static readonly $classname$ defaultInstance = new $classname$();\r\n"
// Must call Build() to make sure all lists are made read-only
"private static readonly $classname$ defaultInstance = new Builder().BuildPartial();\r\n"
"public static $classname$ DefaultInstance {\r\n"
" get { return defaultInstance; }\r\n"
"}\r\n"
......
......@@ -175,9 +175,9 @@ RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
void RepeatedMessageFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
"private scg::IList<$type$> $name$_ = pbc::Lists<$type$>.Empty;\r\n"
"private pbc::PopsicleList<$type$> $name$_ = new pbc::PopsicleList<$type$>();\r\n"
"public scg::IList<$type$> $capitalized_name$List {\r\n"
" get { return $name$_; } \r\n" // note: unmodifiable list
" get { return $name$_; } \r\n" // Will be unmodifiable by the time it's exposed
"}\r\n"
"public int $capitalized_name$Count\r\n"
" { get { return $name$_.Count; }\r\n"
......@@ -190,12 +190,10 @@ GenerateMembers(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
// Note: We return an unmodifiable list because otherwise the caller
// could hold on to the returned list and modify it after the message
// has been built, thus mutating the message which is supposed to be
// immutable.
// Note: We can return the original list here, because we
// make it read-only when we build.
"public scg::IList<$type$> $capitalized_name$List {\r\n"
" get { return pbc::Lists.AsReadOnly(result.$name$_); }\r\n"
" get { return result.$name$_; }\r\n"
"}\r\n"
"public int $capitalized_name$Count {\r\n"
" get { return result.$capitalized_name$Count; }\r\n"
......@@ -212,28 +210,19 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return this;\r\n"
"}\r\n"
"public Builder Add$capitalized_name$($type$ value) {\r\n"
" if (result.$name$_ == pbc::Lists<$type$>.Empty) {\r\n"
" result.$name$_ = new scg::List<$type$>();\r\n"
" }\r\n"
" result.$name$_.Add(value);\r\n"
" return this;\r\n"
"}\r\n"
"public Builder Add$capitalized_name$($type$.Builder builderForValue) {\r\n"
" if (result.$name$_ == pbc::Lists<$type$>.Empty) {\r\n"
" result.$name$_ = new scg::List<$type$>();\r\n"
" }\r\n"
" result.$name$_.Add(builderForValue.Build());\r\n"
" return this;\r\n"
"}\r\n"
"public Builder AddRange$capitalized_name$(scg::IEnumerable<$type$> values) {\r\n"
" if (result.$name$_ == pbc::Lists<$type$>.Empty) {\r\n"
" result.$name$_ = new scg::List<$type$>();\r\n"
" }\r\n"
" base.AddRange(values, result.$name$_);\r\n"
" return this;\r\n"
"}\r\n"
"public Builder Clear$capitalized_name$() {\r\n"
" result.$name$_ = pbc::Lists<$type$>.Empty;\r\n"
" result.$name$_.Clear();\r\n"
" return this;\r\n"
"}\r\n");
}
......@@ -242,9 +231,6 @@ void RepeatedMessageFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
printer->Print(variables_,
"if (other.$name$_.Count != 0) {\r\n"
" if (result.$name$_.Count == 0) {\r\n"
" result.$name$_ = new scg::List<$type$>();\r\n"
" }\r\n"
" base.AddRange(other.$name$_, result.$name$_);\r\n"
"}\r\n");
}
......@@ -252,9 +238,7 @@ GenerateMergingCode(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateBuildingCode(io::Printer* printer) const {
printer->Print(variables_,
"if (result.$name$_ != pbc::Lists<$type$>.Empty) {\r\n"
" result.$name$_ = pbc::Lists<$type$>.AsReadOnly(result.$name$_);\r\n"
"}\r\n");
"result.$name$_.MakeReadOnly();\r\n");
}
void RepeatedMessageFieldGenerator::
......
......@@ -239,9 +239,9 @@ RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
void RepeatedPrimitiveFieldGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
"private scg::IList<$type$> $name$_ = pbc::Lists<$type$>.Empty;\r\n"
"private pbc::PopsicleList<$type$> $name$_ = new pbc::PopsicleList<$type$>();\r\n"
"public scg::IList<$type$> $capitalized_name$List {\r\n"
" get { return $name$_; }\r\n" // note: unmodifiable list
" get { return $name$_; } \r\n" // Will be unmodifiable by the time it's exposed
"}\r\n"
"public int $capitalized_name$Count {\r\n"
" get { return $name$_.Count; }\r\n"
......@@ -254,12 +254,10 @@ GenerateMembers(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
// Note: We return an unmodifiable list because otherwise the caller
// could hold on to the returned list and modify it after the message
// has been built, thus mutating the message which is supposed to be
// immutable. This unfortunately limits the use for collection initializers...
// Note: We can return the original list here, because we
// make it read-only when we build.
"public scg::IList<$type$> $capitalized_name$List {\r\n"
" get { return pbc::Lists<$type$>.AsReadOnly(result.$name$_); }\r\n"
" get { return result.$name$_; }\r\n"
"}\r\n"
"public int $capitalized_name$Count {\r\n"
" get { return result.$capitalized_name$Count; }\r\n"
......@@ -272,21 +270,15 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return this;\r\n"
"}\r\n"
"public Builder Add$capitalized_name$($type$ value) {\r\n"
" if (result.$name$_.Count == 0) {\r\n"
" result.$name$_ = new scg::List<$type$>();\r\n"
" }\r\n"
" result.$name$_.Add(value);\r\n"
" return this;\r\n"
"}\r\n"
"public Builder AddRange$capitalized_name$(scg::IEnumerable<$type$> values) {\r\n"
" if (result.$name$_.Count == 0) {\r\n"
" result.$name$_ = new scg::List<$type$>();\r\n"
" }\r\n"
" base.AddRange(values, result.$name$_);\r\n"
" return this;\r\n"
"}\r\n"
"public Builder Clear$capitalized_name$() {\r\n"
" result.$name$_ = pbc::Lists<$type$>.Empty;\r\n"
" result.$name$_.Clear();\r\n"
" return this;\r\n"
"}\r\n");
}
......@@ -295,9 +287,6 @@ void RepeatedPrimitiveFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
printer->Print(variables_,
"if (other.$name$_.Count != 0) {\r\n"
" if (result.$name$_.Count == 0) {\r\n"
" result.$name$_ = new scg::List<$type$>();\r\n"
" }\r\n"
" base.AddRange(other.$name$_, result.$name$_);\r\n"
"}\r\n");
}
......@@ -305,7 +294,7 @@ GenerateMergingCode(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateBuildingCode(io::Printer* printer) const {
printer->Print(variables_,
"result.$name$_ = pbc::Lists<$type$>.AsReadOnly(result.$name$_);\r\n");
"result.$name$_.MakeReadOnly();\r\n");
}
void RepeatedPrimitiveFieldGenerator::
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment