Merge pull request #566 from jskeet/csharp-reflection
Improve C# reflection support
This commit is contained in:
commit
94878b3080
@ -13,12 +13,9 @@ namespace Google.Protobuf.Examples.AddressBook {
|
||||
public static partial class Addressbook {
|
||||
|
||||
#region Static variables
|
||||
internal static pbd::MessageDescriptor internal__static_tutorial_Person__Descriptor;
|
||||
internal static pb::FieldAccess.FieldAccessorTable<global::Google.Protobuf.Examples.AddressBook.Person> internal__static_tutorial_Person__FieldAccessorTable;
|
||||
internal static pbd::MessageDescriptor internal__static_tutorial_Person_PhoneNumber__Descriptor;
|
||||
internal static pb::FieldAccess.FieldAccessorTable<global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber> internal__static_tutorial_Person_PhoneNumber__FieldAccessorTable;
|
||||
internal static pbd::MessageDescriptor internal__static_tutorial_AddressBook__Descriptor;
|
||||
internal static pb::FieldAccess.FieldAccessorTable<global::Google.Protobuf.Examples.AddressBook.AddressBook> internal__static_tutorial_AddressBook__FieldAccessorTable;
|
||||
internal static pb::FieldAccess.FieldAccessorTable internal__static_tutorial_Person__FieldAccessorTable;
|
||||
internal static pb::FieldAccess.FieldAccessorTable internal__static_tutorial_Person_PhoneNumber__FieldAccessorTable;
|
||||
internal static pb::FieldAccess.FieldAccessorTable internal__static_tutorial_AddressBook__FieldAccessorTable;
|
||||
#endregion
|
||||
#region Descriptor
|
||||
public static pbd::FileDescriptor Descriptor {
|
||||
@ -29,33 +26,27 @@ namespace Google.Protobuf.Examples.AddressBook {
|
||||
static Addressbook() {
|
||||
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||
string.Concat(
|
||||
"ChFhZGRyZXNzYm9vay5wcm90bxIIdHV0b3JpYWwi2gEKBlBlcnNvbhIMCgRu",
|
||||
"YW1lGAEgAigJEgoKAmlkGAIgAigFEg0KBWVtYWlsGAMgASgJEisKBXBob25l",
|
||||
"GAQgAygLMhwudHV0b3JpYWwuUGVyc29uLlBob25lTnVtYmVyGk0KC1Bob25l",
|
||||
"TnVtYmVyEg4KBm51bWJlchgBIAIoCRIuCgR0eXBlGAIgASgOMhoudHV0b3Jp",
|
||||
"YWwuUGVyc29uLlBob25lVHlwZToESE9NRSIrCglQaG9uZVR5cGUSCgoGTU9C",
|
||||
"SUxFEAASCAoESE9NRRABEggKBFdPUksQAiIvCgtBZGRyZXNzQm9vaxIgCgZw",
|
||||
"ZXJzb24YASADKAsyEC50dXRvcmlhbC5QZXJzb25CUAoUY29tLmV4YW1wbGUu",
|
||||
"dHV0b3JpYWxCEUFkZHJlc3NCb29rUHJvdG9zqgIkR29vZ2xlLlByb3RvYnVm",
|
||||
"LkV4YW1wbGVzLkFkZHJlc3NCb29r"));
|
||||
pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
|
||||
descriptor = root;
|
||||
internal__static_tutorial_Person__Descriptor = Descriptor.MessageTypes[0];
|
||||
internal__static_tutorial_Person__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable<global::Google.Protobuf.Examples.AddressBook.Person>(internal__static_tutorial_Person__Descriptor,
|
||||
new string[] { "Name", "Id", "Email", "Phone", });
|
||||
internal__static_tutorial_Person_PhoneNumber__Descriptor = internal__static_tutorial_Person__Descriptor.NestedTypes[0];
|
||||
internal__static_tutorial_Person_PhoneNumber__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable<global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber>(internal__static_tutorial_Person_PhoneNumber__Descriptor,
|
||||
new string[] { "Number", "Type", });
|
||||
internal__static_tutorial_AddressBook__Descriptor = Descriptor.MessageTypes[1];
|
||||
internal__static_tutorial_AddressBook__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable<global::Google.Protobuf.Examples.AddressBook.AddressBook>(internal__static_tutorial_AddressBook__Descriptor,
|
||||
new string[] { "Person", });
|
||||
};
|
||||
pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
|
||||
"ChFhZGRyZXNzYm9vay5wcm90bxIIdHV0b3JpYWwi1AEKBlBlcnNvbhIMCgRu",
|
||||
"YW1lGAEgASgJEgoKAmlkGAIgASgFEg0KBWVtYWlsGAMgASgJEisKBXBob25l",
|
||||
"GAQgAygLMhwudHV0b3JpYWwuUGVyc29uLlBob25lTnVtYmVyGkcKC1Bob25l",
|
||||
"TnVtYmVyEg4KBm51bWJlchgBIAEoCRIoCgR0eXBlGAIgASgOMhoudHV0b3Jp",
|
||||
"YWwuUGVyc29uLlBob25lVHlwZSIrCglQaG9uZVR5cGUSCgoGTU9CSUxFEAAS",
|
||||
"CAoESE9NRRABEggKBFdPUksQAiIvCgtBZGRyZXNzQm9vaxIgCgZwZXJzb24Y",
|
||||
"ASADKAsyEC50dXRvcmlhbC5QZXJzb25CUAoUY29tLmV4YW1wbGUudHV0b3Jp",
|
||||
"YWxCEUFkZHJlc3NCb29rUHJvdG9zqgIkR29vZ2xlLlByb3RvYnVmLkV4YW1w",
|
||||
"bGVzLkFkZHJlc3NCb29rYgZwcm90bzM="));
|
||||
descriptor = pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
|
||||
new pbd::FileDescriptor[] {
|
||||
}, assigner);
|
||||
});
|
||||
internal__static_tutorial_Person__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable(typeof(global::Google.Protobuf.Examples.AddressBook.Person), descriptor.MessageTypes[0],
|
||||
new string[] { "Name", "Id", "Email", "Phone", });
|
||||
internal__static_tutorial_Person_PhoneNumber__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable(typeof(global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber), descriptor.MessageTypes[0].NestedTypes[0],
|
||||
new string[] { "Number", "Type", });
|
||||
internal__static_tutorial_AddressBook__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable(typeof(global::Google.Protobuf.Examples.AddressBook.AddressBook), descriptor.MessageTypes[1],
|
||||
new string[] { "Person", });
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -69,19 +60,23 @@ namespace Google.Protobuf.Examples.AddressBook {
|
||||
private static readonly string[] _fieldNames = new string[] { "email", "id", "name", "phone" };
|
||||
private static readonly uint[] _fieldTags = new uint[] { 26, 16, 10, 34 };
|
||||
public static pbd::MessageDescriptor Descriptor {
|
||||
get { return global::Google.Protobuf.Examples.AddressBook.Addressbook.internal__static_tutorial_Person__Descriptor; }
|
||||
get { return global::Google.Protobuf.Examples.AddressBook.Addressbook.Descriptor.MessageTypes[0]; }
|
||||
}
|
||||
|
||||
public pb::FieldAccess.FieldAccessorTable<Person> Fields {
|
||||
public pb::FieldAccess.FieldAccessorTable Fields {
|
||||
get { return global::Google.Protobuf.Examples.AddressBook.Addressbook.internal__static_tutorial_Person__FieldAccessorTable; }
|
||||
}
|
||||
|
||||
private bool _frozen = false;
|
||||
public bool IsFrozen { get { return _frozen; } }
|
||||
|
||||
public Person() { }
|
||||
public Person() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
public Person(Person other) {
|
||||
partial void OnConstruction();
|
||||
|
||||
public Person(Person other) : this() {
|
||||
name_ = other.name_;
|
||||
id_ = other.id_;
|
||||
email_ = other.email_;
|
||||
@ -260,19 +255,23 @@ namespace Google.Protobuf.Examples.AddressBook {
|
||||
private static readonly string[] _fieldNames = new string[] { "number", "type" };
|
||||
private static readonly uint[] _fieldTags = new uint[] { 10, 16 };
|
||||
public static pbd::MessageDescriptor Descriptor {
|
||||
get { return global::Google.Protobuf.Examples.AddressBook.Addressbook.internal__static_tutorial_Person_PhoneNumber__Descriptor; }
|
||||
get { return global::Google.Protobuf.Examples.AddressBook.Person.Descriptor.NestedTypes[0]; }
|
||||
}
|
||||
|
||||
public pb::FieldAccess.FieldAccessorTable<PhoneNumber> Fields {
|
||||
public pb::FieldAccess.FieldAccessorTable Fields {
|
||||
get { return global::Google.Protobuf.Examples.AddressBook.Addressbook.internal__static_tutorial_Person_PhoneNumber__FieldAccessorTable; }
|
||||
}
|
||||
|
||||
private bool _frozen = false;
|
||||
public bool IsFrozen { get { return _frozen; } }
|
||||
|
||||
public PhoneNumber() { }
|
||||
public PhoneNumber() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
public PhoneNumber(PhoneNumber other) {
|
||||
partial void OnConstruction();
|
||||
|
||||
public PhoneNumber(PhoneNumber other) : this() {
|
||||
number_ = other.number_;
|
||||
type_ = other.type_;
|
||||
}
|
||||
@ -299,7 +298,7 @@ namespace Google.Protobuf.Examples.AddressBook {
|
||||
}
|
||||
|
||||
public const int TypeFieldNumber = 2;
|
||||
private global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType type_ = global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.HOME;
|
||||
private global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType type_ = global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE;
|
||||
public global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType Type {
|
||||
get { return type_; }
|
||||
set {
|
||||
@ -327,7 +326,7 @@ namespace Google.Protobuf.Examples.AddressBook {
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (Number.Length != 0) hash ^= Number.GetHashCode();
|
||||
if (Type != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.HOME) hash ^= Type.GetHashCode();
|
||||
if (Type != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE) hash ^= Type.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -336,7 +335,7 @@ namespace Google.Protobuf.Examples.AddressBook {
|
||||
output.WriteRawTag(10);
|
||||
output.WriteString(Number);
|
||||
}
|
||||
if (Type != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.HOME) {
|
||||
if (Type != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE) {
|
||||
output.WriteRawTag(16);
|
||||
output.WriteEnum((int) Type);
|
||||
}
|
||||
@ -347,7 +346,7 @@ namespace Google.Protobuf.Examples.AddressBook {
|
||||
if (Number.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Number);
|
||||
}
|
||||
if (Type != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.HOME) {
|
||||
if (Type != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type);
|
||||
}
|
||||
return size;
|
||||
@ -360,7 +359,7 @@ namespace Google.Protobuf.Examples.AddressBook {
|
||||
if (other.Number.Length != 0) {
|
||||
Number = other.Number;
|
||||
}
|
||||
if (other.Type != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.HOME) {
|
||||
if (other.Type != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE) {
|
||||
Type = other.Type;
|
||||
}
|
||||
}
|
||||
@ -403,19 +402,23 @@ namespace Google.Protobuf.Examples.AddressBook {
|
||||
private static readonly string[] _fieldNames = new string[] { "person" };
|
||||
private static readonly uint[] _fieldTags = new uint[] { 10 };
|
||||
public static pbd::MessageDescriptor Descriptor {
|
||||
get { return global::Google.Protobuf.Examples.AddressBook.Addressbook.internal__static_tutorial_AddressBook__Descriptor; }
|
||||
get { return global::Google.Protobuf.Examples.AddressBook.Addressbook.Descriptor.MessageTypes[1]; }
|
||||
}
|
||||
|
||||
public pb::FieldAccess.FieldAccessorTable<AddressBook> Fields {
|
||||
public pb::FieldAccess.FieldAccessorTable Fields {
|
||||
get { return global::Google.Protobuf.Examples.AddressBook.Addressbook.internal__static_tutorial_AddressBook__FieldAccessorTable; }
|
||||
}
|
||||
|
||||
private bool _frozen = false;
|
||||
public bool IsFrozen { get { return _frozen; } }
|
||||
|
||||
public AddressBook() { }
|
||||
public AddressBook() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
public AddressBook(AddressBook other) {
|
||||
partial void OnConstruction();
|
||||
|
||||
public AddressBook(AddressBook other) : this() {
|
||||
person_ = other.person_.Clone();
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Google.Protobuf.TestProtos;
|
||||
using NUnit.Framework;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
|
||||
namespace Google.Protobuf.Collections
|
||||
{
|
||||
@ -53,6 +55,18 @@ namespace Google.Protobuf.Collections
|
||||
Assert.IsTrue(message.IsFrozen);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Freeze_Idempotent()
|
||||
{
|
||||
var message = new ForeignMessage { C = 20 };
|
||||
var map = new MapField<string, ForeignMessage> { { "x", message } };
|
||||
Assert.IsFalse(map.IsFrozen);
|
||||
map.Freeze();
|
||||
Assert.IsTrue(message.IsFrozen);
|
||||
map.Freeze();
|
||||
Assert.IsTrue(message.IsFrozen);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Freeze_PreventsMutation()
|
||||
{
|
||||
@ -187,6 +201,15 @@ namespace Google.Protobuf.Collections
|
||||
EqualityTester.AssertInequality(map1, map2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Equality_Simple()
|
||||
{
|
||||
var map = new MapField<string, string>();
|
||||
EqualityTester.AssertEquality(map, map);
|
||||
EqualityTester.AssertInequality(map, null);
|
||||
Assert.IsFalse(map.Equals(new object()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EqualityIsValueSensitive()
|
||||
{
|
||||
@ -287,7 +310,8 @@ namespace Google.Protobuf.Collections
|
||||
Assert.IsFalse(map.Remove("missing"));
|
||||
Assert.AreEqual(1, map.Count);
|
||||
Assert.IsTrue(map.Remove("foo"));
|
||||
Assert.AreEqual(0, map.Count);
|
||||
Assert.AreEqual(0, map.Count);
|
||||
Assert.Throws<ArgumentNullException>(() => map.Remove(null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -346,6 +370,164 @@ namespace Google.Protobuf.Collections
|
||||
Assert.AreEqual("z", map["x"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetEnumerator_NonGeneric()
|
||||
{
|
||||
IEnumerable map = new MapField<string, string> { { "x", "y" } };
|
||||
CollectionAssert.AreEqual(new[] { new KeyValuePair<string, string>("x", "y") },
|
||||
map.Cast<object>().ToList());
|
||||
}
|
||||
|
||||
// Test for the explicitly-implemented non-generic IDictionary interface
|
||||
[Test]
|
||||
public void IDictionary_GetEnumerator()
|
||||
{
|
||||
IDictionary map = new MapField<string, string> { { "x", "y" } };
|
||||
var enumerator = map.GetEnumerator();
|
||||
|
||||
// Commented assertions show an ideal situation - it looks like
|
||||
// the LinkedList enumerator doesn't throw when you ask for the current entry
|
||||
// at an inappropriate time; fixing this would be more work than it's worth.
|
||||
// Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.AreEqual("x", enumerator.Key);
|
||||
Assert.AreEqual("y", enumerator.Value);
|
||||
Assert.AreEqual(new DictionaryEntry("x", "y"), enumerator.Current);
|
||||
Assert.AreEqual(new DictionaryEntry("x", "y"), enumerator.Entry);
|
||||
Assert.IsFalse(enumerator.MoveNext());
|
||||
// Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
|
||||
enumerator.Reset();
|
||||
// Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.AreEqual("x", enumerator.Key); // Assume the rest are okay
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IDictionary_Add()
|
||||
{
|
||||
var map = new MapField<string, string> { { "x", "y" } };
|
||||
IDictionary dictionary = map;
|
||||
dictionary.Add("a", "b");
|
||||
Assert.AreEqual("b", map["a"]);
|
||||
Assert.Throws<ArgumentException>(() => dictionary.Add("a", "duplicate"));
|
||||
Assert.Throws<InvalidCastException>(() => dictionary.Add(new object(), "key is bad"));
|
||||
Assert.Throws<InvalidCastException>(() => dictionary.Add("value is bad", new object()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IDictionary_Contains()
|
||||
{
|
||||
var map = new MapField<string, string> { { "x", "y" } };
|
||||
IDictionary dictionary = map;
|
||||
|
||||
Assert.IsFalse(dictionary.Contains("a"));
|
||||
Assert.IsFalse(dictionary.Contains(5));
|
||||
// Surprising, but IDictionary.Contains is only about keys.
|
||||
Assert.IsFalse(dictionary.Contains(new DictionaryEntry("x", "y")));
|
||||
Assert.IsTrue(dictionary.Contains("x"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IDictionary_Remove()
|
||||
{
|
||||
var map = new MapField<string, string> { { "x", "y" } };
|
||||
IDictionary dictionary = map;
|
||||
dictionary.Remove("a");
|
||||
Assert.AreEqual(1, dictionary.Count);
|
||||
dictionary.Remove(5);
|
||||
Assert.AreEqual(1, dictionary.Count);
|
||||
dictionary.Remove(new DictionaryEntry("x", "y"));
|
||||
Assert.AreEqual(1, dictionary.Count);
|
||||
dictionary.Remove("x");
|
||||
Assert.AreEqual(0, dictionary.Count);
|
||||
Assert.Throws<ArgumentNullException>(() => dictionary.Remove(null));
|
||||
|
||||
map.Freeze();
|
||||
// Call should fail even though it clearly doesn't contain 5 as a key.
|
||||
Assert.Throws<InvalidOperationException>(() => dictionary.Remove(5));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IDictionary_CopyTo()
|
||||
{
|
||||
var map = new MapField<string, string> { { "x", "y" } };
|
||||
IDictionary dictionary = map;
|
||||
var array = new DictionaryEntry[3];
|
||||
dictionary.CopyTo(array, 1);
|
||||
CollectionAssert.AreEqual(new[] { default(DictionaryEntry), new DictionaryEntry("x", "y"), default(DictionaryEntry) },
|
||||
array);
|
||||
var objectArray = new object[3];
|
||||
dictionary.CopyTo(objectArray, 1);
|
||||
CollectionAssert.AreEqual(new object[] { null, new DictionaryEntry("x", "y"), null },
|
||||
objectArray);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IDictionary_IsFixedSize()
|
||||
{
|
||||
var map = new MapField<string, string> { { "x", "y" } };
|
||||
IDictionary dictionary = map;
|
||||
Assert.IsFalse(dictionary.IsFixedSize);
|
||||
map.Freeze();
|
||||
Assert.IsTrue(dictionary.IsFixedSize);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IDictionary_Keys()
|
||||
{
|
||||
IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
|
||||
CollectionAssert.AreEqual(new[] { "x" }, dictionary.Keys);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IDictionary_Values()
|
||||
{
|
||||
IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
|
||||
CollectionAssert.AreEqual(new[] { "y" }, dictionary.Values);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IDictionary_IsSynchronized()
|
||||
{
|
||||
IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
|
||||
Assert.IsFalse(dictionary.IsSynchronized);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IDictionary_SyncRoot()
|
||||
{
|
||||
IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
|
||||
Assert.AreSame(dictionary, dictionary.SyncRoot);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IDictionary_Indexer_Get()
|
||||
{
|
||||
IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
|
||||
Assert.AreEqual("y", dictionary["x"]);
|
||||
Assert.IsNull(dictionary["a"]);
|
||||
Assert.IsNull(dictionary[5]);
|
||||
Assert.Throws<ArgumentNullException>(() => dictionary[null].GetHashCode());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IDictionary_Indexer_Set()
|
||||
{
|
||||
var map = new MapField<string, string> { { "x", "y" } };
|
||||
IDictionary dictionary = map;
|
||||
map["a"] = "b";
|
||||
Assert.AreEqual("b", map["a"]);
|
||||
map["a"] = "c";
|
||||
Assert.AreEqual("c", map["a"]);
|
||||
Assert.Throws<InvalidCastException>(() => dictionary[5] = "x");
|
||||
Assert.Throws<InvalidCastException>(() => dictionary["x"] = 5);
|
||||
Assert.Throws<ArgumentNullException>(() => dictionary[null] = "z");
|
||||
Assert.Throws<ArgumentNullException>(() => dictionary["x"] = null);
|
||||
map.Freeze();
|
||||
// Note: Not InvalidOperationException.
|
||||
Assert.Throws<NotSupportedException>(() => dictionary["a"] = "c");
|
||||
}
|
||||
|
||||
private static KeyValuePair<TKey, TValue> NewKeyValuePair<TKey, TValue>(TKey key, TValue value)
|
||||
{
|
||||
return new KeyValuePair<TKey, TValue>(key, value);
|
||||
|
@ -31,9 +31,11 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Google.Protobuf.TestProtos;
|
||||
using NUnit.Framework;
|
||||
|
||||
@ -82,6 +84,115 @@ namespace Google.Protobuf.Collections
|
||||
Assert.AreEqual("bar", list[2]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveAt_Valid()
|
||||
{
|
||||
var list = new RepeatedField<string> { "first", "second", "third" };
|
||||
list.RemoveAt(1);
|
||||
CollectionAssert.AreEqual(new[] { "first", "third" }, list);
|
||||
// Just check that these don't throw...
|
||||
list.RemoveAt(list.Count - 1); // Now the count will be 1...
|
||||
list.RemoveAt(0);
|
||||
Assert.AreEqual(0, list.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveAt_Invalid()
|
||||
{
|
||||
var list = new RepeatedField<string> { "first", "second", "third" };
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => list.RemoveAt(-1));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => list.RemoveAt(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Insert_Valid()
|
||||
{
|
||||
var list = new RepeatedField<string> { "first", "second" };
|
||||
list.Insert(1, "middle");
|
||||
CollectionAssert.AreEqual(new[] { "first", "middle", "second" }, list);
|
||||
list.Insert(3, "end");
|
||||
CollectionAssert.AreEqual(new[] { "first", "middle", "second", "end" }, list);
|
||||
list.Insert(0, "start");
|
||||
CollectionAssert.AreEqual(new[] { "start", "first", "middle", "second", "end" }, list);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Insert_Invalid()
|
||||
{
|
||||
var list = new RepeatedField<string> { "first", "second" };
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => list.Insert(-1, "foo"));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => list.Insert(3, "foo"));
|
||||
Assert.Throws<ArgumentNullException>(() => list.Insert(0, null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Equals_RepeatedField()
|
||||
{
|
||||
var list = new RepeatedField<string> { "first", "second" };
|
||||
Assert.IsFalse(list.Equals((RepeatedField<string>) null));
|
||||
Assert.IsTrue(list.Equals(list));
|
||||
Assert.IsFalse(list.Equals(new RepeatedField<string> { "first", "third" }));
|
||||
Assert.IsFalse(list.Equals(new RepeatedField<string> { "first" }));
|
||||
Assert.IsTrue(list.Equals(new RepeatedField<string> { "first", "second" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Equals_Object()
|
||||
{
|
||||
var list = new RepeatedField<string> { "first", "second" };
|
||||
Assert.IsFalse(list.Equals((object) null));
|
||||
Assert.IsTrue(list.Equals((object) list));
|
||||
Assert.IsFalse(list.Equals((object) new RepeatedField<string> { "first", "third" }));
|
||||
Assert.IsFalse(list.Equals((object) new RepeatedField<string> { "first" }));
|
||||
Assert.IsTrue(list.Equals((object) new RepeatedField<string> { "first", "second" }));
|
||||
Assert.IsFalse(list.Equals(new object()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetEnumerator_GenericInterface()
|
||||
{
|
||||
IEnumerable<string> list = new RepeatedField<string> { "first", "second" };
|
||||
// Select gets rid of the optimizations in ToList...
|
||||
CollectionAssert.AreEqual(new[] { "first", "second" }, list.Select(x => x).ToList());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetEnumerator_NonGenericInterface()
|
||||
{
|
||||
IEnumerable list = new RepeatedField<string> { "first", "second" };
|
||||
CollectionAssert.AreEqual(new[] { "first", "second" }, list.Cast<object>().ToList());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyTo()
|
||||
{
|
||||
var list = new RepeatedField<string> { "first", "second" };
|
||||
string[] stringArray = new string[4];
|
||||
list.CopyTo(stringArray, 1);
|
||||
CollectionAssert.AreEqual(new[] { null, "first", "second", null }, stringArray);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Indexer_Get()
|
||||
{
|
||||
var list = new RepeatedField<string> { "first", "second" };
|
||||
Assert.AreEqual("first", list[0]);
|
||||
Assert.AreEqual("second", list[1]);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => list[-1].GetHashCode());
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => list[2].GetHashCode());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Indexer_Set()
|
||||
{
|
||||
var list = new RepeatedField<string> { "first", "second" };
|
||||
list[0] = "changed";
|
||||
Assert.AreEqual("changed", list[0]);
|
||||
Assert.Throws<ArgumentNullException>(() => list[0] = null);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => list[-1] = "bad");
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => list[2] = "bad");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Freeze_FreezesElements()
|
||||
{
|
||||
@ -124,6 +235,27 @@ namespace Google.Protobuf.Collections
|
||||
clone[0] = 1;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Enumerator()
|
||||
{
|
||||
var list = new RepeatedField<string> { "first", "second" };
|
||||
using (var enumerator = list.GetEnumerator())
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.AreEqual("first", enumerator.Current);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.AreEqual("second", enumerator.Current);
|
||||
Assert.IsFalse(enumerator.MoveNext());
|
||||
Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
|
||||
Assert.IsFalse(enumerator.MoveNext());
|
||||
enumerator.Reset();
|
||||
Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.AreEqual("first", enumerator.Current);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddEntriesFrom_PackedInt32()
|
||||
{
|
||||
@ -309,6 +441,42 @@ namespace Google.Protobuf.Collections
|
||||
Assert.IsTrue(input.IsAtEnd);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CalculateSize_VariableSizeNonPacked()
|
||||
{
|
||||
var list = new RepeatedField<int> { 1, 500, 1 };
|
||||
var tag = WireFormat.MakeTag(1, WireFormat.WireType.Varint);
|
||||
// 2 bytes for the first entry, 3 bytes for the second, 2 bytes for the third
|
||||
Assert.AreEqual(7, list.CalculateSize(FieldCodec.ForInt32(tag)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CalculateSize_FixedSizeNonPacked()
|
||||
{
|
||||
var list = new RepeatedField<int> { 1, 500, 1 };
|
||||
var tag = WireFormat.MakeTag(1, WireFormat.WireType.Fixed32);
|
||||
// 5 bytes for the each entry
|
||||
Assert.AreEqual(15, list.CalculateSize(FieldCodec.ForSFixed32(tag)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CalculateSize_VariableSizePacked()
|
||||
{
|
||||
var list = new RepeatedField<int> { 1, 500, 1};
|
||||
var tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
|
||||
// 1 byte for the tag, 1 byte for the length,
|
||||
// 1 byte for the first entry, 2 bytes for the second, 1 byte for the third
|
||||
Assert.AreEqual(6, list.CalculateSize(FieldCodec.ForInt32(tag)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CalculateSize_FixedSizePacked()
|
||||
{
|
||||
var list = new RepeatedField<int> { 1, 500, 1 };
|
||||
var tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
|
||||
// 1 byte for the tag, 1 byte for the length, 4 bytes per entry
|
||||
Assert.AreEqual(14, list.CalculateSize(FieldCodec.ForSFixed32(tag)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNegativeEnumArray()
|
||||
@ -378,5 +546,100 @@ namespace Google.Protobuf.Collections
|
||||
Assert.AreEqual(((SampleEnum)(-4)), values[4]);
|
||||
Assert.AreEqual(((SampleEnum)(-5)), values[5]);
|
||||
}
|
||||
|
||||
// Fairly perfunctory tests for the non-generic IList implementation
|
||||
[Test]
|
||||
public void IList_Indexer()
|
||||
{
|
||||
var field = new RepeatedField<string> { "first", "second" };
|
||||
IList list = field;
|
||||
Assert.AreEqual("first", list[0]);
|
||||
list[1] = "changed";
|
||||
Assert.AreEqual("changed", field[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IList_Contains()
|
||||
{
|
||||
IList list = new RepeatedField<string> { "first", "second" };
|
||||
Assert.IsTrue(list.Contains("second"));
|
||||
Assert.IsFalse(list.Contains("third"));
|
||||
Assert.IsFalse(list.Contains(new object()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IList_Add()
|
||||
{
|
||||
IList list = new RepeatedField<string> { "first", "second" };
|
||||
list.Add("third");
|
||||
CollectionAssert.AreEqual(new[] { "first", "second", "third" }, list);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IList_Remove()
|
||||
{
|
||||
IList list = new RepeatedField<string> { "first", "second" };
|
||||
list.Remove("third"); // No-op, no exception
|
||||
list.Remove(new object()); // No-op, no exception
|
||||
list.Remove("first");
|
||||
CollectionAssert.AreEqual(new[] { "second" }, list);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IList_IsFixedSize()
|
||||
{
|
||||
var field = new RepeatedField<string> { "first", "second" };
|
||||
IList list = field;
|
||||
Assert.IsFalse(list.IsFixedSize);
|
||||
field.Freeze();
|
||||
Assert.IsTrue(list.IsFixedSize);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IList_IndexOf()
|
||||
{
|
||||
IList list = new RepeatedField<string> { "first", "second" };
|
||||
Assert.AreEqual(1, list.IndexOf("second"));
|
||||
Assert.AreEqual(-1, list.IndexOf("third"));
|
||||
Assert.AreEqual(-1, list.IndexOf(new object()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IList_SyncRoot()
|
||||
{
|
||||
IList list = new RepeatedField<string> { "first", "second" };
|
||||
Assert.AreSame(list, list.SyncRoot);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IList_CopyTo()
|
||||
{
|
||||
IList list = new RepeatedField<string> { "first", "second" };
|
||||
string[] stringArray = new string[4];
|
||||
list.CopyTo(stringArray, 1);
|
||||
CollectionAssert.AreEqual(new[] { null, "first", "second", null }, stringArray);
|
||||
|
||||
object[] objectArray = new object[4];
|
||||
list.CopyTo(objectArray, 1);
|
||||
CollectionAssert.AreEqual(new[] { null, "first", "second", null }, objectArray);
|
||||
|
||||
Assert.Throws<ArrayTypeMismatchException>(() => list.CopyTo(new StringBuilder[4], 1));
|
||||
Assert.Throws<ArrayTypeMismatchException>(() => list.CopyTo(new int[4], 1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IList_IsSynchronized()
|
||||
{
|
||||
IList list = new RepeatedField<string> { "first", "second" };
|
||||
Assert.IsFalse(list.IsSynchronized);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IList_Insert()
|
||||
{
|
||||
IList list = new RepeatedField<string> { "first", "second" };
|
||||
list.Insert(1, "middle");
|
||||
CollectionAssert.AreEqual(new[] { "first", "middle", "second" }, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,8 @@
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using Google.Protobuf.DescriptorProtos;
|
||||
using Google.Protobuf.Descriptors;
|
||||
using Google.Protobuf.TestProtos;
|
||||
using NUnit.Framework;
|
||||
@ -50,7 +52,7 @@ namespace Google.Protobuf
|
||||
Assert.AreEqual("google/protobuf/unittest_proto3.proto", file.Name);
|
||||
Assert.AreEqual("protobuf_unittest", file.Package);
|
||||
|
||||
Assert.AreEqual("UnittestProto", file.Options.JavaOuterClassname);
|
||||
Assert.AreEqual("UnittestProto", file.Proto.Options.JavaOuterClassname);
|
||||
Assert.AreEqual("google/protobuf/unittest_proto3.proto", file.Proto.Name);
|
||||
|
||||
// unittest.proto doesn't have any public imports, but unittest_import.proto does.
|
||||
@ -92,7 +94,7 @@ namespace Google.Protobuf
|
||||
Assert.AreEqual("protobuf_unittest.TestAllTypes", messageType.FullName);
|
||||
Assert.AreEqual(UnittestProto3.Descriptor, messageType.File);
|
||||
Assert.IsNull(messageType.ContainingType);
|
||||
Assert.IsNull(messageType.Options);
|
||||
Assert.IsNull(messageType.Proto.Options);
|
||||
|
||||
Assert.AreEqual("TestAllTypes", messageType.Name);
|
||||
|
||||
@ -143,7 +145,7 @@ namespace Google.Protobuf
|
||||
Assert.AreEqual(messageType, primitiveField.ContainingType);
|
||||
Assert.AreEqual(UnittestProto3.Descriptor, primitiveField.File);
|
||||
Assert.AreEqual(FieldType.Int32, primitiveField.FieldType);
|
||||
Assert.IsNull(primitiveField.Options);
|
||||
Assert.IsNull(primitiveField.Proto.Options);
|
||||
|
||||
Assert.AreEqual("single_nested_enum", enumField.Name);
|
||||
Assert.AreEqual(FieldType.Enum, enumField.FieldType);
|
||||
@ -177,7 +179,7 @@ namespace Google.Protobuf
|
||||
Assert.AreEqual("protobuf_unittest.ForeignEnum", enumType.FullName);
|
||||
Assert.AreEqual(UnittestProto3.Descriptor, enumType.File);
|
||||
Assert.Null(enumType.ContainingType);
|
||||
Assert.Null(enumType.Options);
|
||||
Assert.Null(enumType.Proto.Options);
|
||||
|
||||
Assert.AreEqual("NestedEnum", nestedType.Name);
|
||||
Assert.AreEqual("protobuf_unittest.TestAllTypes.NestedEnum",
|
||||
@ -197,5 +199,27 @@ namespace Google.Protobuf
|
||||
Assert.AreEqual(i, enumType.Values[i].Index);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OneofDescriptor()
|
||||
{
|
||||
OneofDescriptor descriptor = TestAllTypes.Descriptor.FindDescriptor<OneofDescriptor>("oneof_field");
|
||||
Assert.AreEqual("oneof_field", descriptor.Name);
|
||||
Assert.AreEqual("protobuf_unittest.TestAllTypes.oneof_field", descriptor.FullName);
|
||||
|
||||
var expectedFields = new[] {
|
||||
TestAllTypes.OneofBytesFieldNumber,
|
||||
TestAllTypes.OneofNestedMessageFieldNumber,
|
||||
TestAllTypes.OneofStringFieldNumber,
|
||||
TestAllTypes.OneofUint32FieldNumber }
|
||||
.Select(fieldNumber => TestAllTypes.Descriptor.FindFieldByNumber(fieldNumber))
|
||||
.ToList();
|
||||
foreach (var field in expectedFields)
|
||||
{
|
||||
Assert.AreSame(descriptor, field.ContainingOneof);
|
||||
}
|
||||
|
||||
CollectionAssert.AreEquivalent(expectedFields, descriptor.Fields);
|
||||
}
|
||||
}
|
||||
}
|
@ -45,15 +45,20 @@ namespace Google.Protobuf
|
||||
public static void AssertEquality<T>(T first, T second) where T : IEquatable<T>
|
||||
{
|
||||
Assert.IsTrue(first.Equals(second));
|
||||
Assert.IsTrue(first.Equals((object) second));
|
||||
Assert.AreEqual(first.GetHashCode(), second.GetHashCode());
|
||||
}
|
||||
|
||||
public static void AssertInequality<T>(T first, T second) where T : IEquatable<T>
|
||||
{
|
||||
Assert.IsFalse(first.Equals(second));
|
||||
Assert.IsFalse(first.Equals((object) second));
|
||||
// While this isn't a requirement, the chances of this test failing due to
|
||||
// coincidence rather than a bug are very small.
|
||||
Assert.AreNotEqual(first.GetHashCode(), second.GetHashCode());
|
||||
if (first != null && second != null)
|
||||
{
|
||||
Assert.AreNotEqual(first.GetHashCode(), second.GetHashCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,12 +86,22 @@ namespace Google.Protobuf
|
||||
codec.TestDefaultValue();
|
||||
}
|
||||
|
||||
[Test, TestCaseSource("Codecs")]
|
||||
public void FixedSize(ICodecTestData codec)
|
||||
{
|
||||
codec.TestFixedSize();
|
||||
}
|
||||
|
||||
// This is ugly, but it means we can have a non-generic interface.
|
||||
// It feels like NUnit should support this better, but I don't know
|
||||
// of any better ways right now.
|
||||
public interface ICodecTestData
|
||||
{
|
||||
void TestRoundTripRaw();
|
||||
void TestRoundTripWithTag();
|
||||
void TestCalculateSizeWithTag();
|
||||
void TestDefaultValue();
|
||||
void TestFixedSize();
|
||||
}
|
||||
|
||||
public class FieldCodecTestData<T> : ICodecTestData
|
||||
@ -169,6 +179,11 @@ namespace Google.Protobuf
|
||||
}
|
||||
}
|
||||
|
||||
public void TestFixedSize()
|
||||
{
|
||||
Assert.AreEqual(name.Contains("Fixed"), codec.FixedSize != 0);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return name;
|
||||
|
@ -29,11 +29,13 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endregion
|
||||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Google.Protobuf.TestProtos;
|
||||
using NUnit.Framework;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Google.Protobuf
|
||||
{
|
||||
@ -595,5 +597,142 @@ namespace Google.Protobuf
|
||||
Assert.AreEqual(message, message2);
|
||||
Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase);
|
||||
}
|
||||
|
||||
// TODO: Consider moving these tests to a separate reflection test - although they do require generated messages.
|
||||
|
||||
[Test]
|
||||
public void Reflection_GetValue()
|
||||
{
|
||||
var message = SampleMessages.CreateFullTestAllTypes();
|
||||
var fields = message.Fields;
|
||||
Assert.AreEqual(message.SingleBool, fields[TestAllTypes.SingleBoolFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleBytes, fields[TestAllTypes.SingleBytesFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleDouble, fields[TestAllTypes.SingleDoubleFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleFixed32, fields[TestAllTypes.SingleFixed32FieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleFixed64, fields[TestAllTypes.SingleFixed64FieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleFloat, fields[TestAllTypes.SingleFloatFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleForeignEnum, fields[TestAllTypes.SingleForeignEnumFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleForeignMessage, fields[TestAllTypes.SingleForeignMessageFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleImportEnum, fields[TestAllTypes.SingleImportEnumFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleImportMessage, fields[TestAllTypes.SingleImportMessageFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleInt32, fields[TestAllTypes.SingleInt32FieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleInt64, fields[TestAllTypes.SingleInt64FieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleNestedEnum, fields[TestAllTypes.SingleNestedEnumFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleNestedMessage, fields[TestAllTypes.SingleNestedMessageFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SinglePublicImportMessage, fields[TestAllTypes.SinglePublicImportMessageFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleSint32, fields[TestAllTypes.SingleSint32FieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleSint64, fields[TestAllTypes.SingleSint64FieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleString, fields[TestAllTypes.SingleStringFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleSfixed32, fields[TestAllTypes.SingleSfixed32FieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleSfixed64, fields[TestAllTypes.SingleSfixed64FieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleUint32, fields[TestAllTypes.SingleUint32FieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.SingleUint64, fields[TestAllTypes.SingleUint64FieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.OneofBytes, fields[TestAllTypes.OneofBytesFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.OneofString, fields[TestAllTypes.OneofStringFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.OneofNestedMessage, fields[TestAllTypes.OneofNestedMessageFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(message.OneofUint32, fields[TestAllTypes.OneofUint32FieldNumber].GetValue(message));
|
||||
|
||||
// Just one example for repeated fields - they're all just returning the list
|
||||
var list = (IList)fields[TestAllTypes.RepeatedInt32FieldNumber].GetValue(message);
|
||||
Assert.AreEqual(message.RepeatedInt32, list);
|
||||
Assert.AreEqual(message.RepeatedInt32[0], list[0]); // Just in case there was any doubt...
|
||||
|
||||
// Just a single map field, for the same reason
|
||||
var mapMessage = new TestMap { MapStringString = { { "key1", "value1" }, { "key2", "value2" } } };
|
||||
var dictionary = (IDictionary)mapMessage.Fields[TestMap.MapStringStringFieldNumber].GetValue(mapMessage);
|
||||
Assert.AreEqual(mapMessage.MapStringString, dictionary);
|
||||
Assert.AreEqual("value1", dictionary["key1"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Reflection_Clear()
|
||||
{
|
||||
var message = SampleMessages.CreateFullTestAllTypes();
|
||||
var fields = message.Fields;
|
||||
fields[TestAllTypes.SingleBoolFieldNumber].Clear(message);
|
||||
fields[TestAllTypes.SingleInt32FieldNumber].Clear(message);
|
||||
fields[TestAllTypes.SingleStringFieldNumber].Clear(message);
|
||||
fields[TestAllTypes.SingleBytesFieldNumber].Clear(message);
|
||||
fields[TestAllTypes.SingleForeignEnumFieldNumber].Clear(message);
|
||||
fields[TestAllTypes.SingleForeignMessageFieldNumber].Clear(message);
|
||||
fields[TestAllTypes.RepeatedDoubleFieldNumber].Clear(message);
|
||||
|
||||
var expected = new TestAllTypes(SampleMessages.CreateFullTestAllTypes())
|
||||
{
|
||||
SingleBool = false,
|
||||
SingleInt32 = 0,
|
||||
SingleString = "",
|
||||
SingleBytes = ByteString.Empty,
|
||||
SingleForeignEnum = 0,
|
||||
SingleForeignMessage = null,
|
||||
};
|
||||
expected.RepeatedDouble.Clear();
|
||||
|
||||
Assert.AreEqual(expected, message);
|
||||
|
||||
// Separately, maps.
|
||||
var mapMessage = new TestMap { MapStringString = { { "key1", "value1" }, { "key2", "value2" } } };
|
||||
mapMessage.Fields[TestMap.MapStringStringFieldNumber].Clear(mapMessage);
|
||||
Assert.AreEqual(0, mapMessage.MapStringString.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Reflection_SetValue_SingleFields()
|
||||
{
|
||||
// Just a sample (primitives, messages, enums, strings, byte strings)
|
||||
var message = SampleMessages.CreateFullTestAllTypes();
|
||||
var fields = message.Fields;
|
||||
fields[TestAllTypes.SingleBoolFieldNumber].SetValue(message, false);
|
||||
fields[TestAllTypes.SingleInt32FieldNumber].SetValue(message, 500);
|
||||
fields[TestAllTypes.SingleStringFieldNumber].SetValue(message, "It's a string");
|
||||
fields[TestAllTypes.SingleBytesFieldNumber].SetValue(message, ByteString.CopyFrom(99, 98, 97));
|
||||
fields[TestAllTypes.SingleForeignEnumFieldNumber].SetValue(message, ForeignEnum.FOREIGN_FOO);
|
||||
fields[TestAllTypes.SingleForeignMessageFieldNumber].SetValue(message, new ForeignMessage { C = 12345 });
|
||||
fields[TestAllTypes.SingleDoubleFieldNumber].SetValue(message, 20150701.5);
|
||||
|
||||
var expected = new TestAllTypes(SampleMessages.CreateFullTestAllTypes())
|
||||
{
|
||||
SingleBool = false,
|
||||
SingleInt32 = 500,
|
||||
SingleString = "It's a string",
|
||||
SingleBytes = ByteString.CopyFrom(99, 98, 97),
|
||||
SingleForeignEnum = ForeignEnum.FOREIGN_FOO,
|
||||
SingleForeignMessage = new ForeignMessage { C = 12345 },
|
||||
SingleDouble = 20150701.5
|
||||
};
|
||||
|
||||
Assert.AreEqual(expected, message);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Reflection_SetValue_SingleFields_WrongType()
|
||||
{
|
||||
var message = SampleMessages.CreateFullTestAllTypes();
|
||||
var fields = message.Fields;
|
||||
Assert.Throws<InvalidCastException>(() => fields[TestAllTypes.SingleBoolFieldNumber].SetValue(message, "This isn't a bool"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Reflection_SetValue_MapFields()
|
||||
{
|
||||
var message = new TestMap();
|
||||
var fields = message.Fields;
|
||||
Assert.Throws<InvalidOperationException>(() => fields[TestMap.MapStringStringFieldNumber].SetValue(message, new Dictionary<string, string>()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Reflection_SetValue_RepeatedFields()
|
||||
{
|
||||
var message = SampleMessages.CreateFullTestAllTypes();
|
||||
var fields = message.Fields;
|
||||
Assert.Throws<InvalidOperationException>(() => fields[TestAllTypes.RepeatedDoubleFieldNumber].SetValue(message, new double[10]));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Reflection_GetValue_IncorrectType()
|
||||
{
|
||||
var message = SampleMessages.CreateFullTestAllTypes();
|
||||
Assert.Throws<InvalidCastException>(() => message.Fields[TestAllTypes.SingleBoolFieldNumber].GetValue(new TestMap()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,8 +13,7 @@ namespace Google.Protobuf.TestProtos {
|
||||
public static partial class UnittestImportProto3 {
|
||||
|
||||
#region Static variables
|
||||
internal static pbd::MessageDescriptor internal__static_protobuf_unittest_import_ImportMessage__Descriptor;
|
||||
internal static pb::FieldAccess.FieldAccessorTable<global::Google.Protobuf.TestProtos.ImportMessage> internal__static_protobuf_unittest_import_ImportMessage__FieldAccessorTable;
|
||||
internal static pb::FieldAccess.FieldAccessorTable internal__static_protobuf_unittest_import_ImportMessage__FieldAccessorTable;
|
||||
#endregion
|
||||
#region Descriptor
|
||||
public static pbd::FileDescriptor Descriptor {
|
||||
@ -33,17 +32,13 @@ namespace Google.Protobuf.TestProtos {
|
||||
"UhAIEg4KCklNUE9SVF9CQVoQCUI8Chhjb20uZ29vZ2xlLnByb3RvYnVmLnRl",
|
||||
"c3RIAfgBAaoCGkdvb2dsZS5Qcm90b2J1Zi5UZXN0UHJvdG9zUABiBnByb3Rv",
|
||||
"Mw=="));
|
||||
pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
|
||||
descriptor = root;
|
||||
internal__static_protobuf_unittest_import_ImportMessage__Descriptor = Descriptor.MessageTypes[0];
|
||||
internal__static_protobuf_unittest_import_ImportMessage__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable<global::Google.Protobuf.TestProtos.ImportMessage>(internal__static_protobuf_unittest_import_ImportMessage__Descriptor,
|
||||
new string[] { "D", });
|
||||
};
|
||||
pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
|
||||
descriptor = pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
|
||||
new pbd::FileDescriptor[] {
|
||||
global::Google.Protobuf.TestProtos.UnittestImportPublicProto3.Descriptor,
|
||||
}, assigner);
|
||||
});
|
||||
internal__static_protobuf_unittest_import_ImportMessage__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable(typeof(global::Google.Protobuf.TestProtos.ImportMessage), descriptor.MessageTypes[0],
|
||||
new string[] { "D", });
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -67,19 +62,23 @@ namespace Google.Protobuf.TestProtos {
|
||||
private static readonly string[] _fieldNames = new string[] { "d" };
|
||||
private static readonly uint[] _fieldTags = new uint[] { 8 };
|
||||
public static pbd::MessageDescriptor Descriptor {
|
||||
get { return global::Google.Protobuf.TestProtos.UnittestImportProto3.internal__static_protobuf_unittest_import_ImportMessage__Descriptor; }
|
||||
get { return global::Google.Protobuf.TestProtos.UnittestImportProto3.Descriptor.MessageTypes[0]; }
|
||||
}
|
||||
|
||||
public pb::FieldAccess.FieldAccessorTable<ImportMessage> Fields {
|
||||
public pb::FieldAccess.FieldAccessorTable Fields {
|
||||
get { return global::Google.Protobuf.TestProtos.UnittestImportProto3.internal__static_protobuf_unittest_import_ImportMessage__FieldAccessorTable; }
|
||||
}
|
||||
|
||||
private bool _frozen = false;
|
||||
public bool IsFrozen { get { return _frozen; } }
|
||||
|
||||
public ImportMessage() { }
|
||||
public ImportMessage() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
public ImportMessage(ImportMessage other) {
|
||||
partial void OnConstruction();
|
||||
|
||||
public ImportMessage(ImportMessage other) : this() {
|
||||
d_ = other.d_;
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,7 @@ namespace Google.Protobuf.TestProtos {
|
||||
public static partial class UnittestImportPublicProto3 {
|
||||
|
||||
#region Static variables
|
||||
internal static pbd::MessageDescriptor internal__static_protobuf_unittest_import_PublicImportMessage__Descriptor;
|
||||
internal static pb::FieldAccess.FieldAccessorTable<global::Google.Protobuf.TestProtos.PublicImportMessage> internal__static_protobuf_unittest_import_PublicImportMessage__FieldAccessorTable;
|
||||
internal static pb::FieldAccess.FieldAccessorTable internal__static_protobuf_unittest_import_PublicImportMessage__FieldAccessorTable;
|
||||
#endregion
|
||||
#region Descriptor
|
||||
public static pbd::FileDescriptor Descriptor {
|
||||
@ -29,16 +28,12 @@ namespace Google.Protobuf.TestProtos {
|
||||
"bzMucHJvdG8SGHByb3RvYnVmX3VuaXR0ZXN0X2ltcG9ydCIgChNQdWJsaWNJ",
|
||||
"bXBvcnRNZXNzYWdlEgkKAWUYASABKAVCNwoYY29tLmdvb2dsZS5wcm90b2J1",
|
||||
"Zi50ZXN0qgIaR29vZ2xlLlByb3RvYnVmLlRlc3RQcm90b3NiBnByb3RvMw=="));
|
||||
pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
|
||||
descriptor = root;
|
||||
internal__static_protobuf_unittest_import_PublicImportMessage__Descriptor = Descriptor.MessageTypes[0];
|
||||
internal__static_protobuf_unittest_import_PublicImportMessage__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable<global::Google.Protobuf.TestProtos.PublicImportMessage>(internal__static_protobuf_unittest_import_PublicImportMessage__Descriptor,
|
||||
new string[] { "E", });
|
||||
};
|
||||
pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
|
||||
descriptor = pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
|
||||
new pbd::FileDescriptor[] {
|
||||
}, assigner);
|
||||
});
|
||||
internal__static_protobuf_unittest_import_PublicImportMessage__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable(typeof(global::Google.Protobuf.TestProtos.PublicImportMessage), descriptor.MessageTypes[0],
|
||||
new string[] { "E", });
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -52,19 +47,23 @@ namespace Google.Protobuf.TestProtos {
|
||||
private static readonly string[] _fieldNames = new string[] { "e" };
|
||||
private static readonly uint[] _fieldTags = new uint[] { 8 };
|
||||
public static pbd::MessageDescriptor Descriptor {
|
||||
get { return global::Google.Protobuf.TestProtos.UnittestImportPublicProto3.internal__static_protobuf_unittest_import_PublicImportMessage__Descriptor; }
|
||||
get { return global::Google.Protobuf.TestProtos.UnittestImportPublicProto3.Descriptor.MessageTypes[0]; }
|
||||
}
|
||||
|
||||
public pb::FieldAccess.FieldAccessorTable<PublicImportMessage> Fields {
|
||||
public pb::FieldAccess.FieldAccessorTable Fields {
|
||||
get { return global::Google.Protobuf.TestProtos.UnittestImportPublicProto3.internal__static_protobuf_unittest_import_PublicImportMessage__FieldAccessorTable; }
|
||||
}
|
||||
|
||||
private bool _frozen = false;
|
||||
public bool IsFrozen { get { return _frozen; } }
|
||||
|
||||
public PublicImportMessage() { }
|
||||
public PublicImportMessage() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
public PublicImportMessage(PublicImportMessage other) {
|
||||
partial void OnConstruction();
|
||||
|
||||
public PublicImportMessage(PublicImportMessage other) : this() {
|
||||
e_ = other.e_;
|
||||
}
|
||||
|
||||
|
@ -13,20 +13,13 @@ namespace UnitTest.Issues.TestProtos {
|
||||
public static partial class UnittestIssues {
|
||||
|
||||
#region Static variables
|
||||
internal static pbd::MessageDescriptor internal__static_unittest_issues_Issue307__Descriptor;
|
||||
internal static pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.Issue307> internal__static_unittest_issues_Issue307__FieldAccessorTable;
|
||||
internal static pbd::MessageDescriptor internal__static_unittest_issues_Issue307_NestedOnce__Descriptor;
|
||||
internal static pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce> internal__static_unittest_issues_Issue307_NestedOnce__FieldAccessorTable;
|
||||
internal static pbd::MessageDescriptor internal__static_unittest_issues_Issue307_NestedOnce_NestedTwice__Descriptor;
|
||||
internal static pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Types.NestedTwice> internal__static_unittest_issues_Issue307_NestedOnce_NestedTwice__FieldAccessorTable;
|
||||
internal static pbd::MessageDescriptor internal__static_unittest_issues_NegativeEnumMessage__Descriptor;
|
||||
internal static pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.NegativeEnumMessage> internal__static_unittest_issues_NegativeEnumMessage__FieldAccessorTable;
|
||||
internal static pbd::MessageDescriptor internal__static_unittest_issues_DeprecatedChild__Descriptor;
|
||||
internal static pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.DeprecatedChild> internal__static_unittest_issues_DeprecatedChild__FieldAccessorTable;
|
||||
internal static pbd::MessageDescriptor internal__static_unittest_issues_DeprecatedFieldsMessage__Descriptor;
|
||||
internal static pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.DeprecatedFieldsMessage> internal__static_unittest_issues_DeprecatedFieldsMessage__FieldAccessorTable;
|
||||
internal static pbd::MessageDescriptor internal__static_unittest_issues_ItemField__Descriptor;
|
||||
internal static pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.ItemField> internal__static_unittest_issues_ItemField__FieldAccessorTable;
|
||||
internal static pb::FieldAccess.FieldAccessorTable internal__static_unittest_issues_Issue307__FieldAccessorTable;
|
||||
internal static pb::FieldAccess.FieldAccessorTable internal__static_unittest_issues_Issue307_NestedOnce__FieldAccessorTable;
|
||||
internal static pb::FieldAccess.FieldAccessorTable internal__static_unittest_issues_Issue307_NestedOnce_NestedTwice__FieldAccessorTable;
|
||||
internal static pb::FieldAccess.FieldAccessorTable internal__static_unittest_issues_NegativeEnumMessage__FieldAccessorTable;
|
||||
internal static pb::FieldAccess.FieldAccessorTable internal__static_unittest_issues_DeprecatedChild__FieldAccessorTable;
|
||||
internal static pb::FieldAccess.FieldAccessorTable internal__static_unittest_issues_DeprecatedFieldsMessage__FieldAccessorTable;
|
||||
internal static pb::FieldAccess.FieldAccessorTable internal__static_unittest_issues_ItemField__FieldAccessorTable;
|
||||
#endregion
|
||||
#region Descriptor
|
||||
public static pbd::FileDescriptor Descriptor {
|
||||
@ -55,40 +48,30 @@ namespace UnitTest.Issues.TestProtos {
|
||||
"EPv//////////wESFQoITWludXNPbmUQ////////////ASouCg5EZXByZWNh",
|
||||
"dGVkRW51bRITCg9ERVBSRUNBVEVEX1pFUk8QABIHCgNvbmUQAUIfSAGqAhpV",
|
||||
"bml0VGVzdC5Jc3N1ZXMuVGVzdFByb3Rvc2IGcHJvdG8z"));
|
||||
pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
|
||||
descriptor = root;
|
||||
internal__static_unittest_issues_Issue307__Descriptor = Descriptor.MessageTypes[0];
|
||||
internal__static_unittest_issues_Issue307__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.Issue307>(internal__static_unittest_issues_Issue307__Descriptor,
|
||||
new string[] { });
|
||||
internal__static_unittest_issues_Issue307_NestedOnce__Descriptor = internal__static_unittest_issues_Issue307__Descriptor.NestedTypes[0];
|
||||
internal__static_unittest_issues_Issue307_NestedOnce__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce>(internal__static_unittest_issues_Issue307_NestedOnce__Descriptor,
|
||||
new string[] { });
|
||||
internal__static_unittest_issues_Issue307_NestedOnce_NestedTwice__Descriptor = internal__static_unittest_issues_Issue307_NestedOnce__Descriptor.NestedTypes[0];
|
||||
internal__static_unittest_issues_Issue307_NestedOnce_NestedTwice__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Types.NestedTwice>(internal__static_unittest_issues_Issue307_NestedOnce_NestedTwice__Descriptor,
|
||||
new string[] { });
|
||||
internal__static_unittest_issues_NegativeEnumMessage__Descriptor = Descriptor.MessageTypes[1];
|
||||
internal__static_unittest_issues_NegativeEnumMessage__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.NegativeEnumMessage>(internal__static_unittest_issues_NegativeEnumMessage__Descriptor,
|
||||
new string[] { "Value", "Values", "PackedValues", });
|
||||
internal__static_unittest_issues_DeprecatedChild__Descriptor = Descriptor.MessageTypes[2];
|
||||
internal__static_unittest_issues_DeprecatedChild__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.DeprecatedChild>(internal__static_unittest_issues_DeprecatedChild__Descriptor,
|
||||
new string[] { });
|
||||
internal__static_unittest_issues_DeprecatedFieldsMessage__Descriptor = Descriptor.MessageTypes[3];
|
||||
internal__static_unittest_issues_DeprecatedFieldsMessage__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.DeprecatedFieldsMessage>(internal__static_unittest_issues_DeprecatedFieldsMessage__Descriptor,
|
||||
new string[] { "PrimitiveValue", "PrimitiveArray", "MessageValue", "MessageArray", "EnumValue", "EnumArray", });
|
||||
internal__static_unittest_issues_ItemField__Descriptor = Descriptor.MessageTypes[4];
|
||||
internal__static_unittest_issues_ItemField__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable<global::UnitTest.Issues.TestProtos.ItemField>(internal__static_unittest_issues_ItemField__Descriptor,
|
||||
new string[] { "Item", });
|
||||
};
|
||||
pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
|
||||
descriptor = pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
|
||||
new pbd::FileDescriptor[] {
|
||||
}, assigner);
|
||||
});
|
||||
internal__static_unittest_issues_Issue307__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable(typeof(global::UnitTest.Issues.TestProtos.Issue307), descriptor.MessageTypes[0],
|
||||
new string[] { });
|
||||
internal__static_unittest_issues_Issue307_NestedOnce__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable(typeof(global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce), descriptor.MessageTypes[0].NestedTypes[0],
|
||||
new string[] { });
|
||||
internal__static_unittest_issues_Issue307_NestedOnce_NestedTwice__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable(typeof(global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Types.NestedTwice), descriptor.MessageTypes[0].NestedTypes[0].NestedTypes[0],
|
||||
new string[] { });
|
||||
internal__static_unittest_issues_NegativeEnumMessage__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable(typeof(global::UnitTest.Issues.TestProtos.NegativeEnumMessage), descriptor.MessageTypes[1],
|
||||
new string[] { "Value", "Values", "PackedValues", });
|
||||
internal__static_unittest_issues_DeprecatedChild__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable(typeof(global::UnitTest.Issues.TestProtos.DeprecatedChild), descriptor.MessageTypes[2],
|
||||
new string[] { });
|
||||
internal__static_unittest_issues_DeprecatedFieldsMessage__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable(typeof(global::UnitTest.Issues.TestProtos.DeprecatedFieldsMessage), descriptor.MessageTypes[3],
|
||||
new string[] { "PrimitiveValue", "PrimitiveArray", "MessageValue", "MessageArray", "EnumValue", "EnumArray", });
|
||||
internal__static_unittest_issues_ItemField__FieldAccessorTable =
|
||||
new pb::FieldAccess.FieldAccessorTable(typeof(global::UnitTest.Issues.TestProtos.ItemField), descriptor.MessageTypes[4],
|
||||
new string[] { "Item", });
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -116,19 +99,23 @@ namespace UnitTest.Issues.TestProtos {
|
||||
private static readonly string[] _fieldNames = new string[] { };
|
||||
private static readonly uint[] _fieldTags = new uint[] { };
|
||||
public static pbd::MessageDescriptor Descriptor {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_Issue307__Descriptor; }
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.Descriptor.MessageTypes[0]; }
|
||||
}
|
||||
|
||||
public pb::FieldAccess.FieldAccessorTable<Issue307> Fields {
|
||||
public pb::FieldAccess.FieldAccessorTable Fields {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_Issue307__FieldAccessorTable; }
|
||||
}
|
||||
|
||||
private bool _frozen = false;
|
||||
public bool IsFrozen { get { return _frozen; } }
|
||||
|
||||
public Issue307() { }
|
||||
public Issue307() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
public Issue307(Issue307 other) {
|
||||
partial void OnConstruction();
|
||||
|
||||
public Issue307(Issue307 other) : this() {
|
||||
}
|
||||
|
||||
public Issue307 Clone() {
|
||||
@ -201,19 +188,23 @@ namespace UnitTest.Issues.TestProtos {
|
||||
private static readonly string[] _fieldNames = new string[] { };
|
||||
private static readonly uint[] _fieldTags = new uint[] { };
|
||||
public static pbd::MessageDescriptor Descriptor {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_Issue307_NestedOnce__Descriptor; }
|
||||
get { return global::UnitTest.Issues.TestProtos.Issue307.Descriptor.NestedTypes[0]; }
|
||||
}
|
||||
|
||||
public pb::FieldAccess.FieldAccessorTable<NestedOnce> Fields {
|
||||
public pb::FieldAccess.FieldAccessorTable Fields {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_Issue307_NestedOnce__FieldAccessorTable; }
|
||||
}
|
||||
|
||||
private bool _frozen = false;
|
||||
public bool IsFrozen { get { return _frozen; } }
|
||||
|
||||
public NestedOnce() { }
|
||||
public NestedOnce() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
public NestedOnce(NestedOnce other) {
|
||||
partial void OnConstruction();
|
||||
|
||||
public NestedOnce(NestedOnce other) : this() {
|
||||
}
|
||||
|
||||
public NestedOnce Clone() {
|
||||
@ -286,19 +277,23 @@ namespace UnitTest.Issues.TestProtos {
|
||||
private static readonly string[] _fieldNames = new string[] { };
|
||||
private static readonly uint[] _fieldTags = new uint[] { };
|
||||
public static pbd::MessageDescriptor Descriptor {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_Issue307_NestedOnce_NestedTwice__Descriptor; }
|
||||
get { return global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Descriptor.NestedTypes[0]; }
|
||||
}
|
||||
|
||||
public pb::FieldAccess.FieldAccessorTable<NestedTwice> Fields {
|
||||
public pb::FieldAccess.FieldAccessorTable Fields {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_Issue307_NestedOnce_NestedTwice__FieldAccessorTable; }
|
||||
}
|
||||
|
||||
private bool _frozen = false;
|
||||
public bool IsFrozen { get { return _frozen; } }
|
||||
|
||||
public NestedTwice() { }
|
||||
public NestedTwice() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
public NestedTwice(NestedTwice other) {
|
||||
partial void OnConstruction();
|
||||
|
||||
public NestedTwice(NestedTwice other) : this() {
|
||||
}
|
||||
|
||||
public NestedTwice Clone() {
|
||||
@ -380,19 +375,23 @@ namespace UnitTest.Issues.TestProtos {
|
||||
private static readonly string[] _fieldNames = new string[] { "packed_values", "value", "values" };
|
||||
private static readonly uint[] _fieldTags = new uint[] { 26, 8, 16 };
|
||||
public static pbd::MessageDescriptor Descriptor {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_NegativeEnumMessage__Descriptor; }
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.Descriptor.MessageTypes[1]; }
|
||||
}
|
||||
|
||||
public pb::FieldAccess.FieldAccessorTable<NegativeEnumMessage> Fields {
|
||||
public pb::FieldAccess.FieldAccessorTable Fields {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_NegativeEnumMessage__FieldAccessorTable; }
|
||||
}
|
||||
|
||||
private bool _frozen = false;
|
||||
public bool IsFrozen { get { return _frozen; } }
|
||||
|
||||
public NegativeEnumMessage() { }
|
||||
public NegativeEnumMessage() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
public NegativeEnumMessage(NegativeEnumMessage other) {
|
||||
partial void OnConstruction();
|
||||
|
||||
public NegativeEnumMessage(NegativeEnumMessage other) : this() {
|
||||
value_ = other.value_;
|
||||
values_ = other.values_.Clone();
|
||||
packedValues_ = other.packedValues_.Clone();
|
||||
@ -529,19 +528,23 @@ namespace UnitTest.Issues.TestProtos {
|
||||
private static readonly string[] _fieldNames = new string[] { };
|
||||
private static readonly uint[] _fieldTags = new uint[] { };
|
||||
public static pbd::MessageDescriptor Descriptor {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_DeprecatedChild__Descriptor; }
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.Descriptor.MessageTypes[2]; }
|
||||
}
|
||||
|
||||
public pb::FieldAccess.FieldAccessorTable<DeprecatedChild> Fields {
|
||||
public pb::FieldAccess.FieldAccessorTable Fields {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_DeprecatedChild__FieldAccessorTable; }
|
||||
}
|
||||
|
||||
private bool _frozen = false;
|
||||
public bool IsFrozen { get { return _frozen; } }
|
||||
|
||||
public DeprecatedChild() { }
|
||||
public DeprecatedChild() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
public DeprecatedChild(DeprecatedChild other) {
|
||||
partial void OnConstruction();
|
||||
|
||||
public DeprecatedChild(DeprecatedChild other) : this() {
|
||||
}
|
||||
|
||||
public DeprecatedChild Clone() {
|
||||
@ -613,19 +616,23 @@ namespace UnitTest.Issues.TestProtos {
|
||||
private static readonly string[] _fieldNames = new string[] { "EnumArray", "EnumValue", "MessageArray", "MessageValue", "PrimitiveArray", "PrimitiveValue" };
|
||||
private static readonly uint[] _fieldTags = new uint[] { 50, 40, 34, 26, 18, 8 };
|
||||
public static pbd::MessageDescriptor Descriptor {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_DeprecatedFieldsMessage__Descriptor; }
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.Descriptor.MessageTypes[3]; }
|
||||
}
|
||||
|
||||
public pb::FieldAccess.FieldAccessorTable<DeprecatedFieldsMessage> Fields {
|
||||
public pb::FieldAccess.FieldAccessorTable Fields {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_DeprecatedFieldsMessage__FieldAccessorTable; }
|
||||
}
|
||||
|
||||
private bool _frozen = false;
|
||||
public bool IsFrozen { get { return _frozen; } }
|
||||
|
||||
public DeprecatedFieldsMessage() { }
|
||||
public DeprecatedFieldsMessage() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
public DeprecatedFieldsMessage(DeprecatedFieldsMessage other) {
|
||||
partial void OnConstruction();
|
||||
|
||||
public DeprecatedFieldsMessage(DeprecatedFieldsMessage other) : this() {
|
||||
primitiveValue_ = other.primitiveValue_;
|
||||
primitiveArray_ = other.primitiveArray_.Clone();
|
||||
MessageValue = other.messageValue_ != null ? other.MessageValue.Clone() : null;
|
||||
@ -849,19 +856,23 @@ namespace UnitTest.Issues.TestProtos {
|
||||
private static readonly string[] _fieldNames = new string[] { "item" };
|
||||
private static readonly uint[] _fieldTags = new uint[] { 8 };
|
||||
public static pbd::MessageDescriptor Descriptor {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_ItemField__Descriptor; }
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.Descriptor.MessageTypes[4]; }
|
||||
}
|
||||
|
||||
public pb::FieldAccess.FieldAccessorTable<ItemField> Fields {
|
||||
public pb::FieldAccess.FieldAccessorTable Fields {
|
||||
get { return global::UnitTest.Issues.TestProtos.UnittestIssues.internal__static_unittest_issues_ItemField__FieldAccessorTable; }
|
||||
}
|
||||
|
||||
private bool _frozen = false;
|
||||
public bool IsFrozen { get { return _frozen; } }
|
||||
|
||||
public ItemField() { }
|
||||
public ItemField() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
public ItemField(ItemField other) {
|
||||
partial void OnConstruction();
|
||||
|
||||
public ItemField(ItemField other) : this() {
|
||||
item_ = other.item_;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -48,7 +48,7 @@ namespace Google.Protobuf.Collections
|
||||
/// </remarks>
|
||||
/// <typeparam name="TKey">Key type in the map. Must be a type supported by Protocol Buffer map keys.</typeparam>
|
||||
/// <typeparam name="TValue">Value type in the map. Must be a type supported by Protocol Buffers.</typeparam>
|
||||
public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IFreezable, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>
|
||||
public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IFreezable, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary
|
||||
{
|
||||
// TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
|
||||
private bool frozen;
|
||||
@ -64,7 +64,7 @@ namespace Google.Protobuf.Collections
|
||||
{
|
||||
foreach (var pair in list)
|
||||
{
|
||||
clone.Add(pair.Key, pair.Value == null ? pair.Value : ((IDeepCloneable<TValue>) pair.Value).Clone());
|
||||
clone.Add(pair.Key, pair.Value == null ? pair.Value : ((IDeepCloneable<TValue>)pair.Value).Clone());
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -309,7 +309,7 @@ namespace Google.Protobuf.Collections
|
||||
/// </remarks>
|
||||
/// <param name="input">Stream to read from</param>
|
||||
/// <param name="codec">Codec describing how the key/value pairs are encoded</param>
|
||||
public void AddEntriesFrom(CodedInputStream input, Codec codec)
|
||||
public void AddEntriesFrom(CodedInputStream input, Codec codec)
|
||||
{
|
||||
var adapter = new Codec.MessageAdapter(codec);
|
||||
do
|
||||
@ -318,7 +318,7 @@ namespace Google.Protobuf.Collections
|
||||
input.ReadMessage(adapter);
|
||||
this[adapter.Key] = adapter.Value;
|
||||
} while (input.MaybeConsumeTag(codec.MapTag));
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteTo(CodedOutputStream output, Codec codec)
|
||||
{
|
||||
@ -350,6 +350,104 @@ namespace Google.Protobuf.Collections
|
||||
return size;
|
||||
}
|
||||
|
||||
#region IDictionary explicit interface implementation
|
||||
void IDictionary.Add(object key, object value)
|
||||
{
|
||||
Add((TKey)key, (TValue)value);
|
||||
}
|
||||
|
||||
bool IDictionary.Contains(object key)
|
||||
{
|
||||
if (!(key is TKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return ContainsKey((TKey)key);
|
||||
}
|
||||
|
||||
IDictionaryEnumerator IDictionary.GetEnumerator()
|
||||
{
|
||||
return new DictionaryEnumerator(GetEnumerator());
|
||||
}
|
||||
|
||||
void IDictionary.Remove(object key)
|
||||
{
|
||||
ThrowHelper.ThrowIfNull(key, "key");
|
||||
this.CheckMutable();
|
||||
if (!(key is TKey))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Remove((TKey)key);
|
||||
}
|
||||
|
||||
void ICollection.CopyTo(Array array, int index)
|
||||
{
|
||||
// This is ugly and slow as heck, but with any luck it will never be used anyway.
|
||||
ICollection temp = this.Select(pair => new DictionaryEntry(pair.Key, pair.Value)).ToList();
|
||||
temp.CopyTo(array, index);
|
||||
}
|
||||
|
||||
bool IDictionary.IsFixedSize { get { return IsFrozen; } }
|
||||
|
||||
ICollection IDictionary.Keys { get { return (ICollection)Keys; } }
|
||||
|
||||
ICollection IDictionary.Values { get { return (ICollection)Values; } }
|
||||
|
||||
bool ICollection.IsSynchronized { get { return false; } }
|
||||
|
||||
object ICollection.SyncRoot { get { return this; } }
|
||||
|
||||
object IDictionary.this[object key]
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowHelper.ThrowIfNull(key, "key");
|
||||
if (!(key is TKey))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
TValue value;
|
||||
TryGetValue((TKey)key, out value);
|
||||
return value;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (frozen)
|
||||
{
|
||||
throw new NotSupportedException("Dictionary is frozen");
|
||||
}
|
||||
this[(TKey)key] = (TValue)value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private class DictionaryEnumerator : IDictionaryEnumerator
|
||||
{
|
||||
private readonly IEnumerator<KeyValuePair<TKey, TValue>> enumerator;
|
||||
|
||||
internal DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> enumerator)
|
||||
{
|
||||
this.enumerator = enumerator;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
return enumerator.MoveNext();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
enumerator.Reset();
|
||||
}
|
||||
|
||||
public object Current { get { return Entry; } }
|
||||
public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }
|
||||
public object Key { get { return enumerator.Current.Key; } }
|
||||
public object Value { get { return enumerator.Current.Value; } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A codec for a specific map field. This contains all the information required to encoded and
|
||||
/// decode the nested messages.
|
||||
|
@ -41,7 +41,7 @@ namespace Google.Protobuf.Collections
|
||||
/// restrictions (no null values) and capabilities (deep cloning and freezing).
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The element type of the repeated field.</typeparam>
|
||||
public sealed class RepeatedField<T> : IList<T>, IDeepCloneable<RepeatedField<T>>, IEquatable<RepeatedField<T>>, IFreezable
|
||||
public sealed class RepeatedField<T> : IList<T>, IList, IDeepCloneable<RepeatedField<T>>, IEquatable<RepeatedField<T>>, IFreezable
|
||||
{
|
||||
private static readonly T[] EmptyArray = new T[0];
|
||||
|
||||
@ -376,6 +376,7 @@ namespace Google.Protobuf.Collections
|
||||
this.CheckMutable();
|
||||
EnsureSize(count + 1);
|
||||
Array.Copy(array, index, array, index + 1, count - index);
|
||||
array[index] = item;
|
||||
count++;
|
||||
}
|
||||
|
||||
@ -415,7 +416,60 @@ namespace Google.Protobuf.Collections
|
||||
array[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Explicit interface implementation for IList and ICollection.
|
||||
bool IList.IsFixedSize { get { return IsFrozen; } }
|
||||
|
||||
void ICollection.CopyTo(Array array, int index)
|
||||
{
|
||||
Array.Copy(this.array, 0, array, index, count);
|
||||
}
|
||||
|
||||
bool ICollection.IsSynchronized { get { return false; } }
|
||||
|
||||
object ICollection.SyncRoot { get { return this; } }
|
||||
|
||||
object IList.this[int index]
|
||||
{
|
||||
get { return this[index]; }
|
||||
set { this[index] = (T)value; }
|
||||
}
|
||||
|
||||
int IList.Add(object value)
|
||||
{
|
||||
Add((T) value);
|
||||
return count - 1;
|
||||
}
|
||||
|
||||
bool IList.Contains(object value)
|
||||
{
|
||||
return (value is T && Contains((T)value));
|
||||
}
|
||||
|
||||
int IList.IndexOf(object value)
|
||||
{
|
||||
if (!(value is T))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return IndexOf((T)value);
|
||||
}
|
||||
|
||||
void IList.Insert(int index, object value)
|
||||
{
|
||||
Insert(index, (T) value);
|
||||
}
|
||||
|
||||
void IList.Remove(object value)
|
||||
{
|
||||
if (!(value is T))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Remove((T)value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public struct Enumerator : IEnumerator<T>
|
||||
{
|
||||
private int index;
|
||||
@ -431,6 +485,7 @@ namespace Google.Protobuf.Collections
|
||||
{
|
||||
if (index + 1 >= field.Count)
|
||||
{
|
||||
index = field.Count;
|
||||
return false;
|
||||
}
|
||||
index++;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,36 +30,18 @@
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endregion
|
||||
|
||||
// This file just contains partial classes for each of the
|
||||
// autogenerated classes, so that they implement
|
||||
// IDescriptorProto
|
||||
// This file just contains partial classes for any autogenerated classes that need additional support.
|
||||
namespace Google.Protobuf.DescriptorProtos
|
||||
{
|
||||
public partial class DescriptorProto : IDescriptorProto<MessageOptions>
|
||||
{
|
||||
}
|
||||
|
||||
public partial class EnumDescriptorProto : IDescriptorProto<EnumOptions>
|
||||
{
|
||||
}
|
||||
|
||||
public partial class EnumValueDescriptorProto : IDescriptorProto<EnumValueOptions>
|
||||
{
|
||||
}
|
||||
|
||||
public partial class FieldDescriptorProto : IDescriptorProto<FieldOptions>
|
||||
{
|
||||
}
|
||||
|
||||
public partial class FileDescriptorProto : IDescriptorProto<FileOptions>
|
||||
{
|
||||
}
|
||||
|
||||
public partial class MethodDescriptorProto : IDescriptorProto<MethodOptions>
|
||||
{
|
||||
}
|
||||
|
||||
public partial class ServiceDescriptorProto : IDescriptorProto<ServiceOptions>
|
||||
internal partial class FieldDescriptorProto
|
||||
{
|
||||
// We can't tell the difference between "explicitly set to 0" and "not set"
|
||||
// in proto3, but we need to tell the difference for OneofIndex. descriptor.proto
|
||||
// is really a proto2 file, but the runtime doesn't know about proto2 semantics...
|
||||
// We fake it by defaulting to -1.
|
||||
partial void OnConstruction()
|
||||
{
|
||||
OneofIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
@ -34,61 +34,36 @@ using Google.Protobuf.DescriptorProtos;
|
||||
|
||||
namespace Google.Protobuf.Descriptors
|
||||
{
|
||||
// TODO(jonskeet): The descriptor type hierarchy needs changing so that we can hide the descriptor protos.
|
||||
/// <summary>
|
||||
/// Base class for nearly all descriptors, providing common functionality.
|
||||
/// </summary>
|
||||
/// <typeparam name="TProto">Type of the protocol buffer form of this descriptor</typeparam>
|
||||
/// <typeparam name="TOptions">Type of the options protocol buffer for this descriptor</typeparam>
|
||||
public abstract class DescriptorBase<TProto, TOptions> : IDescriptor<TProto>
|
||||
where TProto : IMessage, IDescriptorProto<TOptions>
|
||||
public abstract class DescriptorBase : IDescriptor
|
||||
{
|
||||
private TProto proto;
|
||||
private readonly FileDescriptor file;
|
||||
private readonly string fullName;
|
||||
private readonly int index;
|
||||
|
||||
protected DescriptorBase(TProto proto, FileDescriptor file, string fullName)
|
||||
internal DescriptorBase(FileDescriptor file, string fullName, int index)
|
||||
{
|
||||
this.proto = proto;
|
||||
this.file = file;
|
||||
this.fullName = fullName;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
internal virtual void ReplaceProto(TProto newProto)
|
||||
/// <value>
|
||||
/// The index of this descriptor within its parent descriptor.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This returns the index of this descriptor within its parent, for
|
||||
/// this descriptor's type. (There can be duplicate values for different
|
||||
/// types, e.g. one enum type with index 0 and one message type with index 0.)
|
||||
/// </remarks>
|
||||
public int Index
|
||||
{
|
||||
this.proto = newProto;
|
||||
get { return index; }
|
||||
}
|
||||
|
||||
protected static string ComputeFullName(FileDescriptor file, MessageDescriptor parent, string name)
|
||||
{
|
||||
if (parent != null)
|
||||
{
|
||||
return parent.FullName + "." + name;
|
||||
}
|
||||
if (file.Package.Length > 0)
|
||||
{
|
||||
return file.Package + "." + name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
IMessage IDescriptor.Proto
|
||||
{
|
||||
get { return proto; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the protocol buffer form of this descriptor.
|
||||
/// </summary>
|
||||
public TProto Proto
|
||||
{
|
||||
get { return proto; }
|
||||
}
|
||||
|
||||
public TOptions Options
|
||||
{
|
||||
get { return proto.Options; }
|
||||
}
|
||||
public abstract string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The fully qualified name of the descriptor's target.
|
||||
@ -98,14 +73,6 @@ namespace Google.Protobuf.Descriptors
|
||||
get { return fullName; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The brief name of the descriptor's target.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return proto.Name; }
|
||||
}
|
||||
|
||||
/// <value>
|
||||
/// The file this descriptor was declared in.
|
||||
/// </value>
|
||||
|
@ -257,7 +257,7 @@ namespace Google.Protobuf.Descriptors
|
||||
/// or unqualified. C++-like name lookup semantics are used to search for the
|
||||
/// matching descriptor.
|
||||
/// </summary>
|
||||
public IDescriptor LookupSymbol(string name, IDescriptor relativeTo)
|
||||
internal IDescriptor LookupSymbol(string name, IDescriptor relativeTo)
|
||||
{
|
||||
// TODO(jonskeet): This could be optimized in a number of ways.
|
||||
|
||||
|
@ -38,14 +38,16 @@ namespace Google.Protobuf.Descriptors
|
||||
/// <summary>
|
||||
/// Descriptor for an enum type in a .proto file.
|
||||
/// </summary>
|
||||
public sealed class EnumDescriptor : IndexedDescriptorBase<EnumDescriptorProto, EnumOptions>
|
||||
public sealed class EnumDescriptor : DescriptorBase
|
||||
{
|
||||
private readonly EnumDescriptorProto proto;
|
||||
private readonly MessageDescriptor containingType;
|
||||
private readonly IList<EnumValueDescriptor> values;
|
||||
|
||||
internal EnumDescriptor(EnumDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index)
|
||||
: base(proto, file, ComputeFullName(file, parent, proto.Name), index)
|
||||
: base(file, file.ComputeFullName(parent, proto.Name), index)
|
||||
{
|
||||
this.proto = proto;
|
||||
containingType = parent;
|
||||
|
||||
if (proto.Value.Count == 0)
|
||||
@ -61,6 +63,13 @@ namespace Google.Protobuf.Descriptors
|
||||
File.DescriptorPool.AddSymbol(this);
|
||||
}
|
||||
|
||||
internal EnumDescriptorProto Proto { get { return proto; } }
|
||||
|
||||
/// <summary>
|
||||
/// The brief name of the descriptor's target.
|
||||
/// </summary>
|
||||
public override string Name { get { return proto.Name; } }
|
||||
|
||||
/// <value>
|
||||
/// If this is a nested type, get the outer descriptor, otherwise null.
|
||||
/// </value>
|
||||
@ -95,14 +104,5 @@ namespace Google.Protobuf.Descriptors
|
||||
{
|
||||
return File.DescriptorPool.FindSymbol<EnumValueDescriptor>(FullName + "." + name);
|
||||
}
|
||||
|
||||
internal override void ReplaceProto(EnumDescriptorProto newProto)
|
||||
{
|
||||
base.ReplaceProto(newProto);
|
||||
for (int i = 0; i < values.Count; i++)
|
||||
{
|
||||
values[i].ReplaceProto(newProto.Value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -37,27 +37,27 @@ namespace Google.Protobuf.Descriptors
|
||||
/// <summary>
|
||||
/// Descriptor for a single enum value within an enum in a .proto file.
|
||||
/// </summary>
|
||||
public sealed class EnumValueDescriptor : IndexedDescriptorBase<EnumValueDescriptorProto, EnumValueOptions>
|
||||
public sealed class EnumValueDescriptor : DescriptorBase
|
||||
{
|
||||
private readonly EnumDescriptor enumDescriptor;
|
||||
private readonly EnumValueDescriptorProto proto;
|
||||
|
||||
internal EnumValueDescriptor(EnumValueDescriptorProto proto, FileDescriptor file,
|
||||
EnumDescriptor parent, int index)
|
||||
: base(proto, file, parent.FullName + "." + proto.Name, index)
|
||||
: base(file, parent.FullName + "." + proto.Name, index)
|
||||
{
|
||||
this.proto = proto;
|
||||
enumDescriptor = parent;
|
||||
file.DescriptorPool.AddSymbol(this);
|
||||
file.DescriptorPool.AddEnumValueByNumber(this);
|
||||
}
|
||||
|
||||
public int Number
|
||||
{
|
||||
get { return Proto.Number; }
|
||||
}
|
||||
internal EnumValueDescriptorProto Proto { get { return proto; } }
|
||||
|
||||
public override string Name { get { return proto.Name; } }
|
||||
|
||||
public EnumDescriptor EnumDescriptor
|
||||
{
|
||||
get { return enumDescriptor; }
|
||||
}
|
||||
public int Number { get { return Proto.Number; } }
|
||||
|
||||
public EnumDescriptor EnumDescriptor { get { return enumDescriptor; } }
|
||||
}
|
||||
}
|
@ -38,21 +38,20 @@ namespace Google.Protobuf.Descriptors
|
||||
/// <summary>
|
||||
/// Descriptor for a field or extension within a message in a .proto file.
|
||||
/// </summary>
|
||||
public sealed class FieldDescriptor : IndexedDescriptorBase<FieldDescriptorProto, FieldOptions>,
|
||||
IComparable<FieldDescriptor>
|
||||
public sealed class FieldDescriptor : DescriptorBase, IComparable<FieldDescriptor>
|
||||
{
|
||||
private readonly FieldDescriptorProto proto;
|
||||
private EnumDescriptor enumType;
|
||||
private MessageDescriptor messageType;
|
||||
private MessageDescriptor containingType;
|
||||
private OneofDescriptor containingOneof;
|
||||
private readonly MessageDescriptor containingType;
|
||||
private readonly OneofDescriptor containingOneof;
|
||||
private FieldType fieldType;
|
||||
|
||||
private readonly object optionsLock = new object();
|
||||
|
||||
internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
|
||||
MessageDescriptor parent, int index)
|
||||
: base(proto, file, ComputeFullName(file, parent, proto.Name), index)
|
||||
: base(file, file.ComputeFullName(parent, proto.Name), index)
|
||||
{
|
||||
this.proto = proto;
|
||||
if (proto.Type != 0)
|
||||
{
|
||||
fieldType = GetFieldTypeFromProtoType(proto.Type);
|
||||
@ -64,7 +63,8 @@ namespace Google.Protobuf.Descriptors
|
||||
"Field numbers must be positive integers.");
|
||||
}
|
||||
containingType = parent;
|
||||
if (proto.OneofIndex != 0)
|
||||
// OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnConstruction.
|
||||
if (proto.OneofIndex != -1)
|
||||
{
|
||||
if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.OneofDecl.Count)
|
||||
{
|
||||
@ -72,12 +72,18 @@ namespace Google.Protobuf.Descriptors
|
||||
"FieldDescriptorProto.oneof_index is out of range for type " + parent.Name);
|
||||
}
|
||||
containingOneof = parent.Oneofs[proto.OneofIndex];
|
||||
containingOneof.fieldCount ++;
|
||||
}
|
||||
|
||||
file.DescriptorPool.AddSymbol(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The brief name of the descriptor's target.
|
||||
/// </summary>
|
||||
public override string Name { get { return proto.Name; } }
|
||||
|
||||
internal FieldDescriptorProto Proto { get { return proto; } }
|
||||
|
||||
/// <summary>
|
||||
/// Maps a field type as included in the .proto file to a FieldType.
|
||||
/// </summary>
|
||||
@ -131,9 +137,14 @@ namespace Google.Protobuf.Descriptors
|
||||
get { return Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REPEATED; }
|
||||
}
|
||||
|
||||
public bool IsMap
|
||||
{
|
||||
get { return fieldType == FieldType.Message && messageType.Proto.Options != null && messageType.Proto.Options.MapEntry; }
|
||||
}
|
||||
|
||||
public bool IsPacked
|
||||
{
|
||||
get { return Proto.Options.Packed; }
|
||||
get { return Proto.Options != null && Proto.Options.Packed; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -273,7 +284,7 @@ namespace Google.Protobuf.Descriptors
|
||||
|
||||
File.DescriptorPool.AddFieldByNumber(this);
|
||||
|
||||
if (containingType != null && containingType.Options != null && containingType.Options.MessageSetWireFormat)
|
||||
if (containingType != null && containingType.Proto.Options != null && containingType.Proto.Options.MessageSetWireFormat)
|
||||
{
|
||||
throw new DescriptorValidationException(this, "MessageSet format is not supported.");
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ namespace Google.Protobuf.Descriptors
|
||||
/// IDescriptor is implemented such that the File property returns this descriptor,
|
||||
/// and the FullName is the same as the Name.
|
||||
/// </summary>
|
||||
public sealed class FileDescriptor : IDescriptor<FileDescriptorProto>
|
||||
public sealed class FileDescriptor : IDescriptor
|
||||
{
|
||||
private readonly FileDescriptorProto proto;
|
||||
private readonly IList<MessageDescriptor> messageTypes;
|
||||
@ -87,6 +87,22 @@ namespace Google.Protobuf.Descriptors
|
||||
new ServiceDescriptor(service, this, index));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the full name of a descriptor within this file, with an optional parent message.
|
||||
/// </summary>
|
||||
internal string ComputeFullName(MessageDescriptor parent, string name)
|
||||
{
|
||||
if (parent != null)
|
||||
{
|
||||
return parent.FullName + "." + name;
|
||||
}
|
||||
if (Package.Length > 0)
|
||||
{
|
||||
return Package + "." + name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts public dependencies from direct dependencies. This is a static method despite its
|
||||
/// first parameter, as the value we're in the middle of constructing is only used for exceptions.
|
||||
@ -127,19 +143,11 @@ namespace Google.Protobuf.Descriptors
|
||||
/// <value>
|
||||
/// The descriptor in its protocol message representation.
|
||||
/// </value>
|
||||
public FileDescriptorProto Proto
|
||||
internal FileDescriptorProto Proto
|
||||
{
|
||||
get { return proto; }
|
||||
}
|
||||
|
||||
/// <value>
|
||||
/// The <see cref="DescriptorProtos.FileOptions" /> defined in <c>descriptor.proto</c>.
|
||||
/// </value>
|
||||
public FileOptions Options
|
||||
{
|
||||
get { return proto.Options; }
|
||||
}
|
||||
|
||||
/// <value>
|
||||
/// The file name.
|
||||
/// </value>
|
||||
@ -213,14 +221,6 @@ namespace Google.Protobuf.Descriptors
|
||||
get { return this; }
|
||||
}
|
||||
|
||||
/// <value>
|
||||
/// Protocol buffer describing this descriptor.
|
||||
/// </value>
|
||||
IMessage IDescriptor.Proto
|
||||
{
|
||||
get { return Proto; }
|
||||
}
|
||||
|
||||
/// <value>
|
||||
/// Pool containing symbol descriptors.
|
||||
/// </value>
|
||||
@ -255,22 +255,7 @@ namespace Google.Protobuf.Descriptors
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds a FileDescriptor from its protocol buffer representation.
|
||||
/// </summary>
|
||||
/// <param name="proto">The protocol message form of the FileDescriptor.</param>
|
||||
/// <param name="dependencies">FileDescriptors corresponding to all of the
|
||||
/// file's dependencies, in the exact order listed in the .proto file. May be null,
|
||||
/// in which case it is treated as an empty array.</param>
|
||||
/// <exception cref="DescriptorValidationException">If <paramref name="proto"/> is not
|
||||
/// a valid descriptor. This can occur for a number of reasons, such as a field
|
||||
/// having an undefined type or because two messages were defined with the same name.</exception>
|
||||
public static FileDescriptor BuildFrom(FileDescriptorProto proto, FileDescriptor[] dependencies)
|
||||
{
|
||||
return BuildFrom(proto, dependencies, false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Builds a FileDescriptor from its protocol buffer representation.
|
||||
/// </summary>
|
||||
@ -336,33 +321,8 @@ namespace Google.Protobuf.Descriptors
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is to be called by generated code only. It is equivalent
|
||||
/// to BuildFrom except that the FileDescriptorProto is encoded in
|
||||
/// protocol buffer wire format. This overload is maintained for backward
|
||||
/// compatibility with source code generated before the custom options were available
|
||||
/// (and working).
|
||||
/// </summary>
|
||||
public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descriptorData, FileDescriptor[] dependencies)
|
||||
{
|
||||
return InternalBuildGeneratedFileFrom(descriptorData, dependencies, x => { });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This delegate should be used by generated code only. When calling
|
||||
/// FileDescriptor.InternalBuildGeneratedFileFrom, the caller can provide
|
||||
/// a callback which assigns the global variables defined in the generated code
|
||||
/// which point at parts of the FileDescriptor. The callback returns an
|
||||
/// Extension Registry which contains any extensions which might be used in
|
||||
/// the descriptor - that is, extensions of the various "Options" messages defined
|
||||
/// in descriptor.proto. The callback may also return null to indicate that
|
||||
/// no extensions are used in the descriptor.
|
||||
/// </summary>
|
||||
public delegate void InternalDescriptorAssigner(FileDescriptor descriptor);
|
||||
|
||||
public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descriptorData,
|
||||
FileDescriptor[] dependencies,
|
||||
InternalDescriptorAssigner descriptorAssigner)
|
||||
FileDescriptor[] dependencies)
|
||||
{
|
||||
FileDescriptorProto proto;
|
||||
try
|
||||
@ -374,20 +334,16 @@ namespace Google.Protobuf.Descriptors
|
||||
throw new ArgumentException("Failed to parse protocol buffer descriptor for generated code.", e);
|
||||
}
|
||||
|
||||
FileDescriptor result;
|
||||
try
|
||||
{
|
||||
// When building descriptors for generated code, we allow unknown
|
||||
// dependencies by default.
|
||||
result = BuildFrom(proto, dependencies, true);
|
||||
return BuildFrom(proto, dependencies, true);
|
||||
}
|
||||
catch (DescriptorValidationException e)
|
||||
{
|
||||
throw new ArgumentException("Invalid embedded descriptor for \"" + proto.Name + "\".", e);
|
||||
}
|
||||
|
||||
descriptorAssigner(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
@ -33,23 +33,12 @@
|
||||
namespace Google.Protobuf.Descriptors
|
||||
{
|
||||
/// <summary>
|
||||
/// The non-generic form of the IDescriptor interface. Useful for describing a general
|
||||
/// descriptor.
|
||||
/// Interface implemented by all descriptor types.
|
||||
/// </summary>
|
||||
public interface IDescriptor
|
||||
{
|
||||
string Name { get; }
|
||||
string FullName { get; }
|
||||
FileDescriptor File { get; }
|
||||
IMessage Proto { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strongly-typed form of the IDescriptor interface.
|
||||
/// </summary>
|
||||
/// <typeparam name="TProto">Protocol buffer type underlying this descriptor type</typeparam>
|
||||
internal interface IDescriptor<TProto> : IDescriptor where TProto : IMessage
|
||||
{
|
||||
new TProto Proto { get; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
#region Copyright notice and license
|
||||
// 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.
|
||||
#endregion
|
||||
|
||||
using Google.Protobuf.DescriptorProtos;
|
||||
|
||||
namespace Google.Protobuf.Descriptors
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for descriptors which are also indexed. This is all of them other than
|
||||
/// <see cref="FileDescriptor" />.
|
||||
/// </summary>
|
||||
public abstract class IndexedDescriptorBase<TProto, TOptions> : DescriptorBase<TProto, TOptions>
|
||||
where TProto : IMessage<TProto>, IDescriptorProto<TOptions>
|
||||
{
|
||||
private readonly int index;
|
||||
|
||||
protected IndexedDescriptorBase(TProto proto, FileDescriptor file, string fullName, int index)
|
||||
: base(proto, file, fullName)
|
||||
{
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/// <value>
|
||||
/// The index of this descriptor within its parent descriptor.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This returns the index of this descriptor within its parent, for
|
||||
/// this descriptor's type. (There can be duplicate values for different
|
||||
/// types, e.g. one enum type with index 0 and one message type with index 0.)
|
||||
/// </remarks>
|
||||
public int Index
|
||||
{
|
||||
get { return index; }
|
||||
}
|
||||
}
|
||||
}
|
@ -39,8 +39,9 @@ namespace Google.Protobuf.Descriptors
|
||||
/// <summary>
|
||||
/// Describes a message type.
|
||||
/// </summary>
|
||||
public sealed class MessageDescriptor : IndexedDescriptorBase<DescriptorProto, MessageOptions>
|
||||
public sealed class MessageDescriptor : DescriptorBase
|
||||
{
|
||||
private readonly DescriptorProto proto;
|
||||
private readonly MessageDescriptor containingType;
|
||||
private readonly IList<MessageDescriptor> nestedTypes;
|
||||
private readonly IList<EnumDescriptor> enumTypes;
|
||||
@ -48,8 +49,9 @@ namespace Google.Protobuf.Descriptors
|
||||
private readonly IList<OneofDescriptor> oneofs;
|
||||
|
||||
internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex)
|
||||
: base(proto, file, ComputeFullName(file, parent, proto.Name), typeIndex)
|
||||
: base(file, file.ComputeFullName(parent, proto.Name), typeIndex)
|
||||
{
|
||||
this.proto = proto;
|
||||
containingType = parent;
|
||||
|
||||
oneofs = DescriptorUtil.ConvertAndMakeReadOnly(proto.OneofDecl,
|
||||
@ -68,23 +70,16 @@ namespace Google.Protobuf.Descriptors
|
||||
fields = DescriptorUtil.ConvertAndMakeReadOnly(proto.Field,
|
||||
(field, index) =>
|
||||
new FieldDescriptor(field, file, this, index));
|
||||
|
||||
for (int i = 0; i < proto.OneofDecl.Count; i++)
|
||||
{
|
||||
oneofs[i].fields = new FieldDescriptor[oneofs[i].FieldCount];
|
||||
oneofs[i].fieldCount = 0;
|
||||
}
|
||||
for (int i = 0; i< proto.Field.Count; i++)
|
||||
{
|
||||
OneofDescriptor oneofDescriptor = fields[i].ContainingOneof;
|
||||
if (oneofDescriptor != null)
|
||||
{
|
||||
oneofDescriptor.fields[oneofDescriptor.fieldCount++] = fields[i];
|
||||
}
|
||||
}
|
||||
file.DescriptorPool.AddSymbol(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The brief name of the descriptor's target.
|
||||
/// </summary>
|
||||
public override string Name { get { return proto.Name; } }
|
||||
|
||||
internal DescriptorProto Proto { get { return proto; } }
|
||||
|
||||
/// <value>
|
||||
/// If this is a nested type, get the outer descriptor, otherwise null.
|
||||
/// </value>
|
||||
@ -144,7 +139,7 @@ namespace Google.Protobuf.Descriptors
|
||||
|
||||
/// <summary>
|
||||
/// Finds a nested descriptor by name. The is valid for fields, nested
|
||||
/// message types and enums.
|
||||
/// message types, oneofs and enums.
|
||||
/// </summary>
|
||||
/// <param name="name">The unqualified name of the descriptor, e.g. "Foo"</param>
|
||||
/// <returns>The descriptor, or null if not found.</returns>
|
||||
@ -171,32 +166,8 @@ namespace Google.Protobuf.Descriptors
|
||||
|
||||
foreach (OneofDescriptor oneof in oneofs)
|
||||
{
|
||||
// TODO(jonskeet): Do we need to do this?
|
||||
// oneof.C
|
||||
oneof.CrossLink();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See FileDescriptor.ReplaceProto
|
||||
/// </summary>
|
||||
internal override void ReplaceProto(DescriptorProto newProto)
|
||||
{
|
||||
base.ReplaceProto(newProto);
|
||||
|
||||
for (int i = 0; i < nestedTypes.Count; i++)
|
||||
{
|
||||
nestedTypes[i].ReplaceProto(newProto.NestedType[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < enumTypes.Count; i++)
|
||||
{
|
||||
enumTypes[i].ReplaceProto(newProto.EnumType[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < fields.Count; i++)
|
||||
{
|
||||
fields[i].ReplaceProto(newProto.Field[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -37,8 +37,9 @@ namespace Google.Protobuf.Descriptors
|
||||
/// <summary>
|
||||
/// Describes a single method in a service.
|
||||
/// </summary>
|
||||
public sealed class MethodDescriptor : IndexedDescriptorBase<MethodDescriptorProto, MethodOptions>
|
||||
public sealed class MethodDescriptor : DescriptorBase
|
||||
{
|
||||
private readonly MethodDescriptorProto proto;
|
||||
private readonly ServiceDescriptor service;
|
||||
private MessageDescriptor inputType;
|
||||
private MessageDescriptor outputType;
|
||||
@ -46,35 +47,34 @@ namespace Google.Protobuf.Descriptors
|
||||
/// <value>
|
||||
/// The service this method belongs to.
|
||||
/// </value>
|
||||
public ServiceDescriptor Service
|
||||
{
|
||||
get { return service; }
|
||||
}
|
||||
public ServiceDescriptor Service { get { return service; } }
|
||||
|
||||
/// <value>
|
||||
/// The method's input type.
|
||||
/// </value>
|
||||
public MessageDescriptor InputType
|
||||
{
|
||||
get { return inputType; }
|
||||
}
|
||||
public MessageDescriptor InputType { get { return inputType; } }
|
||||
|
||||
/// <value>
|
||||
/// The method's input type.
|
||||
/// </value>
|
||||
public MessageDescriptor OutputType
|
||||
{
|
||||
get { return outputType; }
|
||||
}
|
||||
public MessageDescriptor OutputType { get { return outputType; } }
|
||||
|
||||
internal MethodDescriptor(MethodDescriptorProto proto, FileDescriptor file,
|
||||
ServiceDescriptor parent, int index)
|
||||
: base(proto, file, parent.FullName + "." + proto.Name, index)
|
||||
: base(file, parent.FullName + "." + proto.Name, index)
|
||||
{
|
||||
this.proto = proto;
|
||||
service = parent;
|
||||
file.DescriptorPool.AddSymbol(this);
|
||||
}
|
||||
|
||||
internal MethodDescriptorProto Proto { get { return proto; } }
|
||||
|
||||
/// <summary>
|
||||
/// The brief name of the descriptor's target.
|
||||
/// </summary>
|
||||
public override string Name { get { return proto.Name; } }
|
||||
|
||||
internal void CrossLink()
|
||||
{
|
||||
IDescriptor lookup = File.DescriptorPool.LookupSymbol(Proto.InputType, this);
|
||||
|
@ -31,48 +31,49 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using Google.Protobuf.DescriptorProtos;
|
||||
|
||||
namespace Google.Protobuf.Descriptors
|
||||
{
|
||||
public sealed class OneofDescriptor
|
||||
public sealed class OneofDescriptor : DescriptorBase
|
||||
{
|
||||
private int index;
|
||||
private OneofDescriptorProto proto;
|
||||
private FileDescriptor file;
|
||||
private readonly OneofDescriptorProto proto;
|
||||
private MessageDescriptor containingType;
|
||||
internal int fieldCount;
|
||||
internal IList<FieldDescriptor> fields;
|
||||
private IList<FieldDescriptor> fields;
|
||||
|
||||
internal OneofDescriptor(OneofDescriptorProto proto, FileDescriptor file,
|
||||
MessageDescriptor parent, int index)
|
||||
internal OneofDescriptor(OneofDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index)
|
||||
: base(file, file.ComputeFullName(parent, proto.Name), index)
|
||||
{
|
||||
this.proto = proto;
|
||||
this.file = file;
|
||||
this.index = index;
|
||||
|
||||
containingType = parent;
|
||||
fieldCount = 0;
|
||||
|
||||
file.DescriptorPool.AddSymbol(this);
|
||||
}
|
||||
|
||||
public int Index
|
||||
{
|
||||
get { return index; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The brief name of the descriptor's target.
|
||||
/// </summary>
|
||||
public override string Name { get { return proto.Name; } }
|
||||
|
||||
public MessageDescriptor ContainingType
|
||||
{
|
||||
get { return containingType; }
|
||||
}
|
||||
|
||||
public int FieldCount
|
||||
{
|
||||
get { return fieldCount; }
|
||||
}
|
||||
public IList<FieldDescriptor> Fields { get { return fields; } }
|
||||
|
||||
public FieldDescriptor Field(int index)
|
||||
internal void CrossLink()
|
||||
{
|
||||
return fields[index];
|
||||
List<FieldDescriptor> fieldCollection = new List<FieldDescriptor>();
|
||||
foreach (var field in ContainingType.Fields)
|
||||
{
|
||||
if (field.ContainingOneof == this)
|
||||
{
|
||||
fieldCollection.Add(field);
|
||||
}
|
||||
}
|
||||
fields = new ReadOnlyCollection<FieldDescriptor>(fieldCollection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ namespace Google.Protobuf.Descriptors
|
||||
/// just as placeholders so that someone cannot define, say, a message type
|
||||
/// that has the same name as an existing package.
|
||||
/// </summary>
|
||||
internal sealed class PackageDescriptor : IDescriptor<IMessage>
|
||||
internal sealed class PackageDescriptor : IDescriptor
|
||||
{
|
||||
private readonly string name;
|
||||
private readonly string fullName;
|
||||
@ -50,11 +50,6 @@ namespace Google.Protobuf.Descriptors
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public IMessage Proto
|
||||
{
|
||||
get { return file.Proto; }
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return name; }
|
||||
|
@ -39,19 +39,28 @@ namespace Google.Protobuf.Descriptors
|
||||
/// <summary>
|
||||
/// Describes a service type.
|
||||
/// </summary>
|
||||
public sealed class ServiceDescriptor : IndexedDescriptorBase<ServiceDescriptorProto, ServiceOptions>
|
||||
public sealed class ServiceDescriptor : DescriptorBase
|
||||
{
|
||||
private readonly ServiceDescriptorProto proto;
|
||||
private readonly IList<MethodDescriptor> methods;
|
||||
|
||||
public ServiceDescriptor(ServiceDescriptorProto proto, FileDescriptor file, int index)
|
||||
: base(proto, file, ComputeFullName(file, null, proto.Name), index)
|
||||
internal ServiceDescriptor(ServiceDescriptorProto proto, FileDescriptor file, int index)
|
||||
: base(file, file.ComputeFullName(null, proto.Name), index)
|
||||
{
|
||||
this.proto = proto;
|
||||
methods = DescriptorUtil.ConvertAndMakeReadOnly(proto.Method,
|
||||
(method, i) => new MethodDescriptor(method, file, this, i));
|
||||
|
||||
file.DescriptorPool.AddSymbol(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The brief name of the descriptor's target.
|
||||
/// </summary>
|
||||
public override string Name { get { return proto.Name; } }
|
||||
|
||||
internal ServiceDescriptorProto Proto { get { return proto; } }
|
||||
|
||||
/// <value>
|
||||
/// An unmodifiable list of methods in this service.
|
||||
/// </value>
|
||||
@ -77,14 +86,5 @@ namespace Google.Protobuf.Descriptors
|
||||
method.CrossLink();
|
||||
}
|
||||
}
|
||||
|
||||
internal override void ReplaceProto(ServiceDescriptorProto newProto)
|
||||
{
|
||||
base.ReplaceProto(newProto);
|
||||
for (int i = 0; i < methods.Count; i++)
|
||||
{
|
||||
methods[i].ReplaceProto(newProto.Method[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -32,34 +32,37 @@
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Google.Protobuf.Descriptors;
|
||||
|
||||
namespace Google.Protobuf.FieldAccess
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for field accessors.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of message containing the field</typeparam>
|
||||
internal abstract class FieldAccessorBase<T> : IFieldAccessor<T> where T : IMessage<T>
|
||||
internal abstract class FieldAccessorBase : IFieldAccessor
|
||||
{
|
||||
private readonly Func<T, object> getValueDelegate;
|
||||
private readonly Func<object, object> getValueDelegate;
|
||||
private readonly FieldDescriptor descriptor;
|
||||
|
||||
internal FieldAccessorBase(string name)
|
||||
internal FieldAccessorBase(Type type, string propertyName, FieldDescriptor descriptor)
|
||||
{
|
||||
PropertyInfo property = typeof(T).GetProperty(name);
|
||||
PropertyInfo property = type.GetProperty(propertyName);
|
||||
if (property == null || !property.CanRead)
|
||||
{
|
||||
throw new ArgumentException("Not all required properties/methods available");
|
||||
}
|
||||
getValueDelegate = ReflectionUtil.CreateUpcastDelegate<T>(property.GetGetMethod());
|
||||
this.descriptor = descriptor;
|
||||
getValueDelegate = ReflectionUtil.CreateFuncObjectObject(property.GetGetMethod());
|
||||
}
|
||||
|
||||
public object GetValue(T message)
|
||||
public FieldDescriptor Descriptor { get { return descriptor; } }
|
||||
|
||||
public object GetValue(object message)
|
||||
{
|
||||
return getValueDelegate(message);
|
||||
}
|
||||
|
||||
public abstract bool HasValue(T message);
|
||||
public abstract void Clear(T message);
|
||||
public abstract void SetValue(T message, object value);
|
||||
public abstract void Clear(object message);
|
||||
public abstract void SetValue(object message, object value);
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using Google.Protobuf.Descriptors;
|
||||
|
||||
namespace Google.Protobuf.FieldAccess
|
||||
@ -38,34 +39,43 @@ namespace Google.Protobuf.FieldAccess
|
||||
/// <summary>
|
||||
/// Provides access to fields in generated messages via reflection.
|
||||
/// </summary>
|
||||
public sealed class FieldAccessorTable<T> where T : IMessage<T>
|
||||
public sealed class FieldAccessorTable
|
||||
{
|
||||
private readonly IFieldAccessor<T>[] accessors;
|
||||
private readonly ReadOnlyCollection<IFieldAccessor> accessors;
|
||||
private readonly MessageDescriptor descriptor;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a FieldAccessorTable for a particular message class.
|
||||
/// Only one FieldAccessorTable should be constructed per class.
|
||||
/// </summary>
|
||||
/// <param name="type">The CLR type for the message.</param>
|
||||
/// <param name="descriptor">The type's descriptor</param>
|
||||
/// <param name="propertyNames">The Pascal-case names of all the field-based properties in the message.</param>
|
||||
public FieldAccessorTable(MessageDescriptor descriptor, string[] propertyNames)
|
||||
public FieldAccessorTable(Type type, MessageDescriptor descriptor, string[] propertyNames)
|
||||
{
|
||||
this.descriptor = descriptor;
|
||||
accessors = new IFieldAccessor<T>[descriptor.Fields.Count];
|
||||
bool supportFieldPresence = descriptor.File.Syntax == FileDescriptor.ProtoSyntax.Proto2;
|
||||
for (int i = 0; i < accessors.Length; i++)
|
||||
var accessorsArray = new IFieldAccessor[descriptor.Fields.Count];
|
||||
for (int i = 0; i < accessorsArray.Length; i++)
|
||||
{
|
||||
var field = descriptor.Fields[i];
|
||||
var name = propertyNames[i];
|
||||
accessors[i] = field.IsRepeated
|
||||
? (IFieldAccessor<T>) new RepeatedFieldAccessor<T>(propertyNames[i])
|
||||
: new SingleFieldAccessor<T>(field, name, supportFieldPresence);
|
||||
accessorsArray[i] =
|
||||
field.IsMap ? new MapFieldAccessor(type, name, field)
|
||||
: field.IsRepeated ? new RepeatedFieldAccessor(type, name, field)
|
||||
: (IFieldAccessor) new SingleFieldAccessor(type, name, field);
|
||||
}
|
||||
accessors = new ReadOnlyCollection<IFieldAccessor>(accessorsArray);
|
||||
// TODO(jonskeet): Oneof support
|
||||
}
|
||||
|
||||
internal IFieldAccessor<T> this[int fieldNumber]
|
||||
// TODO: Validate the name here... should possibly make this type a more "general reflection access" type,
|
||||
// bearing in mind the oneof parts to come as well.
|
||||
/// <summary>
|
||||
/// Returns all of the field accessors for the message type.
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<IFieldAccessor> Accessors { get { return accessors; } }
|
||||
|
||||
public IFieldAccessor this[int fieldNumber]
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -74,7 +84,7 @@ namespace Google.Protobuf.FieldAccess
|
||||
}
|
||||
}
|
||||
|
||||
internal IFieldAccessor<T> this[FieldDescriptor field]
|
||||
internal IFieldAccessor this[FieldDescriptor field]
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -30,39 +30,41 @@
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endregion
|
||||
|
||||
using Google.Protobuf.Descriptors;
|
||||
|
||||
namespace Google.Protobuf.FieldAccess
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows fields to be reflectively accessed in a smart manner.
|
||||
/// The property descriptors for each field are created once and then cached.
|
||||
/// In addition, this interface holds knowledge of repeated fields, builders etc.
|
||||
/// Allows fields to be reflectively accessed.
|
||||
/// </summary>
|
||||
internal interface IFieldAccessor<T> where T : IMessage<T>
|
||||
public interface IFieldAccessor
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the specified message contains the field. For primitive fields
|
||||
/// declared in proto3-syntax messages, this simply checks whether the value is the default one.
|
||||
/// Returns the descriptor associated with this field.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">The field is a repeated field, or a single primitive field.</exception>
|
||||
bool HasValue(T message);
|
||||
FieldDescriptor Descriptor { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Clears the field in the specified message. (For repeated fields,
|
||||
/// this clears the list.)
|
||||
/// </summary>
|
||||
void Clear(T message);
|
||||
void Clear(object message);
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the field value. For repeated values, this will be an
|
||||
/// <see cref="IList"/> implementation.
|
||||
/// <see cref="IList"/> implementation. For map values, this will be an
|
||||
/// <see cref="IDictionary"/> implementation.
|
||||
/// </summary>
|
||||
object GetValue(T message);
|
||||
object GetValue(object message);
|
||||
|
||||
/// <summary>
|
||||
/// Mutator for single fields only. (Repeated fields must be mutated
|
||||
/// by fetching the list, then mutating that.)
|
||||
/// Mutator for single "simple" fields only.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">The field is a repeated field.</exception>
|
||||
void SetValue(T message, object value);
|
||||
/// <remarks>
|
||||
/// Repeated fields are mutated by fetching the value and manipulating it as a list.
|
||||
/// Map fields are mutated by fetching the value and manipulating it as a dictionary.
|
||||
/// </remarks>
|
||||
/// <exception cref="InvalidOperationException">The field is not a "simple" field, or the message is frozen.</exception>
|
||||
void SetValue(object message, object value);
|
||||
}
|
||||
}
|
@ -1,53 +1,59 @@
|
||||
#region Copyright notice and license
|
||||
// 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.
|
||||
#endregion
|
||||
|
||||
namespace Google.Protobuf.DescriptorProtos
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface implemented by all DescriptorProtos. The generator doesn't
|
||||
/// emit the interface implementation claim, so PartialClasses.cs contains
|
||||
/// partial class declarations for each of them.
|
||||
/// </summary>
|
||||
/// <typeparam name="TOptions">The associated options protocol buffer type</typeparam>
|
||||
public interface IDescriptorProto<TOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// The brief name of the descriptor's target.
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The options for this descriptor.
|
||||
/// </summary>
|
||||
TOptions Options { get; }
|
||||
}
|
||||
}
|
||||
#region Copyright notice and license
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2015 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.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Google.Protobuf.Descriptors;
|
||||
|
||||
namespace Google.Protobuf.FieldAccess
|
||||
{
|
||||
/// <summary>
|
||||
/// Accessor for map fields.
|
||||
/// </summary>
|
||||
internal sealed class MapFieldAccessor : FieldAccessorBase
|
||||
{
|
||||
internal MapFieldAccessor(Type type, string propertyName, FieldDescriptor descriptor) : base(type, propertyName, descriptor)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Clear(object message)
|
||||
{
|
||||
IDictionary list = (IDictionary) GetValue(message);
|
||||
list.Clear();
|
||||
}
|
||||
|
||||
public override void SetValue(object message, object value)
|
||||
{
|
||||
throw new InvalidOperationException("SetValue is not implemented for map fields");
|
||||
}
|
||||
}
|
||||
}
|
@ -31,6 +31,7 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Google.Protobuf.FieldAccess
|
||||
@ -51,101 +52,42 @@ namespace Google.Protobuf.FieldAccess
|
||||
internal static readonly Type[] EmptyTypes = new Type[0];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a delegate which will execute the given method and then return
|
||||
/// the result as an object.
|
||||
/// Creates a delegate which will cast the argument to the appropriate method target type,
|
||||
/// call the method on it, then convert the result to object.
|
||||
/// </summary>
|
||||
public static Func<T, object> CreateUpcastDelegate<T>(MethodInfo method)
|
||||
internal static Func<object, object> CreateFuncObjectObject(MethodInfo method)
|
||||
{
|
||||
// The tricky bit is invoking CreateCreateUpcastDelegateImpl with the right type parameters
|
||||
MethodInfo openImpl = typeof(ReflectionUtil).GetMethod("CreateUpcastDelegateImpl");
|
||||
MethodInfo closedImpl = openImpl.MakeGenericMethod(typeof(T), method.ReturnType);
|
||||
return (Func<T, object>) closedImpl.Invoke(null, new object[] {method});
|
||||
ParameterExpression parameter = Expression.Parameter(typeof(object), "p");
|
||||
Expression downcast = Expression.Convert(parameter, method.DeclaringType);
|
||||
Expression call = Expression.Call(downcast, method);
|
||||
Expression upcast = Expression.Convert(call, typeof(object));
|
||||
return Expression.Lambda<Func<object, object>>(upcast, parameter).Compile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a delegate which will execute the given method after casting the first argument to
|
||||
/// the target type of the method, and the second argument to the first parameter type of the method.
|
||||
/// </summary>
|
||||
internal static Action<object, object> CreateActionObjectObject(MethodInfo method)
|
||||
{
|
||||
ParameterExpression targetParameter = Expression.Parameter(typeof(object), "target");
|
||||
ParameterExpression argParameter = Expression.Parameter(typeof(object), "arg");
|
||||
Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
|
||||
Expression castArgument = Expression.Convert(argParameter, method.GetParameters()[0].ParameterType);
|
||||
Expression call = Expression.Call(castTarget, method, castArgument);
|
||||
return Expression.Lambda<Action<object, object>>(call, targetParameter, argParameter).Compile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method used solely for implementing CreateUpcastDelegate. Public to avoid trust issues
|
||||
/// in low-trust scenarios.
|
||||
/// Creates a delegate which will execute the given method after casting the first argument to
|
||||
/// the target type of the method.
|
||||
/// </summary>
|
||||
public static Func<TSource, object> CreateUpcastDelegateImpl<TSource, TResult>(MethodInfo method)
|
||||
internal static Action<object> CreateActionObject(MethodInfo method)
|
||||
{
|
||||
// Convert the reflection call into an open delegate, i.e. instead of calling x.Method()
|
||||
// we'll call getter(x).
|
||||
Func<TSource, TResult> getter = ReflectionUtil.CreateDelegateFunc<TSource, TResult>(method);
|
||||
|
||||
// Implicit upcast to object (within the delegate)
|
||||
return source => getter(source);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a delegate which will execute the given method after casting the parameter
|
||||
/// down from object to the required parameter type.
|
||||
/// </summary>
|
||||
public static Action<T, object> CreateDowncastDelegate<T>(MethodInfo method)
|
||||
{
|
||||
MethodInfo openImpl = typeof(ReflectionUtil).GetMethod("CreateDowncastDelegateImpl");
|
||||
MethodInfo closedImpl = openImpl.MakeGenericMethod(typeof(T), method.GetParameters()[0].ParameterType);
|
||||
return (Action<T, object>) closedImpl.Invoke(null, new object[] {method});
|
||||
}
|
||||
|
||||
public static Action<TSource, object> CreateDowncastDelegateImpl<TSource, TParam>(MethodInfo method)
|
||||
{
|
||||
// Convert the reflection call into an open delegate, i.e. instead of calling x.Method(y) we'll
|
||||
// call Method(x, y)
|
||||
Action<TSource, TParam> call = ReflectionUtil.CreateDelegateAction<TSource, TParam>(method);
|
||||
|
||||
return (source, parameter) => call(source, (TParam) parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a delegate which will execute the given method after casting the parameter
|
||||
/// down from object to the required parameter type.
|
||||
/// </summary>
|
||||
public static Action<T, object> CreateDowncastDelegateIgnoringReturn<T>(MethodInfo method)
|
||||
{
|
||||
MethodInfo openImpl = typeof(ReflectionUtil).GetMethod("CreateDowncastDelegateIgnoringReturnImpl");
|
||||
MethodInfo closedImpl = openImpl.MakeGenericMethod(typeof(T), method.GetParameters()[0].ParameterType,
|
||||
method.ReturnType);
|
||||
return (Action<T, object>) closedImpl.Invoke(null, new object[] {method});
|
||||
}
|
||||
|
||||
public static Action<TSource, object> CreateDowncastDelegateIgnoringReturnImpl<TSource, TParam, TReturn>(
|
||||
MethodInfo method)
|
||||
{
|
||||
// Convert the reflection call into an open delegate, i.e. instead of calling x.Method(y) we'll
|
||||
// call Method(x, y)
|
||||
Func<TSource, TParam, TReturn> call = ReflectionUtil.CreateDelegateFunc<TSource, TParam, TReturn>(method);
|
||||
|
||||
return delegate(TSource source, object parameter) { call(source, (TParam) parameter); };
|
||||
}
|
||||
|
||||
internal static Func<TResult> CreateDelegateFunc<TResult>(MethodInfo method)
|
||||
{
|
||||
object tdelegate = Delegate.CreateDelegate(typeof(Func<TResult>), null, method);
|
||||
return (Func<TResult>)tdelegate;
|
||||
}
|
||||
|
||||
internal static Func<T, TResult> CreateDelegateFunc<T, TResult>(MethodInfo method)
|
||||
{
|
||||
object tdelegate = Delegate.CreateDelegate(typeof(Func<T, TResult>), null, method);
|
||||
return (Func<T, TResult>)tdelegate;
|
||||
}
|
||||
|
||||
internal static Func<T1, T2, TResult> CreateDelegateFunc<T1, T2, TResult>(MethodInfo method)
|
||||
{
|
||||
object tdelegate = Delegate.CreateDelegate(typeof(Func<T1, T2, TResult>), null, method);
|
||||
return (Func<T1, T2, TResult>)tdelegate;
|
||||
}
|
||||
|
||||
internal static Action<T> CreateDelegateAction<T>(MethodInfo method)
|
||||
{
|
||||
object tdelegate = Delegate.CreateDelegate(typeof(Action<T>), null, method);
|
||||
return (Action<T>)tdelegate;
|
||||
}
|
||||
|
||||
internal static Action<T1, T2> CreateDelegateAction<T1, T2>(MethodInfo method)
|
||||
{
|
||||
object tdelegate = Delegate.CreateDelegate(typeof(Action<T1, T2>), null, method);
|
||||
return (Action<T1, T2>)tdelegate;
|
||||
ParameterExpression targetParameter = Expression.Parameter(typeof(object), "target");
|
||||
Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
|
||||
Expression call = Expression.Call(castTarget, method);
|
||||
return Expression.Lambda<Action<object>>(call, targetParameter).Compile();
|
||||
}
|
||||
}
|
||||
}
|
@ -32,33 +32,28 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Google.Protobuf.Descriptors;
|
||||
|
||||
namespace Google.Protobuf.FieldAccess
|
||||
{
|
||||
/// <summary>
|
||||
/// Accessor for repeated fields.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of message containing the field.</typeparam>
|
||||
internal sealed class RepeatedFieldAccessor<T> : FieldAccessorBase<T> where T : IMessage<T>
|
||||
internal sealed class RepeatedFieldAccessor : FieldAccessorBase
|
||||
{
|
||||
internal RepeatedFieldAccessor(string name) : base(name)
|
||||
internal RepeatedFieldAccessor(Type type, string propertyName, FieldDescriptor descriptor) : base(type, propertyName, descriptor)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Clear(T message)
|
||||
public override void Clear(object message)
|
||||
{
|
||||
IList list = (IList) GetValue(message);
|
||||
list.Clear();
|
||||
}
|
||||
|
||||
public override bool HasValue(T message)
|
||||
public override void SetValue(object message, object value)
|
||||
{
|
||||
throw new NotImplementedException("HasValue is not implemented for repeated fields");
|
||||
}
|
||||
|
||||
public override void SetValue(T message, object value)
|
||||
{
|
||||
throw new NotImplementedException("SetValue is not implemented for repeated fields");
|
||||
throw new InvalidOperationException("SetValue is not implemented for repeated fields");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,76 +39,46 @@ namespace Google.Protobuf.FieldAccess
|
||||
/// <summary>
|
||||
/// Accessor for single fields.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of message containing the field.</typeparam>
|
||||
internal sealed class SingleFieldAccessor<T> : FieldAccessorBase<T> where T : IMessage<T>
|
||||
internal sealed class SingleFieldAccessor : FieldAccessorBase
|
||||
{
|
||||
// All the work here is actually done in the constructor - it creates the appropriate delegates.
|
||||
// There are various cases to consider, based on the property type (message, string/bytes, or "genuine" primitive)
|
||||
// and proto2 vs proto3 for non-message types, as proto3 doesn't support "full" presence detection or default
|
||||
// values.
|
||||
|
||||
private readonly Action<T, object> setValueDelegate;
|
||||
private readonly Action<T> clearDelegate;
|
||||
private readonly Func<T, bool> hasValueDelegate;
|
||||
private readonly Action<object, object> setValueDelegate;
|
||||
private readonly Action<object> clearDelegate;
|
||||
|
||||
internal SingleFieldAccessor(FieldDescriptor descriptor, string name, bool supportsFieldPresence) : base(name)
|
||||
internal SingleFieldAccessor(Type type, string propertyName, FieldDescriptor descriptor) : base(type, propertyName, descriptor)
|
||||
{
|
||||
PropertyInfo property = typeof(T).GetProperty(name);
|
||||
PropertyInfo property = type.GetProperty(propertyName);
|
||||
// We know there *is* such a property, or the base class constructor would have thrown. We should be able to write
|
||||
// to it though.
|
||||
if (!property.CanWrite)
|
||||
{
|
||||
throw new ArgumentException("Not all required properties/methods available");
|
||||
}
|
||||
setValueDelegate = ReflectionUtil.CreateDowncastDelegate<T>(property.GetSetMethod());
|
||||
setValueDelegate = ReflectionUtil.CreateActionObjectObject(property.GetSetMethod());
|
||||
|
||||
var clrType = property.PropertyType;
|
||||
|
||||
// TODO: What should clear on a oneof member do? Clear the oneof?
|
||||
|
||||
if (typeof(IMessage).IsAssignableFrom(clrType))
|
||||
{
|
||||
// Message types are simple - we only need to detect nullity.
|
||||
clearDelegate = message => SetValue(message, null);
|
||||
hasValueDelegate = message => GetValue(message) == null;
|
||||
}
|
||||
|
||||
if (supportsFieldPresence)
|
||||
{
|
||||
// Proto2: we expect a HasFoo property and a ClearFoo method.
|
||||
// For strings and byte arrays, setting the property to null would have the equivalent effect,
|
||||
// but we generate the method for consistency, which makes this simpler.
|
||||
PropertyInfo hasProperty = typeof(T).GetProperty("Has" + name);
|
||||
MethodInfo clearMethod = typeof(T).GetMethod("Clear" + name);
|
||||
if (hasProperty == null || clearMethod == null || !hasProperty.CanRead)
|
||||
{
|
||||
throw new ArgumentException("Not all required properties/methods available");
|
||||
}
|
||||
hasValueDelegate = ReflectionUtil.CreateDelegateFunc<T, bool>(hasProperty.GetGetMethod());
|
||||
clearDelegate = ReflectionUtil.CreateDelegateAction<T>(clearMethod);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
// TODO(jonskeet): Reimplement. We need a better way of working out default values.
|
||||
// Proto3: for field detection, we just need the default value of the field (0, "", byte[0] etc)
|
||||
// To clear a field, we set the value to that default.
|
||||
object defaultValue = descriptor.DefaultValue;
|
||||
hasValueDelegate = message => GetValue(message).Equals(defaultValue);
|
||||
clearDelegate = message => SetValue(message, defaultValue);
|
||||
*/
|
||||
}
|
||||
// TODO: Validate that this is a reasonable single field? (Should be a value type, a message type, or string/ByteString.)
|
||||
object defaultValue =
|
||||
typeof(IMessage).IsAssignableFrom(clrType) ? null
|
||||
: clrType == typeof(string) ? ""
|
||||
: clrType == typeof(ByteString) ? ByteString.Empty
|
||||
: Activator.CreateInstance(clrType);
|
||||
clearDelegate = message => SetValue(message, defaultValue);
|
||||
}
|
||||
|
||||
public override bool HasValue(T message)
|
||||
{
|
||||
return hasValueDelegate(message);
|
||||
}
|
||||
|
||||
public override void Clear(T message)
|
||||
public override void Clear(object message)
|
||||
{
|
||||
clearDelegate(message);
|
||||
}
|
||||
|
||||
public override void SetValue(T message, object value)
|
||||
public override void SetValue(object message, object value)
|
||||
{
|
||||
setValueDelegate(message, value);
|
||||
}
|
||||
|
@ -68,12 +68,12 @@ namespace Google.Protobuf
|
||||
|
||||
public static FieldCodec<uint> ForFixed32(uint tag)
|
||||
{
|
||||
return new FieldCodec<uint>(input => input.ReadFixed32(), (output, value) => output.WriteFixed32(value), CodedOutputStream.ComputeFixed32Size, tag);
|
||||
return new FieldCodec<uint>(input => input.ReadFixed32(), (output, value) => output.WriteFixed32(value), 4, tag);
|
||||
}
|
||||
|
||||
public static FieldCodec<int> ForSFixed32(uint tag)
|
||||
{
|
||||
return new FieldCodec<int>(input => input.ReadSFixed32(), (output, value) => output.WriteSFixed32(value), CodedOutputStream.ComputeSFixed32Size, tag);
|
||||
return new FieldCodec<int>(input => input.ReadSFixed32(), (output, value) => output.WriteSFixed32(value), 4, tag);
|
||||
}
|
||||
|
||||
public static FieldCodec<uint> ForUInt32(uint tag)
|
||||
@ -93,12 +93,12 @@ namespace Google.Protobuf
|
||||
|
||||
public static FieldCodec<ulong> ForFixed64(uint tag)
|
||||
{
|
||||
return new FieldCodec<ulong>(input => input.ReadFixed64(), (output, value) => output.WriteFixed64(value), CodedOutputStream.ComputeFixed64Size, tag);
|
||||
return new FieldCodec<ulong>(input => input.ReadFixed64(), (output, value) => output.WriteFixed64(value), 8, tag);
|
||||
}
|
||||
|
||||
public static FieldCodec<long> ForSFixed64(uint tag)
|
||||
{
|
||||
return new FieldCodec<long>(input => input.ReadSFixed64(), (output, value) => output.WriteSFixed64(value), CodedOutputStream.ComputeSFixed64Size, tag);
|
||||
return new FieldCodec<long>(input => input.ReadSFixed64(), (output, value) => output.WriteSFixed64(value), 8, tag);
|
||||
}
|
||||
|
||||
public static FieldCodec<ulong> ForUInt64(uint tag)
|
||||
|
@ -40,12 +40,11 @@ namespace Google.Protobuf
|
||||
// TODO(jonskeet): Split these interfaces into separate files when we're happy with them.
|
||||
|
||||
/// <summary>
|
||||
/// Reflection support for a specific message type. message
|
||||
/// Reflection support for a specific message type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The message type being reflected.</typeparam>
|
||||
public interface IReflectedMessage<T> where T : IMessage<T>
|
||||
public interface IReflectedMessage
|
||||
{
|
||||
FieldAccessorTable<T> Fields { get; }
|
||||
FieldAccessorTable Fields { get; }
|
||||
// TODO(jonskeet): Descriptor? Or a single property which has "all you need for reflection"?
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,6 @@
|
||||
<Compile Include="Collections\ReadOnlyDictionary.cs" />
|
||||
<Compile Include="Collections\RepeatedField.cs" />
|
||||
<Compile Include="DescriptorProtos\DescriptorProtoFile.cs" />
|
||||
<Compile Include="DescriptorProtos\IDescriptorProto.cs" />
|
||||
<Compile Include="DescriptorProtos\PartialClasses.cs" />
|
||||
<Compile Include="Descriptors\DescriptorBase.cs" />
|
||||
<Compile Include="Descriptors\DescriptorPool.cs" />
|
||||
@ -74,11 +73,11 @@
|
||||
<Compile Include="Descriptors\FileDescriptor.cs" />
|
||||
<Compile Include="Descriptors\OneofDescriptor.cs" />
|
||||
<Compile Include="Descriptors\IDescriptor.cs" />
|
||||
<Compile Include="Descriptors\IndexedDescriptorBase.cs" />
|
||||
<Compile Include="Descriptors\MessageDescriptor.cs" />
|
||||
<Compile Include="Descriptors\MethodDescriptor.cs" />
|
||||
<Compile Include="Descriptors\PackageDescriptor.cs" />
|
||||
<Compile Include="Descriptors\ServiceDescriptor.cs" />
|
||||
<Compile Include="FieldAccess\MapFieldAccessor.cs" />
|
||||
<Compile Include="FieldCodec.cs" />
|
||||
<Compile Include="FrameworkPortability.cs" />
|
||||
<Compile Include="Freezable.cs" />
|
||||
|
@ -1,6 +1,6 @@
|
||||
// See README.txt for information and build instructions.
|
||||
|
||||
syntax = "proto2";
|
||||
syntax = "proto3";
|
||||
|
||||
package tutorial;
|
||||
|
||||
@ -9,9 +9,9 @@ option java_outer_classname = "AddressBookProtos";
|
||||
option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
|
||||
|
||||
message Person {
|
||||
required string name = 1;
|
||||
required int32 id = 2; // Unique ID number for this person.
|
||||
optional string email = 3;
|
||||
string name = 1;
|
||||
int32 id = 2; // Unique ID number for this person.
|
||||
string email = 3;
|
||||
|
||||
enum PhoneType {
|
||||
MOBILE = 0;
|
||||
@ -20,8 +20,8 @@ message Person {
|
||||
}
|
||||
|
||||
message PhoneNumber {
|
||||
required string number = 1;
|
||||
optional PhoneType type = 2 [default = HOME];
|
||||
string number = 1;
|
||||
PhoneType type = 2;
|
||||
}
|
||||
|
||||
repeated PhoneNumber phone = 4;
|
||||
|
@ -65,6 +65,7 @@ void FieldGeneratorBase::SetCommonFieldVariables(
|
||||
tag_bytes += ", " + SimpleItoa(tag_array[i]);
|
||||
}
|
||||
|
||||
(*variables)["access_level"] = class_access_level();
|
||||
(*variables)["tag"] = SimpleItoa(tag);
|
||||
(*variables)["tag_size"] = SimpleItoa(tag_size);
|
||||
(*variables)["tag_bytes"] = tag_bytes;
|
||||
|
@ -68,6 +68,12 @@ bool Generator::Generate(
|
||||
vector<pair<string, string> > options;
|
||||
ParseGeneratorParameter(parameter, &options);
|
||||
|
||||
// We only support proto3 - but we make an exception for descriptor.proto.
|
||||
if (file->syntax() != FileDescriptor::SYNTAX_PROTO3 && !IsDescriptorProto(file)) {
|
||||
*error = "C# code generation only supports proto3 syntax";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string file_extension = ".cs";
|
||||
for (int i = 0; i < options.size(); i++) {
|
||||
if (options[i].first == "file_extension") {
|
||||
|
@ -101,6 +101,15 @@ uint FixedMakeTag(const FieldDescriptor* descriptor);
|
||||
|
||||
FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
|
||||
|
||||
// Determines whether we're generating code for the proto representation of descriptors etc,
|
||||
// for use in the runtime. This is the only type which is allowed to use proto2 syntax,
|
||||
// and it generates internal classes.
|
||||
inline bool IsDescriptorProto(const FileDescriptor* descriptor) {
|
||||
// TODO: Do this better! (Currently this depends on a hack in generate_protos.sh to rename
|
||||
// the file...)
|
||||
return descriptor->name() == "google/protobuf/descriptor_proto_file.proto";
|
||||
}
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
@ -78,7 +78,7 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
|
||||
AddDeprecatedFlag(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"public pbc::MapField<$key_type_name$, $value_type_name$> $property_name$ {\n"
|
||||
"$access_level$ pbc::MapField<$key_type_name$, $value_type_name$> $property_name$ {\n"
|
||||
" get { return $name$_; }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
@ -116,8 +116,7 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
|
||||
|
||||
// The descriptor for this type.
|
||||
printer->Print(
|
||||
"internal static pbd::MessageDescriptor internal__$identifier$__Descriptor;\n"
|
||||
"internal static pb::FieldAccess.FieldAccessorTable<$full_class_name$> internal__$identifier$__FieldAccessorTable;\n",
|
||||
"internal static pb::FieldAccess.FieldAccessorTable internal__$identifier$__FieldAccessorTable;\n",
|
||||
"identifier", GetUniqueFileScopeIdentifier(descriptor_),
|
||||
"full_class_name", full_class_name());
|
||||
|
||||
@ -130,24 +129,23 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
|
||||
void MessageGenerator::GenerateStaticVariableInitializers(io::Printer* printer) {
|
||||
map<string, string> vars;
|
||||
vars["identifier"] = GetUniqueFileScopeIdentifier(descriptor_);
|
||||
vars["index"] = SimpleItoa(descriptor_->index());
|
||||
vars["full_class_name"] = full_class_name();
|
||||
if (descriptor_->containing_type() != NULL) {
|
||||
vars["parent"] = GetUniqueFileScopeIdentifier(
|
||||
descriptor_->containing_type());
|
||||
}
|
||||
printer->Print(vars, "internal__$identifier$__Descriptor = ");
|
||||
|
||||
if (!descriptor_->containing_type()) {
|
||||
printer->Print(vars, "Descriptor.MessageTypes[$index$];\n");
|
||||
} else {
|
||||
printer->Print(vars, "internal__$parent$__Descriptor.NestedTypes[$index$];\n");
|
||||
// Work out how to get to the message descriptor (which may be multiply nested) from the file
|
||||
// descriptor.
|
||||
string descriptor_chain;
|
||||
const Descriptor* current_descriptor = descriptor_;
|
||||
while (current_descriptor->containing_type()) {
|
||||
descriptor_chain = ".NestedTypes[" + SimpleItoa(current_descriptor->index()) + "]" + descriptor_chain;
|
||||
current_descriptor = current_descriptor->containing_type();
|
||||
}
|
||||
descriptor_chain = "descriptor.MessageTypes[" + SimpleItoa(current_descriptor->index()) + "]" + descriptor_chain;
|
||||
vars["descriptor_chain"] = descriptor_chain;
|
||||
|
||||
printer->Print(
|
||||
vars,
|
||||
"internal__$identifier$__FieldAccessorTable = \n"
|
||||
" new pb::FieldAccess.FieldAccessorTable<$full_class_name$>(internal__$identifier$__Descriptor,\n");
|
||||
" new pb::FieldAccess.FieldAccessorTable(typeof($full_class_name$), $descriptor_chain$,\n");
|
||||
printer->Print(" new string[] { ");
|
||||
for (int i = 0; i < descriptor_->field_count(); i++) {
|
||||
printer->Print("\"$property_name$\", ",
|
||||
@ -201,23 +199,35 @@ void MessageGenerator::Generate(io::Printer* printer) {
|
||||
"private static readonly uint[] _fieldTags = new uint[] { $tags$ };\n",
|
||||
"tags", JoinStrings(tags, ", "));
|
||||
|
||||
// Access the message descriptor via the relevant file descriptor or containing message descriptor.
|
||||
if (!descriptor_->containing_type()) {
|
||||
vars["descriptor_accessor"] = GetFullUmbrellaClassName(descriptor_->file())
|
||||
+ ".Descriptor.MessageTypes[" + SimpleItoa(descriptor_->index()) + "]";
|
||||
} else {
|
||||
vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type())
|
||||
+ ".Descriptor.NestedTypes[" + SimpleItoa(descriptor_->index()) + "]";
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
vars,
|
||||
"public static pbd::MessageDescriptor Descriptor {\n"
|
||||
" get { return $umbrella_class_name$.internal__$identifier$__Descriptor; }\n"
|
||||
" get { return $descriptor_accessor$; }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"public pb::FieldAccess.FieldAccessorTable<$class_name$> Fields {\n"
|
||||
"public pb::FieldAccess.FieldAccessorTable Fields {\n"
|
||||
" get { return $umbrella_class_name$.internal__$identifier$__FieldAccessorTable; }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"private bool _frozen = false;\n"
|
||||
"public bool IsFrozen { get { return _frozen; } }\n\n");
|
||||
|
||||
// Parameterless constructor
|
||||
// Parameterless constructor and partial OnConstruction method.
|
||||
printer->Print(
|
||||
vars,
|
||||
"public $class_name$() { }\n\n");
|
||||
"public $class_name$() {\n"
|
||||
" OnConstruction();\n"
|
||||
"}\n\n"
|
||||
"partial void OnConstruction();\n\n");
|
||||
|
||||
GenerateCloningCode(printer);
|
||||
GenerateFreezingCode(printer);
|
||||
@ -304,7 +314,7 @@ void MessageGenerator::GenerateCloningCode(io::Printer* printer) {
|
||||
vars["class_name"] = class_name();
|
||||
printer->Print(
|
||||
vars,
|
||||
"public $class_name$($class_name$ other) {\n");
|
||||
"public $class_name$($class_name$ other) : this() {\n");
|
||||
printer->Indent();
|
||||
// Clone non-oneof fields first
|
||||
for (int i = 0; i < descriptor_->field_count(); i++) {
|
||||
|
@ -64,7 +64,7 @@ void MessageFieldGenerator::GenerateMembers(io::Printer* printer) {
|
||||
AddDeprecatedFlag(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"public $type_name$ $property_name$ {\n"
|
||||
"$access_level$ $type_name$ $property_name$ {\n"
|
||||
" get { return $name$_; }\n"
|
||||
" set {\n"
|
||||
" pb::Freezable.CheckMutable(this);\n"
|
||||
@ -158,7 +158,7 @@ void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
|
||||
AddDeprecatedFlag(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"public $type_name$ $property_name$ {\n"
|
||||
"$access_level$ $type_name$ $property_name$ {\n"
|
||||
" get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : null; }\n"
|
||||
" set {\n"
|
||||
" pb::Freezable.CheckMutable(this);\n"
|
||||
|
@ -71,7 +71,7 @@ void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
|
||||
AddDeprecatedFlag(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"public $type_name$ $property_name$ {\n"
|
||||
"$access_level$ $type_name$ $property_name$ {\n"
|
||||
" get { return $name$_; }\n"
|
||||
" set {\n"
|
||||
" pb::Freezable.CheckMutable(this);\n");
|
||||
@ -174,7 +174,7 @@ void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
|
||||
AddDeprecatedFlag(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"public $type_name$ $property_name$ {\n"
|
||||
"$access_level$ $type_name$ $property_name$ {\n"
|
||||
" get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : $default_value$; }\n"
|
||||
" set {\n"
|
||||
" pb::Freezable.CheckMutable(this);\n");
|
||||
|
@ -65,7 +65,7 @@ void RepeatedEnumFieldGenerator::GenerateMembers(io::Printer* printer) {
|
||||
AddDeprecatedFlag(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"public pbc::RepeatedField<$type_name$> $property_name$ {\n"
|
||||
"$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
|
||||
" get { return $name$_; }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ void RepeatedMessageFieldGenerator::GenerateMembers(io::Printer* printer) {
|
||||
AddDeprecatedFlag(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"public pbc::RepeatedField<$type_name$> $property_name$ {\n"
|
||||
"$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
|
||||
" get { return $name$_; }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ void RepeatedPrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
|
||||
AddDeprecatedFlag(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"public pbc::RepeatedField<$type_name$> $property_name$ {\n"
|
||||
"$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
|
||||
" get { return $name$_; }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ void SourceGeneratorBase::WriteGeneratedCodeAttributes(io::Printer* printer) {
|
||||
}
|
||||
|
||||
std::string SourceGeneratorBase::class_access_level() {
|
||||
return "public"; // public_classes is always on.
|
||||
return IsDescriptorProto(descriptor_) ? "internal" : "public"; // public_classes is always on.
|
||||
}
|
||||
|
||||
} // namespace csharp
|
||||
|
@ -176,22 +176,11 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) {
|
||||
printer->Print("\"$base64$\"));\n", "base64", base64);
|
||||
printer->Outdent();
|
||||
printer->Outdent();
|
||||
printer->Print(
|
||||
"pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {\n");
|
||||
printer->Indent();
|
||||
printer->Print("descriptor = root;\n");
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
MessageGenerator messageGenerator(file_->message_type(i));
|
||||
messageGenerator.GenerateStaticVariableInitializers(printer);
|
||||
}
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print("};\n");
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Invoke internalBuildGeneratedFileFrom() to build the file.
|
||||
// Invoke InternalBuildGeneratedFileFrom() to build the file.
|
||||
printer->Print(
|
||||
"pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,\n");
|
||||
"descriptor = pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,\n");
|
||||
printer->Print(" new pbd::FileDescriptor[] {\n");
|
||||
for (int i = 0; i < file_->dependency_count(); i++) {
|
||||
printer->Print(
|
||||
@ -199,7 +188,12 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) {
|
||||
"full_umbrella_class_name",
|
||||
GetFullUmbrellaClassName(file_->dependency(i)));
|
||||
}
|
||||
printer->Print(" }, assigner);\n");
|
||||
printer->Print(" });\n");
|
||||
// Then invoke any other static variable initializers, e.g. field accessors.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
MessageGenerator messageGenerator(file_->message_type(i));
|
||||
messageGenerator.GenerateStaticVariableInitializers(printer);
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
printer->Print("#endregion\n\n");
|
||||
|
Loading…
Reference in New Issue
Block a user