Descriptor framework skeleton. Somewhat generic to avoid lots of code duplication.

This commit is contained in:
Jon Skeet 2008-08-14 20:33:36 +01:00
parent c0daf10724
commit 9f4f0a56b1
14 changed files with 382 additions and 47 deletions

View File

@ -1,15 +0,0 @@
// This file contains quick hacks to represent code that will be autogenerated.
namespace Google.ProtocolBuffers {
public class DescriptorProtos {
public class MessageOptions {
public bool IsMessageSetWireFormat;
}
public class EnumValueDescriptorProto {
}
public class FieldDescriptorProto {
}
}
}

View File

@ -0,0 +1,147 @@
// This file contains quick hacks to represent code that will be autogenerated.
namespace Google.ProtocolBuffers.DescriptorProtos {
/// <summary>
/// This only exists until we've got the real code...
/// </summary>
public abstract class TemporaryMessage<T> : IMessage<T> where T : IMessage<T> {
#region IMessage<T> Members
public IMessage<T> DefaultInstanceForType {
get { throw new System.NotImplementedException(); }
}
public IBuilder<T> CreateBuilderForType() {
throw new System.NotImplementedException();
}
#endregion
#region IMessage Members
public Google.ProtocolBuffers.Descriptors.MessageDescriptor DescriptorForType {
get { throw new System.NotImplementedException(); }
}
public System.Collections.Generic.IDictionary<Google.ProtocolBuffers.Descriptors.FieldDescriptor, object> AllFields {
get { throw new System.NotImplementedException(); }
}
public bool HasField(Google.ProtocolBuffers.Descriptors.FieldDescriptor field) {
throw new System.NotImplementedException();
}
public object this[Google.ProtocolBuffers.Descriptors.FieldDescriptor field] {
get { throw new System.NotImplementedException(); }
}
public int GetRepeatedFieldCount(Google.ProtocolBuffers.Descriptors.FieldDescriptor field) {
throw new System.NotImplementedException();
}
public object this[Google.ProtocolBuffers.Descriptors.FieldDescriptor field, int index] {
get { throw new System.NotImplementedException(); }
}
public UnknownFieldSet UnknownFields {
get { throw new System.NotImplementedException(); }
}
public bool IsInitialized {
get { throw new System.NotImplementedException(); }
}
public void WriteTo(CodedOutputStream output) {
throw new System.NotImplementedException();
}
public int SerializedSize {
get { throw new System.NotImplementedException(); }
}
public ByteString ToByteString() {
throw new System.NotImplementedException();
}
public byte[] ToByteArray() {
throw new System.NotImplementedException();
}
public void WriteTo(System.IO.Stream output) {
throw new System.NotImplementedException();
}
IMessage IMessage.DefaultInstanceForType {
get { throw new System.NotImplementedException(); }
}
IBuilder IMessage.CreateBuilderForType() {
throw new System.NotImplementedException();
}
#endregion
}
public partial class MessageOptions : TemporaryMessage<MessageOptions> {
public bool IsMessageSetWireFormat;
}
public partial class DescriptorProto : TemporaryMessage<DescriptorProto> {
public string Name { get; set; }
public string FullName { get; set; }
public MessageOptions Options { get; set; }
}
public partial class EnumDescriptorProto : TemporaryMessage<EnumDescriptorProto> {
public string Name { get; set; }
public string FullName { get; set; }
public EnumOptions Options { get; set; }
}
public partial class EnumOptions : TemporaryMessage<EnumOptions> { }
public partial class EnumValueDescriptorProto : TemporaryMessage<EnumValueDescriptorProto> {
public string Name { get; set; }
public string FullName { get; set; }
public EnumValueOptions Options { get; set; }
}
public partial class EnumValueOptions : TemporaryMessage <EnumValueOptions> { }
public partial class FieldDescriptorProto : TemporaryMessage<FieldDescriptorProto> {
public string Name { get; set; }
public string FullName { get; set; }
public FieldOptions Options { get; set; }
}
public partial class FieldOptions : TemporaryMessage<FieldOptions> { }
public partial class FileDescriptorProto : TemporaryMessage<FileDescriptorProto> {
public string Name { get; set; }
public string FullName { get; set; }
public FileOptions Options { get; set; }
}
public partial class FileOptions : TemporaryMessage<FileOptions> { }
public partial class MethodDescriptorProto : TemporaryMessage<MethodDescriptorProto> {
public string Name { get; set; }
public string FullName { get; set; }
public MethodOptions Options { get; set; }
}
public partial class MethodOptions : TemporaryMessage<MethodOptions> { }
public partial class ServiceDescriptorProto : TemporaryMessage<ServiceDescriptorProto> {
public string Name { get; set; }
public string FullName { get; set; }
public ServiceOptions Options { get; set; }
}
public partial class ServiceOptions : TemporaryMessage<ServiceOptions> { }
}

View File

@ -0,0 +1,22 @@
namespace Google.ProtocolBuffers.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 fully qualified name of the descriptor's target.
/// </summary>
string FullName { get; }
/// <summary>
/// The brief name of the descriptor's target.
/// </summary>
string Name { get; }
TOptions Options { get; }
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
// This class just contains partial classes for each of the
// autogenerated classes, so that they implement
// IDescriptorProto
namespace Google.ProtocolBuffers.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> { }
}

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.DescriptorProtos;
namespace Google.ProtocolBuffers.Descriptors {
/// <summary>
/// Base class for 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> where TProto : IMessage<TProto>, IDescriptorProto<TOptions> {
private readonly TProto proto;
private readonly FileDescriptor file;
protected DescriptorBase(TProto proto, FileDescriptor file) {
this.proto = proto;
this.file = file;
}
/// <summary>
/// Returns the protocol buffer form of this descriptor
/// </summary>
public TProto Proto {
get { return proto; }
}
public TOptions Options {
get { return proto.Options; }
}
/// <summary>
/// The fully qualified name of the descriptor's target.
/// </summary>
public string FullName {
get { return proto.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>
public FileDescriptor File {
get { return file; }
}
}
}

View File

@ -1,6 +1,11 @@

using Google.ProtocolBuffers.DescriptorProtos;
namespace Google.ProtocolBuffers.Descriptors {
public class EnumDescriptor {
public class EnumDescriptor : IndexedDescriptorBase<EnumDescriptorProto, EnumOptions> {
internal EnumDescriptor(EnumDescriptorProto proto, EnumOptions options, FileDescriptor file, int index)
: base(proto, file, index) {
}
internal EnumValueDescriptor FindValueByNumber(int rawValue) {
throw new System.NotImplementedException();
}

View File

@ -1,17 +1,18 @@
using System;
using Google.ProtocolBuffers.DescriptorProtos;
namespace Google.ProtocolBuffers.Descriptors {
public class EnumValueDescriptor {
public class EnumValueDescriptor : IndexedDescriptorBase<EnumValueDescriptorProto, EnumValueOptions> {
internal EnumValueDescriptor(DescriptorProtos.EnumValueDescriptorProto proto,
private readonly EnumDescriptor enumDescriptor;
internal EnumValueDescriptor(EnumValueDescriptorProto proto,
FileDescriptor file,
EnumDescriptor parent,
int index) {
int index) : base (proto, file, index) {
enumDescriptor = parent;
}
private EnumDescriptor enumDescriptor;
public int Number {
get { throw new NotImplementedException(); }
}

View File

@ -2,20 +2,23 @@
using System.Collections.Generic;
using System.Reflection;
using Google.ProtocolBuffers.Collections;
using Google.ProtocolBuffers.DescriptorProtos;
namespace Google.ProtocolBuffers.Descriptors {
public class FieldDescriptor {
public class FieldDescriptor : IndexedDescriptorBase<FieldDescriptorProto, FieldOptions> {
private FieldDescriptor(DescriptorProtos.FieldDescriptorProto proto,
FileDescriptor file,
MessageDescriptor parent,
int index,
bool isExtension) {
private readonly EnumDescriptor enumType;
private readonly MessageDescriptor parent;
internal FieldDescriptor(FieldDescriptorProto proto,
FileDescriptor file,
MessageDescriptor parent,
int index,
bool isExtension) : base(proto, file, index) {
enumType = null;
this.parent = parent;
}
private EnumDescriptor enumType;
public bool IsRequired {
get;
set;
@ -30,9 +33,9 @@ namespace Google.ProtocolBuffers.Descriptors {
public bool IsExtension { get; set; }
public MessageDescriptor ContainingType { get; set; }
public string FullName { get; set; }
public MessageDescriptor ContainingType {
get { return parent; }
}
public bool IsOptional { get; set; }
@ -61,10 +64,6 @@ namespace Google.ProtocolBuffers.Descriptors {
get { throw new NotImplementedException(); }
}
public string Name {
get { throw new NotImplementedException(); }
}
/// <summary>
/// Immutable mapping from field type to mapped type. Built using the attributes on
/// FieldType values.

View File

@ -1,4 +1,7 @@
namespace Google.ProtocolBuffers.Descriptors {
class FileDescriptor {
using Google.ProtocolBuffers.DescriptorProtos;
namespace Google.ProtocolBuffers.Descriptors {
public class FileDescriptor : DescriptorBase<FileDescriptorProto, FileOptions> {
public FileDescriptor(FileDescriptorProto proto, FileDescriptor file) : base(proto, file) {
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.DescriptorProtos;
namespace Google.ProtocolBuffers.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, int index)
: base(proto, file) {
this.index = index;
}
/// <value>
/// The index of this descriptor within its parent descriptor.
/// </value>
/// <remarks>
/// TODO(jonskeet): Transcribe appropriately.
/// </remarks>
public int Index {
get { return index; }
}
}
}

View File

@ -1,11 +1,13 @@

using System.Collections.Generic;
using Google.ProtocolBuffers.DescriptorProtos;
namespace Google.ProtocolBuffers.Descriptors {
public class MessageDescriptor {
public class MessageDescriptor : DescriptorBase<DescriptorProto, MessageOptions> {
public IList<FieldDescriptor> Fields;
public DescriptorProtos.MessageOptions Options;
public string FullName;
internal MessageDescriptor(DescriptorProto proto, FileDescriptor file) : base(proto, file) {
}
internal bool IsExtensionNumber(int fieldNumber) {
throw new System.NotImplementedException();

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.DescriptorProtos;
namespace Google.ProtocolBuffers.Descriptors {
public class ServiceDescriptor : IndexedDescriptorBase<ServiceDescriptorProto, ServiceOptions> {
public ServiceDescriptor(ServiceDescriptorProto proto, FileDescriptor file, int index)
: base(proto, file, index) {
}
}
}

View File

@ -84,7 +84,7 @@ namespace Google.ProtocolBuffers {
return fields.ContainsKey(field);
}
// TODO(jonskeet): Should this be in UnknownFieldSet.Builder really?
// TODO(jonskeet): Should this be in UnknownFieldSet.Builder really? Or CodedInputStream?
internal static void MergeFrom(CodedInputStream input,
UnknownFieldSet.Builder unknownFields,
ExtensionRegistry extensionRegistry,
@ -103,15 +103,15 @@ namespace Google.ProtocolBuffers {
}
}
// TODO(jonskeet): Should this be in UnknownFieldSet.Builder really?
// TODO(jonskeet): Should this be in UnknownFieldSet.Builder really? Or CodedInputStream?
/// <summary>
/// Like <see cref="MergeFrom(CodedInputStream, UnknownFieldSet.Builder, ExtensionRegistry, IBuilder)" />
/// but parses a single field.
/// </summary>
/// <param name="input">The input to read the field from</param>
/// <param name="unknownFields">The set of unknown fields to add the newly-read field to</param>
/// <param name="unknownFields">The set of unknown fields to add the newly-read field to, if it's not a known field</param>
/// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
/// <param name="builder">A builder (???)</param>
/// <param name="builder">Builder to merge field into, if it's a known field</param>
/// <param name="tag">The tag, which should already have been read from the input</param>
/// <returns>true unless the tag is an end-group tag</returns>
internal static bool MergeFieldFrom(CodedInputStream input,
@ -194,7 +194,7 @@ namespace Google.ProtocolBuffers {
return true;
}
// TODO(jonskeet): Move to UnknownFieldSet.Builder?
// TODO(jonskeet): Should this be in UnknownFieldSet.Builder really? Or CodedInputStream?
/// <summary>
/// Called by MergeFieldFrom to parse a MessageSet extension.
/// </summary>
@ -511,6 +511,59 @@ namespace Google.ProtocolBuffers {
MergeFields(other.fields);
}
/// <summary>
/// See <see cref="IMessage.WriteTo(CodedOutputStream)" />.
/// </summary>
public void WriteTo(CodedOutputStream output) {
foreach (KeyValuePair<FieldDescriptor, object> entry in fields) {
WriteField(entry.Key, entry.Value, output);
}
}
/// <summary>
/// Writes a single field to a CodedOutputStream.
/// </summary>
public void WriteField(FieldDescriptor field, Object value, CodedOutputStream output) {
if (field.IsExtension && field.ContainingType.Options.IsMessageSetWireFormat) {
output.WriteMessageSetExtension(field.FieldNumber, (IMessage) value);
} else {
if (field.IsRepeated) {
foreach (object element in (IEnumerable) value) {
output.WriteField(field.FieldType, field.FieldNumber, element);
}
} else {
output.WriteField(field.FieldType, field.FieldNumber, value);
}
}
}
/// <summary>
/// See <see cref="IMessage.SerializedSize" />. It's up to the caller to
/// cache the resulting size if desired.
/// </summary>
public int SerializedSize {
get {
int size = 0;
foreach (KeyValuePair<FieldDescriptor, object> entry in fields) {
FieldDescriptor field = entry.Key;
object value = entry.Value;
if (field.IsExtension && field.ContainingType.Options.IsMessageSetWireFormat) {
size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessage) value);
} else {
if (field.IsRepeated) {
foreach (object element in (IEnumerable) value) {
size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
}
} else {
size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, value);
}
}
}
return size;
}
}
/// <summary>
/// Verifies that the given object is of the correct type to be a valid
/// value for the given field.

View File

@ -38,21 +38,26 @@
<ItemGroup>
<Compile Include="AbstractBuilder.cs" />
<Compile Include="AbstractMessage.cs" />
<Compile Include="Autogenerated.cs" />
<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="DescriptorProtos\Autogenerated.cs" />
<Compile Include="DescriptorProtos\IDescriptorProto.cs" />
<Compile Include="DescriptorProtos\PartialClasses.cs" />
<Compile Include="Descriptors\DescriptorBase.cs" />
<Compile Include="Descriptors\EnumDescriptor.cs" />
<Compile Include="Descriptors\EnumValueDescriptor.cs" />
<Compile Include="Descriptors\FieldDescriptor.cs" />
<Compile Include="Descriptors\FieldMappingAttribute.cs" />
<Compile Include="Descriptors\FieldType.cs" />
<Compile Include="Descriptors\FileDescriptor.cs" />
<Compile Include="Descriptors\IndexedDescriptorBase.cs" />
<Compile Include="Descriptors\MappedType.cs" />
<Compile Include="Descriptors\MessageDescriptor.cs" />
<Compile Include="Descriptors\ServiceDescriptor.cs" />
<Compile Include="ExtensionInfo.cs" />
<Compile Include="ExtensionRegistry.cs" />
<Compile Include="FieldAccess\Delegates.cs" />