From 9f4f0a56b1a87af398d0fd9e9bff87e62609b0f7 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Thu, 14 Aug 2008 20:33:36 +0100 Subject: [PATCH] Descriptor framework skeleton. Somewhat generic to avoid lots of code duplication. --- csharp/ProtocolBuffers/Autogenerated.cs | 15 -- .../DescriptorProtos/Autogenerated.cs | 147 ++++++++++++++++++ .../DescriptorProtos/IDescriptorProto.cs | 22 +++ .../DescriptorProtos/PartialClasses.cs | 16 ++ .../Descriptors/DescriptorBase.cs | 54 +++++++ .../Descriptors/EnumDescriptor.cs | 7 +- .../Descriptors/EnumValueDescriptor.cs | 11 +- .../Descriptors/FieldDescriptor.cs | 29 ++-- .../Descriptors/FileDescriptor.cs | 7 +- .../Descriptors/IndexedDescriptorBase.cs | 31 ++++ .../Descriptors/MessageDescriptor.cs | 8 +- .../Descriptors/ServiceDescriptor.cs | 12 ++ csharp/ProtocolBuffers/FieldSet.cs | 63 +++++++- csharp/ProtocolBuffers/ProtocolBuffers.csproj | 7 +- 14 files changed, 382 insertions(+), 47 deletions(-) delete mode 100644 csharp/ProtocolBuffers/Autogenerated.cs create mode 100644 csharp/ProtocolBuffers/DescriptorProtos/Autogenerated.cs create mode 100644 csharp/ProtocolBuffers/DescriptorProtos/IDescriptorProto.cs create mode 100644 csharp/ProtocolBuffers/DescriptorProtos/PartialClasses.cs create mode 100644 csharp/ProtocolBuffers/Descriptors/DescriptorBase.cs create mode 100644 csharp/ProtocolBuffers/Descriptors/IndexedDescriptorBase.cs create mode 100644 csharp/ProtocolBuffers/Descriptors/ServiceDescriptor.cs diff --git a/csharp/ProtocolBuffers/Autogenerated.cs b/csharp/ProtocolBuffers/Autogenerated.cs deleted file mode 100644 index e4aee669f..000000000 --- a/csharp/ProtocolBuffers/Autogenerated.cs +++ /dev/null @@ -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 { - } - } -} diff --git a/csharp/ProtocolBuffers/DescriptorProtos/Autogenerated.cs b/csharp/ProtocolBuffers/DescriptorProtos/Autogenerated.cs new file mode 100644 index 000000000..79d78632c --- /dev/null +++ b/csharp/ProtocolBuffers/DescriptorProtos/Autogenerated.cs @@ -0,0 +1,147 @@ +// This file contains quick hacks to represent code that will be autogenerated. + +namespace Google.ProtocolBuffers.DescriptorProtos { + + /// + /// This only exists until we've got the real code... + /// + public abstract class TemporaryMessage : IMessage where T : IMessage { + #region IMessage Members + + public IMessage DefaultInstanceForType { + get { throw new System.NotImplementedException(); } + } + + public IBuilder 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 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 { + public bool IsMessageSetWireFormat; + } + + public partial class DescriptorProto : TemporaryMessage { + public string Name { get; set; } + public string FullName { get; set; } + public MessageOptions Options { get; set; } + } + + public partial class EnumDescriptorProto : TemporaryMessage { + public string Name { get; set; } + public string FullName { get; set; } + public EnumOptions Options { get; set; } + } + + public partial class EnumOptions : TemporaryMessage { } + + public partial class EnumValueDescriptorProto : TemporaryMessage { + public string Name { get; set; } + public string FullName { get; set; } + public EnumValueOptions Options { get; set; } + } + + public partial class EnumValueOptions : TemporaryMessage { } + + public partial class FieldDescriptorProto : TemporaryMessage { + public string Name { get; set; } + public string FullName { get; set; } + public FieldOptions Options { get; set; } + + } + + public partial class FieldOptions : TemporaryMessage { } + + public partial class FileDescriptorProto : TemporaryMessage { + public string Name { get; set; } + public string FullName { get; set; } + public FileOptions Options { get; set; } + + } + + public partial class FileOptions : TemporaryMessage { } + + public partial class MethodDescriptorProto : TemporaryMessage { + public string Name { get; set; } + public string FullName { get; set; } + public MethodOptions Options { get; set; } + + } + + public partial class MethodOptions : TemporaryMessage { } + + public partial class ServiceDescriptorProto : TemporaryMessage { + public string Name { get; set; } + public string FullName { get; set; } + public ServiceOptions Options { get; set; } + + } + + public partial class ServiceOptions : TemporaryMessage { } +} diff --git a/csharp/ProtocolBuffers/DescriptorProtos/IDescriptorProto.cs b/csharp/ProtocolBuffers/DescriptorProtos/IDescriptorProto.cs new file mode 100644 index 000000000..1bd415ceb --- /dev/null +++ b/csharp/ProtocolBuffers/DescriptorProtos/IDescriptorProto.cs @@ -0,0 +1,22 @@ +namespace Google.ProtocolBuffers.DescriptorProtos { + + /// + /// 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. + /// + /// The associated options protocol buffer type + public interface IDescriptorProto { + /// + /// The fully qualified name of the descriptor's target. + /// + string FullName { get; } + + /// + /// The brief name of the descriptor's target. + /// + string Name { get; } + + TOptions Options { get; } + } +} diff --git a/csharp/ProtocolBuffers/DescriptorProtos/PartialClasses.cs b/csharp/ProtocolBuffers/DescriptorProtos/PartialClasses.cs new file mode 100644 index 000000000..46edb7b17 --- /dev/null +++ b/csharp/ProtocolBuffers/DescriptorProtos/PartialClasses.cs @@ -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 { } + public partial class EnumDescriptorProto : IDescriptorProto { } + public partial class EnumValueDescriptorProto : IDescriptorProto { } + public partial class FieldDescriptorProto : IDescriptorProto { } + public partial class FileDescriptorProto : IDescriptorProto { } + public partial class MethodDescriptorProto : IDescriptorProto { } + public partial class ServiceDescriptorProto : IDescriptorProto { } +} diff --git a/csharp/ProtocolBuffers/Descriptors/DescriptorBase.cs b/csharp/ProtocolBuffers/Descriptors/DescriptorBase.cs new file mode 100644 index 000000000..bb0f32dfb --- /dev/null +++ b/csharp/ProtocolBuffers/Descriptors/DescriptorBase.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Google.ProtocolBuffers.DescriptorProtos; + +namespace Google.ProtocolBuffers.Descriptors { + /// + /// Base class for all descriptors, providing common functionality. + /// + /// Type of the protocol buffer form of this descriptor + /// Type of the options protocol buffer for this descriptor + public abstract class DescriptorBase where TProto : IMessage, IDescriptorProto { + + private readonly TProto proto; + private readonly FileDescriptor file; + + protected DescriptorBase(TProto proto, FileDescriptor file) { + this.proto = proto; + this.file = file; + } + + /// + /// Returns the protocol buffer form of this descriptor + /// + public TProto Proto { + get { return proto; } + } + + public TOptions Options { + get { return proto.Options; } + } + + /// + /// The fully qualified name of the descriptor's target. + /// + public string FullName { + get { return proto.FullName; } + } + + /// + /// The brief name of the descriptor's target. + /// + public string Name { + get { return proto.Name; } + } + + /// + /// The file this descriptor was declared in. + /// + public FileDescriptor File { + get { return file; } + } + } +} diff --git a/csharp/ProtocolBuffers/Descriptors/EnumDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/EnumDescriptor.cs index 2d27b1f05..1ebe5a7e8 100644 --- a/csharp/ProtocolBuffers/Descriptors/EnumDescriptor.cs +++ b/csharp/ProtocolBuffers/Descriptors/EnumDescriptor.cs @@ -1,6 +1,11 @@  +using Google.ProtocolBuffers.DescriptorProtos; namespace Google.ProtocolBuffers.Descriptors { - public class EnumDescriptor { + public class EnumDescriptor : IndexedDescriptorBase { + internal EnumDescriptor(EnumDescriptorProto proto, EnumOptions options, FileDescriptor file, int index) + : base(proto, file, index) { + } + internal EnumValueDescriptor FindValueByNumber(int rawValue) { throw new System.NotImplementedException(); } diff --git a/csharp/ProtocolBuffers/Descriptors/EnumValueDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/EnumValueDescriptor.cs index faa83fd43..94bd68bf3 100644 --- a/csharp/ProtocolBuffers/Descriptors/EnumValueDescriptor.cs +++ b/csharp/ProtocolBuffers/Descriptors/EnumValueDescriptor.cs @@ -1,17 +1,18 @@ using System; +using Google.ProtocolBuffers.DescriptorProtos; namespace Google.ProtocolBuffers.Descriptors { - public class EnumValueDescriptor { + public class EnumValueDescriptor : IndexedDescriptorBase { - 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(); } } diff --git a/csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs index cd2f19b15..0cfc723d0 100644 --- a/csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs +++ b/csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs @@ -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 { - 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(); } - } - /// /// Immutable mapping from field type to mapped type. Built using the attributes on /// FieldType values. diff --git a/csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs index 0aaca8864..38038ee03 100644 --- a/csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs +++ b/csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs @@ -1,4 +1,7 @@ -namespace Google.ProtocolBuffers.Descriptors { - class FileDescriptor { +using Google.ProtocolBuffers.DescriptorProtos; +namespace Google.ProtocolBuffers.Descriptors { + public class FileDescriptor : DescriptorBase { + public FileDescriptor(FileDescriptorProto proto, FileDescriptor file) : base(proto, file) { + } } } diff --git a/csharp/ProtocolBuffers/Descriptors/IndexedDescriptorBase.cs b/csharp/ProtocolBuffers/Descriptors/IndexedDescriptorBase.cs new file mode 100644 index 000000000..b94521635 --- /dev/null +++ b/csharp/ProtocolBuffers/Descriptors/IndexedDescriptorBase.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Google.ProtocolBuffers.DescriptorProtos; + +namespace Google.ProtocolBuffers.Descriptors { + /// + /// Base class for descriptors which are also indexed. This is all of them other than + /// . + /// + public abstract class IndexedDescriptorBase : DescriptorBase + where TProto : IMessage, IDescriptorProto { + + private readonly int index; + + protected IndexedDescriptorBase(TProto proto, FileDescriptor file, int index) + : base(proto, file) { + this.index = index; + } + + /// + /// The index of this descriptor within its parent descriptor. + /// + /// + /// TODO(jonskeet): Transcribe appropriately. + /// + public int Index { + get { return index; } + } + } +} diff --git a/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs index df2972f64..971bc3eb1 100644 --- a/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs +++ b/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs @@ -1,11 +1,13 @@  using System.Collections.Generic; +using Google.ProtocolBuffers.DescriptorProtos; namespace Google.ProtocolBuffers.Descriptors { - public class MessageDescriptor { + public class MessageDescriptor : DescriptorBase { public IList 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(); diff --git a/csharp/ProtocolBuffers/Descriptors/ServiceDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/ServiceDescriptor.cs new file mode 100644 index 000000000..dbe93f99f --- /dev/null +++ b/csharp/ProtocolBuffers/Descriptors/ServiceDescriptor.cs @@ -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 { + public ServiceDescriptor(ServiceDescriptorProto proto, FileDescriptor file, int index) + : base(proto, file, index) { + } + } +} diff --git a/csharp/ProtocolBuffers/FieldSet.cs b/csharp/ProtocolBuffers/FieldSet.cs index 4ad944179..0bcbca817 100644 --- a/csharp/ProtocolBuffers/FieldSet.cs +++ b/csharp/ProtocolBuffers/FieldSet.cs @@ -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? /// /// Like /// but parses a single field. /// /// The input to read the field from - /// The set of unknown fields to add the newly-read field to + /// The set of unknown fields to add the newly-read field to, if it's not a known field /// Registry to use when an extension field is encountered - /// A builder (???) + /// Builder to merge field into, if it's a known field /// The tag, which should already have been read from the input /// true unless the tag is an end-group tag 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? /// /// Called by MergeFieldFrom to parse a MessageSet extension. /// @@ -511,6 +511,59 @@ namespace Google.ProtocolBuffers { MergeFields(other.fields); } + /// + /// See . + /// + public void WriteTo(CodedOutputStream output) { + foreach (KeyValuePair entry in fields) { + WriteField(entry.Key, entry.Value, output); + } + } + + /// + /// Writes a single field to a CodedOutputStream. + /// + 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); + } + } + } + + /// + /// See . It's up to the caller to + /// cache the resulting size if desired. + /// + public int SerializedSize { + get { + int size = 0; + foreach (KeyValuePair 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; + } + } + /// /// Verifies that the given object is of the correct type to be a valid /// value for the given field. diff --git a/csharp/ProtocolBuffers/ProtocolBuffers.csproj b/csharp/ProtocolBuffers/ProtocolBuffers.csproj index d3cd95f6d..5f31a9e73 100644 --- a/csharp/ProtocolBuffers/ProtocolBuffers.csproj +++ b/csharp/ProtocolBuffers/ProtocolBuffers.csproj @@ -38,21 +38,26 @@ - + + + + + +