Browse Source

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

Jon Skeet 17 years ago
parent
commit
9f4f0a56b1

+ 0 - 15
csharp/ProtocolBuffers/Autogenerated.cs

@@ -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 {
-    }
-  }
-}

+ 147 - 0
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 {
+
+  /// <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> { }
+}

+ 22 - 0
csharp/ProtocolBuffers/DescriptorProtos/IDescriptorProto.cs

@@ -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; }
+  }
+}

+ 16 - 0
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<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> { }
+}

+ 54 - 0
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 {
+  /// <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; }
+    }
+  }
+}

+ 6 - 1
csharp/ProtocolBuffers/Descriptors/EnumDescriptor.cs

@@ -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();
     }

+ 6 - 5
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<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(); }
     }

+ 14 - 15
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<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.

+ 5 - 2
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<FileDescriptorProto, FileOptions> {
+    public FileDescriptor(FileDescriptorProto proto, FileDescriptor file) : base(proto, file) {
+    }
   }
 }

+ 31 - 0
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 {
+  /// <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; }
+    }
+  }
+}

+ 5 - 3
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<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();

+ 12 - 0
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<ServiceDescriptorProto, ServiceOptions> {
+    public ServiceDescriptor(ServiceDescriptorProto proto, FileDescriptor file, int index)
+        : base(proto, file, index) {
+    }
+  }
+}

+ 58 - 5
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?
     /// <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.

+ 6 - 1
csharp/ProtocolBuffers/ProtocolBuffers.csproj

@@ -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" />