Commit ec8c3955 authored by Jon Skeet's avatar Jon Skeet

Gradually implementing FieldSet

parent b83aee75
......@@ -25,8 +25,8 @@ namespace Google.ProtocolBuffers {
protected abstract IMessage BuildPartialImpl();
protected abstract IBuilder CloneImpl();
protected abstract IMessage DefaultInstanceForTypeImpl { get; }
protected abstract IBuilder NewBuilderForFieldImpl<TField>(FieldDescriptor field);
protected abstract IBuilder ClearFieldImpl();
protected abstract IBuilder NewBuilderForFieldImpl(FieldDescriptor field);
protected abstract IBuilder ClearFieldImpl(FieldDescriptor field);
protected abstract IBuilder AddRepeatedFieldImpl(FieldDescriptor field, object value);
#endregion
......@@ -39,30 +39,30 @@ namespace Google.ProtocolBuffers {
return BuildPartialImpl();
}
public IBuilder Clone() {
IBuilder IBuilder.Clone() {
return CloneImpl();
}
public IMessage DefaultInstanceForType {
IMessage IBuilder.DefaultInstanceForType {
get { return DefaultInstanceForTypeImpl; }
}
public IBuilder NewBuilderForField<TField>(FieldDescriptor field) {
return NewBuilderForFieldImpl<TField>(field);
IBuilder IBuilder.NewBuilderForField(FieldDescriptor field) {
return NewBuilderForFieldImpl(field);
}
public IBuilder ClearField(FieldDescriptor field) {
return ClearFieldImpl();
IBuilder IBuilder.ClearField(FieldDescriptor field) {
return ClearFieldImpl(field);
}
public IBuilder AddRepeatedField(FieldDescriptor field, object value) {
IBuilder IBuilder.AddRepeatedField(FieldDescriptor field, object value) {
return AddRepeatedFieldImpl(field, value);
}
#endregion
public IBuilder Clear() {
foreach(FieldDescriptor field in AllFields.Keys) {
ClearField(field);
ClearFieldImpl(field);
}
return this;
}
......@@ -85,7 +85,7 @@ namespace Google.ProtocolBuffers {
if (field.IsRepeated) {
// Concatenate repeated fields
foreach (object element in (IEnumerable) entry.Value) {
AddRepeatedField(field, element);
AddRepeatedFieldImpl(field, element);
}
} else if (field.MappedType == MappedType.Message) {
// Merge singular messages
......
using System;
using System.Collections.Generic;
using System.Text;
namespace Google.ProtocolBuffers.Collections {
/// <summary>
/// Non-generic class with generic methods which proxy to the non-generic methods
/// in the generic class.
/// </summary>
public static class Dictionaries {
public static IDictionary<TKey, TValue> AsReadOnly<TKey, TValue> (IDictionary<TKey, TValue> dictionary) {
return dictionary.IsReadOnly ? dictionary : new ReadOnlyDictionary<TKey, TValue>(dictionary);
}
}
}
......@@ -4,18 +4,34 @@ using System.Collections.ObjectModel;
using System.Text;
namespace Google.ProtocolBuffers.Collections {
public static class Lists {
public static IList<T> AsReadOnly<T>(IList<T> list) {
return Lists<T>.AsReadOnly(list);
}
}
/// <summary>
/// Utilities class for dealing with lists.
/// </summary>
static class Lists<T> {
public static class Lists<T> {
static readonly ReadOnlyCollection<T> empty = new ReadOnlyCollection<T>(new T[0]);
/// <summary>
/// Returns an immutable empty list.
/// </summary>
internal static ReadOnlyCollection<T> Empty {
public static ReadOnlyCollection<T> Empty {
get { return empty; }
}
/// <summary>
/// Returns either the original reference if it's already read-only,
/// or a new ReadOnlyCollection wrapping the original list.
/// </summary>
public static IList<T> AsReadOnly(IList<T> list) {
return list.IsReadOnly ? list : new ReadOnlyCollection<T>(list);
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using IEnumerable=System.Collections.IEnumerable;
namespace Google.ProtocolBuffers.Collections {
/// <summary>
/// Read-only wrapper around another dictionary.
/// </summary>
public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue> {
readonly IDictionary<TKey, TValue> wrapped;
public ReadOnlyDictionary(IDictionary<TKey, TValue> wrapped) {
this.wrapped = wrapped;
}
public void Add(TKey key, TValue value) {
throw new InvalidOperationException();
}
public bool ContainsKey(TKey key) {
return wrapped.ContainsKey(key);
}
public ICollection<TKey> Keys {
get { return wrapped.Keys; }
}
public bool Remove(TKey key) {
throw new InvalidOperationException();
}
public bool TryGetValue(TKey key, out TValue value) {
return wrapped.TryGetValue(key, out value);
}
public ICollection<TValue> Values {
get { return wrapped.Values; }
}
public TValue this[TKey key] {
get {
return wrapped[key];
}
set {
throw new InvalidOperationException();
}
}
public void Add(KeyValuePair<TKey, TValue> item) {
throw new InvalidOperationException();
}
public void Clear() {
throw new InvalidOperationException();
}
public bool Contains(KeyValuePair<TKey, TValue> item) {
return wrapped.Contains(item);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
wrapped.CopyTo(array, arrayIndex);
}
public int Count {
get { return wrapped.Count; }
}
public bool IsReadOnly {
get { return true; }
}
public bool Remove(KeyValuePair<TKey, TValue> item) {
throw new InvalidOperationException();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
return wrapped.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return ((IEnumerable) wrapped).GetEnumerator();
}
public override bool Equals(object obj) {
return wrapped.Equals(obj);
}
public override int GetHashCode() {
return wrapped.GetHashCode();
}
public override string ToString() {
return wrapped.ToString();
}
}
}

namespace Google.ProtocolBuffers.Descriptors {
public class EnumDescriptor {
}
}
......@@ -2,8 +2,14 @@
namespace Google.ProtocolBuffers.Descriptors {
public class EnumValueDescriptor {
private EnumDescriptor enumDescriptor;
public int Number {
get { throw new NotImplementedException(); }
}
public EnumDescriptor EnumDescriptor {
get { return enumDescriptor; }
}
}
}

using System;
namespace Google.ProtocolBuffers.Descriptors {
public class FieldDescriptor {
private EnumDescriptor enumType;
public bool IsRequired {
get;
set;
......@@ -25,5 +29,32 @@ namespace Google.ProtocolBuffers.Descriptors {
public MessageDescriptor MessageType { get; set; }
public MessageDescriptor ExtensionScope { get; set; }
/// <summary>
/// For enum fields, returns the field's type.
/// </summary>
public EnumDescriptor EnumType {
get {
if (MappedType != MappedType.Enum) {
throw new InvalidOperationException("EnumType is only valid for enum fields.");
}
return enumType;
}
}
/// <summary>
/// The default value for this field. For repeated fields
/// this will always be an empty list. For message fields it will
/// always be null. For singular values, it will depend on the descriptor.
/// </summary>
public object DefaultValue
{
get { throw new NotImplementedException(); }
}
public string Name
{
get { throw new NotImplementedException(); }
}
}
}
......@@ -9,6 +9,8 @@ namespace Google.ProtocolBuffers.Descriptors {
public enum MappedType {
Int32,
Int64,
UInt32,
UInt64,
Single,
Double,
Boolean,
......
using System;
using System.Collections.Generic;
using System.Text;
namespace Google.ProtocolBuffers.FieldAccess {
namespace Google.ProtocolBuffers.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.
/// </summary>
internal interface IFieldAccessor<TMessage, TBuilder>
where TMessage : IMessage<TMessage>
where TBuilder : IBuilder<TMessage> {
void AddRepeated(IBuilder<TMessage> builder, object value);
/// <summary>
/// Indicates whether the specified message contains the field.
/// </summary>
bool Has(IMessage<TMessage> message);
/// <summary>
/// Gets the count of the repeated field in the specified message.
/// </summary>
int GetRepeatedCount(IMessage<TMessage> message);
void Clear(TBuilder builder);
TBuilder CreateBuilder();
/// <summary>
/// Clears the field in the specified builder.
/// </summary>
/// <param name="builder"></param>
void Clear(IBuilder<TMessage> builder);
/// <summary>
/// Creates a builder for the type of this field (which must be a message field).
/// </summary>
IBuilder CreateBuilder();
/// <summary>
/// Accessor for single fields
/// </summary>
object this[IMessage<TMessage> message] { get; }
object GetValue(IMessage<TMessage> message);
/// <summary>
/// Mutator for single fields
/// </summary>
object this[IBuilder<TMessage> builder] { set; }
void SetValue(IBuilder<TMessage> builder, object value);
/// <summary>
/// Accessor for repeated fields
/// </summary>
object this[IMessage<TMessage> message, int index] { get; }
object GetRepeatedValue(IMessage<TMessage> message, int index);
/// <summary>
/// Mutator for repeated fields
/// </summary>
object this[IBuilder<TMessage> builder, int index] { set; }
void SetRepeated(IBuilder<TMessage> builder, int index, object value);
/// <summary>
/// Adds the specified value to the field in the given builder.
/// </summary>
void AddRepeated(IBuilder<TMessage> builder, object value);
/// <summary>
/// Returns a read-only wrapper around the value of a repeated field.
/// </summary>
object GetRepeatedWrapper(IBuilder<TMessage> builder);
}
}
using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.FieldAccess {
internal class SingularFieldAccessor<TMessage, TBuilder> : IFieldAccessor<TMessage, TBuilder>
where TMessage : IMessage<TMessage>
where TBuilder : IBuilder<TMessage> {
readonly HasFunction<TMessage> hasProxy;
readonly Action<TBuilder> clearProxy;
internal SingularFieldAccessor(FieldDescriptor descriptor, String pascalCaseName) {
/* Class<? extends GeneratedMessage> messageClass,
Class<? extends GeneratedMessage.Builder> builderClass) {
getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
type = getMethod.getReturnType();
setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
hasMethod =
getMethodOrDie(messageClass, "has" + camelCaseName);
clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName); */
}
public bool Has(IMessage<TMessage> message) {
return false;// hasProxy(message);
}
public void Clear(TBuilder builder) {
// clearProxy(builder);
}
public TBuilder CreateBuilder() {
// return createBuilderProxy(builder);
return default(TBuilder);
}
public object this[IMessage<TMessage> message] {
get { return null;/* getProxy(message);*/ }
}
public object this[IBuilder<TMessage> builder] {
set { /*setProxy(builder, value);*/ }
}
#region Repeated operations (which just throw an exception)
public object this[IMessage<TMessage> message, int index] {
get { throw new InvalidOperationException("Repeated operation called on singular field"); }
}
public object this[IBuilder<TMessage> builder, int index] {
set { throw new InvalidOperationException("Repeated operation called on singular field"); }
}
public int GetRepeatedCount(IMessage<TMessage> message) {
throw new InvalidOperationException("Repeated operation called on singular field");
}
public void AddRepeated(IBuilder<TMessage> builder, object value) {
throw new InvalidOperationException("Repeated operation called on singular field");
}
#endregion
}
}
This diff is collapsed.
using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.Collections;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers {
/// <summary>
/// All generated protocol message builder classes extend this class. It implements
/// most of the IBuilder interface using reflection. Users can ignore this class
/// as an implementation detail.
/// </summary>
public abstract class GeneratedBuilder<TMessage, TBuilder> : AbstractBuilder, IBuilder<TMessage>
where TMessage : GeneratedMessage <TMessage, TBuilder>
where TBuilder : GeneratedBuilder<TMessage, TBuilder>, IBuilder<TMessage> {
/// <summary>
/// Returns the message being built at the moment.
/// </summary>
protected abstract GeneratedMessage<TMessage,TBuilder> MessageBeingBuilt { get; }
public override bool Initialized {
get { return MessageBeingBuilt.IsInitialized; }
}
public override IDictionary<FieldDescriptor, object> AllFields {
get { return MessageBeingBuilt.AllFields; }
}
public override object this[FieldDescriptor field] {
get {
// For repeated fields, the underlying list object is still modifiable at this point.
// Make sure not to expose the modifiable list to the caller.
return field.IsRepeated
? MessageBeingBuilt.InternalFieldAccessors[field].GetRepeatedWrapper(this)
: MessageBeingBuilt[field];
}
set {
MessageBeingBuilt.InternalFieldAccessors[field].SetValue(this, value);
}
}
public override MessageDescriptor DescriptorForType {
get { return MessageBeingBuilt.DescriptorForType; }
}
public override int GetRepeatedFieldCount(FieldDescriptor field) {
return MessageBeingBuilt.GetRepeatedFieldCount(field);
}
public override object this[FieldDescriptor field, int index] {
get { return MessageBeingBuilt[field, index]; }
set { MessageBeingBuilt.InternalFieldAccessors[field].SetRepeated(this, index, value); }
}
public override bool HasField(FieldDescriptor field) {
return MessageBeingBuilt.HasField(field);
}
protected override IMessage BuildImpl() {
return Build();
}
protected override IMessage BuildPartialImpl() {
return BuildPartial();
}
protected override IBuilder CloneImpl() {
return Clone();
}
protected override IMessage DefaultInstanceForTypeImpl {
get { return DefaultInstanceForType; }
}
protected override IBuilder NewBuilderForFieldImpl(FieldDescriptor field) {
return NewBuilderForField(field);
}
protected override IBuilder ClearFieldImpl(FieldDescriptor field) {
return ClearField(field);
}
protected override IBuilder AddRepeatedFieldImpl(FieldDescriptor field, object value) {
return AddRepeatedField(field, value);
}
public new abstract IBuilder<TMessage> Clear();
public IBuilder<TMessage> MergeFrom(IMessage<TMessage> other) {
throw new NotImplementedException();
}
public abstract IMessage<TMessage> Build();
public abstract IMessage<TMessage> BuildPartial();
public abstract IBuilder<TMessage> Clone();
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(CodedInputStream input) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
throw new NotImplementedException();
}
public IMessage<TMessage> DefaultInstanceForType {
get { throw new NotImplementedException(); }
}
public IBuilder NewBuilderForField(FieldDescriptor field) {
throw new NotImplementedException();
}
public IBuilder<TMessage> ClearField(FieldDescriptor field) {
MessageBeingBuilt.InternalFieldAccessors[field].Clear(this);
return this;
}
public IBuilder<TMessage> AddRepeatedField(FieldDescriptor field, object value) {
return this;
}
public new IBuilder<TMessage> MergeUnknownFields(UnknownFieldSet unknownFields) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(ByteString data) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(ByteString data, ExtensionRegistry extensionRegistry) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(byte[] data) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(byte[] data, ExtensionRegistry extensionRegistry) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(System.IO.Stream input) {
throw new NotImplementedException();
}
IBuilder<TMessage> IBuilder<TMessage>.MergeFrom(System.IO.Stream input, ExtensionRegistry extensionRegistry) {
throw new NotImplementedException();
}
}
}
using System;
using System.Collections.Generic;
using Google.ProtocolBuffers.Collections;
using Google.ProtocolBuffers.Descriptors;
using Google.ProtocolBuffers.FieldAccess;
......@@ -7,7 +8,7 @@ namespace Google.ProtocolBuffers {
/// <summary>
/// All generated protocol message classes extend this class. It implements
/// most of the IMessage and IBuilder interfaces using reflection. Users
/// most of the IMessage interface using reflection. Users
/// can ignore this class as an implementation detail.
/// </summary>
public abstract class GeneratedMessage<TMessage, TBuilder> : AbstractMessage, IMessage<TMessage>
......@@ -15,7 +16,7 @@ namespace Google.ProtocolBuffers {
private readonly UnknownFieldSet unknownFields = UnknownFieldSet.DefaultInstance;
protected abstract FieldAccessorTable<TMessage, TBuilder> InternalFieldAccessors { get; }
protected internal abstract FieldAccessorTable<TMessage, TBuilder> InternalFieldAccessors { get; }
public override MessageDescriptor DescriptorForType {
get { return InternalFieldAccessors.Descriptor; }
......@@ -38,21 +39,22 @@ namespace Google.ProtocolBuffers {
}
private IDictionary<FieldDescriptor, Object> GetMutableFieldMap() {
var ret = new Dictionary<FieldDescriptor, object>();
// Use a SortedList so we'll end up serializing fields in order
var ret = new SortedList<FieldDescriptor, object>();
MessageDescriptor descriptor = DescriptorForType;
foreach (FieldDescriptor field in descriptor.Fields) {
IFieldAccessor<TMessage, TBuilder> accessor = InternalFieldAccessors[field];
if ((field.IsRepeated && accessor.GetRepeatedCount(this) != 0)
|| accessor.Has(this)) {
ret[field] = accessor[this];
ret[field] = accessor.GetValue(this);
}
}
return ret;
}
public override IDictionary<FieldDescriptor, object> AllFields {
// FIXME: Make it immutable
get { return GetMutableFieldMap(); }
get { return Dictionaries.AsReadOnly(GetMutableFieldMap()); }
}
public override bool HasField(FieldDescriptor field) {
......@@ -64,11 +66,11 @@ namespace Google.ProtocolBuffers {
}
public override object this[FieldDescriptor field, int index] {
get { return InternalFieldAccessors[field][this, index]; }
get { return InternalFieldAccessors[field].GetRepeatedValue(this, index); }
}
public override object this[FieldDescriptor field] {
get { return InternalFieldAccessors[field][this]; }
get { return InternalFieldAccessors[field].GetValue(this); }
}
public override UnknownFieldSet UnknownFields {
......
......@@ -88,7 +88,7 @@ namespace Google.ProtocolBuffers {
IBuilder MergeFrom(CodedInputStream input);
IBuilder MergeFrom(CodedInputStream codedInputStream, ExtensionRegistry extensionRegistry);
IMessage DefaultInstanceForType { get; }
IBuilder NewBuilderForField<TField>(FieldDescriptor field);
IBuilder NewBuilderForField(FieldDescriptor field);
IBuilder ClearField(FieldDescriptor field);
IBuilder AddRepeatedField(FieldDescriptor field, object value);
IBuilder MergeUnknownFields(UnknownFieldSet unknownFields);
......@@ -191,7 +191,7 @@ namespace Google.ProtocolBuffers {
/// Messages built with this can then be passed to the various mutation properties
/// and methods.
/// </summary>
new IBuilder<TField> NewBuilderForField<TField>(FieldDescriptor field) where TField : IMessage<TField>;
//new IBuilder<TField> NewBuilderForField<TField>(FieldDescriptor field) where TField : IMessage<TField>;
/// <summary>
/// Clears the field. This is exactly equivalent to calling the generated
......
......@@ -42,7 +42,10 @@
<Compile Include="ByteString.cs" />
<Compile Include="CodedInputStream.cs" />
<Compile Include="CodedOutputStream.cs" />
<Compile Include="Collections\Dictionaries.cs" />
<Compile Include="Collections\Lists.cs" />
<Compile Include="Collections\ReadOnlyDictionary.cs" />
<Compile Include="Descriptors\EnumDescriptor.cs" />
<Compile Include="Descriptors\EnumValueDescriptor.cs" />
<Compile Include="Descriptors\FieldDescriptor.cs" />
<Compile Include="Descriptors\FieldType.cs" />
......@@ -53,8 +56,8 @@
<Compile Include="FieldAccess\Delegates.cs" />
<Compile Include="FieldAccess\IFieldAccessor.cs" />
<Compile Include="FieldAccess\FieldAccessorTable.cs" />
<Compile Include="FieldAccess\SingularFieldAccessor.cs" />
<Compile Include="FieldSet.cs" />
<Compile Include="GeneratedBuilder.cs" />
<Compile Include="GeneratedExtension.cs" />
<Compile Include="GeneratedMessage.cs" />
<Compile Include="IBuilder.cs" />
......
......@@ -16,6 +16,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using Google.ProtocolBuffers.Collections;
namespace Google.ProtocolBuffers {
public class UnknownFieldSet {
......@@ -48,10 +49,10 @@ namespace Google.ProtocolBuffers {
}
/// <summary>
/// Creates and returns a copy of the mapping from field numbers to values.
/// Returns a read-only view of the mapping from field numbers to values.
/// </summary>
public IDictionary<int, UnknownField> FieldDictionary {
get { return new Dictionary<int, UnknownField>(fields); }
get { return Dictionaries.AsReadOnly(fields); }
}
/// <summary>
......@@ -195,7 +196,11 @@ namespace Google.ProtocolBuffers {
public class Builder
{
private Dictionary<int, UnknownField> fields = new Dictionary<int, UnknownField>();
/// <summary>
/// Mapping from number to field. Note that by using a SortedList we ensure
/// that the fields will be serialized in ascending order.
/// </summary>
private IDictionary<int, UnknownField> fields = new SortedList<int, UnknownField>();
// Optimization: We keep around a builder for the last field that was
// modified so that we can efficiently add to it multiple times in a
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment