Commit d6343be7 authored by Jon Skeet's avatar Jon Skeet

Refactored options

parent 60c059b8
...@@ -4,13 +4,22 @@ import "google/protobuf/descriptor.proto"; ...@@ -4,13 +4,22 @@ import "google/protobuf/descriptor.proto";
package google.protobuf; package google.protobuf;
option (CSharpNamespace) = "Google.ProtocolBuffers.DescriptorProtos"; message CSharpFileOptions {
option (CSharpUmbrellaClassname) = "CSharpOptions"; optional string namespace = 1;
optional string umbrella_classname= 2;
optional bool public_classes = 3;
optional bool multiple_files = 4;
optional bool nest_classes = 5;
extend FileOptions { extend FileOptions {
optional string CSharpNamespace = 20000; optional CSharpFileOptions csharp_options = 1000;
optional string CSharpUmbrellaClassname = 20001; }
optional bool CSharpMultipleFiles = 20002; }
optional bool CSharpNestClasses = 20003;
optional bool CSharpPublicClasses = 20004; message CSharpFieldOptions {
optional string property_name = 1;
extend FieldOptions {
optional CSharpFieldOptions csharp_options = 1000;
}
} }
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// line onwards is as per original distribution. // line onwards is as per original distribution.
import "google/protobuf/csharp_options.proto"; import "google/protobuf/csharp_options.proto";
import "google/protobuf/descriptor.proto"; import "google/protobuf/descriptor.proto";
option (google.protobuf.CSharpNamespace) = "Google.ProtocolBuffers.TestProtos"; option (google.protobuf.CSharpFileOptions.csharp_options).namespace = "Google.ProtocolBuffers.TestProtos";
option (google.protobuf.CSharpUmbrellaClassname) = "UnitTestProtoFile"; option (google.protobuf.CSharpFileOptions.csharp_options).umbrella_classname = "UnitTestProtoFile";
// Protocol Buffers - Google's data interchange format // Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved. // Copyright 2008 Google Inc. All rights reserved.
......
// Additional options required for C# generation. File from copyright // Additional options required for C# generation. File from copyright
// line onwards is as per original distribution. // line onwards is as per original distribution.
import "google/protobuf/csharp_options.proto"; import "google/protobuf/csharp_options.proto";
option (google.protobuf.CSharpNamespace) = "Google.ProtocolBuffers.TestProtos"; option (google.protobuf.CSharpFileOptions.csharp_options).namespace = "Google.ProtocolBuffers.TestProtos";
option (google.protobuf.CSharpUmbrellaClassname) = "UnitTestCustomOptionsProtoFile"; option (google.protobuf.CSharpFileOptions.csharp_options).umbrella_classname = "UnitTestCustomOptionsProtoFile";
// Protocol Buffers - Google's data interchange format // Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved. // Copyright 2008 Google Inc. All rights reserved.
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// line onwards is as per original distribution. // line onwards is as per original distribution.
import "google/protobuf/csharp_options.proto"; import "google/protobuf/csharp_options.proto";
import "google/protobuf/descriptor.proto"; import "google/protobuf/descriptor.proto";
option (google.protobuf.CSharpNamespace) = "Google.ProtocolBuffers.TestProtos"; option (google.protobuf.CSharpFileOptions.csharp_options).namespace = "Google.ProtocolBuffers.TestProtos";
option (google.protobuf.CSharpUmbrellaClassname) = "UnitTestEmbedOptimizeForProtoFile"; option (google.protobuf.CSharpFileOptions.csharp_options).umbrella_classname = "UnitTestEmbedOptimizeForProtoFile";
// Protocol Buffers - Google's data interchange format // Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved. // Copyright 2008 Google Inc. All rights reserved.
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// line onwards is as per original distribution. // line onwards is as per original distribution.
import "google/protobuf/csharp_options.proto"; import "google/protobuf/csharp_options.proto";
import "google/protobuf/descriptor.proto"; import "google/protobuf/descriptor.proto";
option (google.protobuf.CSharpNamespace) = "Google.ProtocolBuffers.TestProtos"; option (google.protobuf.CSharpFileOptions.csharp_options).namespace = "Google.ProtocolBuffers.TestProtos";
option (google.protobuf.CSharpUmbrellaClassname) = "UnitTestImportProtoFile"; option (google.protobuf.CSharpFileOptions.csharp_options).umbrella_classname = "UnitTestImportProtoFile";
// Protocol Buffers - Google's data interchange format // Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved. // Copyright 2008 Google Inc. All rights reserved.
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// line onwards is as per original distribution. // line onwards is as per original distribution.
import "google/protobuf/csharp_options.proto"; import "google/protobuf/csharp_options.proto";
import "google/protobuf/descriptor.proto"; import "google/protobuf/descriptor.proto";
option (google.protobuf.CSharpNamespace) = "Google.ProtocolBuffers.TestProtos"; option (google.protobuf.CSharpFileOptions.csharp_options).namespace = "Google.ProtocolBuffers.TestProtos";
option (google.protobuf.CSharpUmbrellaClassname) = "UnitTestMessageSetProtoFile"; option (google.protobuf.CSharpFileOptions.csharp_options).umbrella_classname = "UnitTestMessageSetProtoFile";
// Protocol Buffers - Google's data interchange format // Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved. // Copyright 2008 Google Inc. All rights reserved.
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// line onwards is as per original distribution. // line onwards is as per original distribution.
import "google/protobuf/csharp_options.proto"; import "google/protobuf/csharp_options.proto";
import "google/protobuf/descriptor.proto"; import "google/protobuf/descriptor.proto";
option (google.protobuf.CSharpNamespace) = "Google.ProtocolBuffers.TestProtos"; option (google.protobuf.CSharpFileOptions.csharp_options).namespace = "Google.ProtocolBuffers.TestProtos";
option (google.protobuf.CSharpUmbrellaClassname) = "UnitTestOptimizeForProtoFile"; option (google.protobuf.CSharpFileOptions.csharp_options).umbrella_classname = "UnitTestOptimizeForProtoFile";
// Protocol Buffers - Google's data interchange format // Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved. // Copyright 2008 Google Inc. All rights reserved.
......
...@@ -5,7 +5,7 @@ using NUnit.Framework; ...@@ -5,7 +5,7 @@ using NUnit.Framework;
namespace Google.ProtocolBuffers.ProtoGen { namespace Google.ProtocolBuffers.ProtoGen {
[TestFixture] [TestFixture]
public class DescriptorUtilTest { public class DescriptorUtilTest {
/* FIXME: Move these around!
[Test] [Test]
public void ExplicitNamespace() { public void ExplicitNamespace() {
FileDescriptorProto proto = new FileDescriptorProto.Builder { FileDescriptorProto proto = new FileDescriptorProto.Builder {
...@@ -64,6 +64,6 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -64,6 +64,6 @@ namespace Google.ProtocolBuffers.ProtoGen {
FileDescriptorProto proto = new FileDescriptorProto.Builder { Name = "x/y/foo_bar" }.Build(); FileDescriptorProto proto = new FileDescriptorProto.Builder { Name = "x/y/foo_bar" }.Build();
FileDescriptor descriptor = FileDescriptor.BuildFrom(proto, null); FileDescriptor descriptor = FileDescriptor.BuildFrom(proto, null);
Assert.AreEqual("FooBar", DescriptorUtil.GetUmbrellaClassName(descriptor)); Assert.AreEqual("FooBar", DescriptorUtil.GetUmbrellaClassName(descriptor));
} } */
} }
} }
using Google.ProtocolBuffers.ProtoGen;
using NUnit.Framework;
namespace Google.ProtocolBuffers.ProtoGen {
[TestFixture]
public class HelpersTest {
[Test]
public void UnderscoresToPascalCase() {
Assert.AreEqual("FooBar", Helpers.UnderscoresToPascalCase("Foo_bar"));
Assert.AreEqual("FooBar", Helpers.UnderscoresToPascalCase("foo_bar"));
Assert.AreEqual("Foo0Bar", Helpers.UnderscoresToPascalCase("Foo0bar"));
Assert.AreEqual("FooBar", Helpers.UnderscoresToPascalCase("Foo_+_Bar"));
}
[Test]
public void UnderscoresToCamelCase() {
Assert.AreEqual("fooBar", Helpers.UnderscoresToCamelCase("Foo_bar"));
Assert.AreEqual("fooBar", Helpers.UnderscoresToCamelCase("foo_bar"));
Assert.AreEqual("foo0Bar", Helpers.UnderscoresToCamelCase("Foo0bar"));
Assert.AreEqual("fooBar", Helpers.UnderscoresToCamelCase("Foo_+_Bar"));
}
[Test]
public void StripSuffix() {
string text = "FooBar";
Assert.IsFalse(Helpers.StripSuffix(ref text, "Foo"));
Assert.AreEqual("FooBar", text);
Assert.IsTrue(Helpers.StripSuffix(ref text, "Bar"));
Assert.AreEqual("Foo", text);
}
}
}
\ No newline at end of file
...@@ -47,7 +47,6 @@ ...@@ -47,7 +47,6 @@
<Compile Include="DependencyResolutionTest.cs" /> <Compile Include="DependencyResolutionTest.cs" />
<Compile Include="DescriptorUtilTest.cs" /> <Compile Include="DescriptorUtilTest.cs" />
<Compile Include="GeneratorTest.cs" /> <Compile Include="GeneratorTest.cs" />
<Compile Include="HelpersTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
......
...@@ -10,80 +10,11 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -10,80 +10,11 @@ namespace Google.ProtocolBuffers.ProtoGen {
/// </summary> /// </summary>
internal static class DescriptorUtil { internal static class DescriptorUtil {
internal static bool NestClasses(IDescriptor descriptor) { internal static string GetFullUmbrellaClassName(IDescriptor descriptor) {
// Defaults to false CSharpFileOptions options = descriptor.File.CSharpOptions;
return descriptor.File.Options.GetExtension(CSharpOptions.CSharpNestClasses); string result = options.Namespace;
}
internal static string GetNamespace(FileDescriptor descriptor) {
if (descriptor.Name == "google/protobuf/descriptor.proto") {
return typeof(DescriptorProtoFile).Namespace;
}
return descriptor.Options.HasExtension(CSharpOptions.CSharpNamespace) ?
descriptor.Options.GetExtension(CSharpOptions.CSharpNamespace) : descriptor.Package;
}
// Groups are hacky: The name of the field is just the lower-cased name
// of the group type. In C#, though, we would like to retain the original
// capitalization of the type name.
internal static string GetFieldName(FieldDescriptor descriptor) {
if (descriptor.FieldType == FieldType.Group) {
return descriptor.MessageType.Name;
} else {
return descriptor.Name;
}
}
internal static string GetClassName(IDescriptor descriptor) {
return ToCSharpName(descriptor.FullName, descriptor.File);
}
internal static string GetFullUmbrellaClassName(FileDescriptor descriptor) {
string result = GetNamespace(descriptor);
if (result != "") result += '.'; if (result != "") result += '.';
result += GetUmbrellaClassName(descriptor); result += options.UmbrellaClassname;
return "global::" + result;
}
internal static string GetUmbrellaClassName(FileDescriptor descriptor) {
if (descriptor.Name == "google/protobuf/descriptor.proto") {
return typeof(DescriptorProtoFile).Name;
}
FileOptions options = descriptor.Options;
if (options.HasExtension(CSharpOptions.CSharpUmbrellaClassname)) {
return descriptor.Options.GetExtension(CSharpOptions.CSharpUmbrellaClassname);
}
int lastSlash = descriptor.Name.LastIndexOf('/');
string baseName = descriptor.Name.Substring(lastSlash + 1);
return Helpers.UnderscoresToPascalCase(StripProto(baseName));
}
private static string StripProto(string text) {
if (!Helpers.StripSuffix(ref text, ".protodevel")) {
Helpers.StripSuffix(ref text, ".proto");
}
return text;
}
private static string ToCSharpName(string name, FileDescriptor file) {
string result;
if (!NestClasses(file)) {
result = GetNamespace(file);
} else {
result = GetUmbrellaClassName(file);
}
if (result != "") {
result += '.';
}
string classname;
if (file.Package == "") {
classname = name;
} else {
// Strip the proto package from full_name since we've replaced it with
// the C# namespace.
classname = name.Substring(file.Package.Length + 1);
}
result += classname.Replace(".", ".Types.");
return "global::" + result; return "global::" + result;
} }
......
...@@ -9,15 +9,15 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -9,15 +9,15 @@ namespace Google.ProtocolBuffers.ProtoGen {
} }
public void Generate(TextGenerator writer) { public void Generate(TextGenerator writer) {
string name = Helpers.UnderscoresToPascalCase(DescriptorUtil.GetFieldName(Descriptor)); string name = NameHelpers.UnderscoresToPascalCase(GetFieldName(Descriptor));
string type; string type;
switch (Descriptor.MappedType) { switch (Descriptor.MappedType) {
case MappedType.Message: case MappedType.Message:
type = DescriptorUtil.GetClassName(Descriptor.MessageType); type = GetClassName(Descriptor.MessageType);
break; break;
case MappedType.Enum: case MappedType.Enum:
type = DescriptorUtil.GetClassName(Descriptor.EnumType); type = GetClassName(Descriptor.EnumType);
break; break;
default: default:
type = DescriptorUtil.GetMappedTypeName(Descriptor.MappedType); type = DescriptorUtil.GetMappedTypeName(Descriptor.MappedType);
......
...@@ -50,7 +50,7 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -50,7 +50,7 @@ namespace Google.ProtocolBuffers.ProtoGen {
if (!Descriptor.HasDefaultValue) { if (!Descriptor.HasDefaultValue) {
return "pb::ByteString.Empty"; return "pb::ByteString.Empty";
} }
return string.Format("(pb::ByteString) {0}.Descriptor.Fields[{1}].DefaultValue", DescriptorUtil.GetClassName(Descriptor.ContainingType), Descriptor.Index); return string.Format("(pb::ByteString) {0}.Descriptor.Fields[{1}].DefaultValue", GetClassName(Descriptor.ContainingType), Descriptor.Index);
case FieldType.String: case FieldType.String:
if (AllPrintableAscii(Descriptor.Proto.DefaultValue)) { if (AllPrintableAscii(Descriptor.Proto.DefaultValue)) {
// All chars are ASCII and printable. In this case we only // All chars are ASCII and printable. In this case we only
...@@ -61,7 +61,7 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -61,7 +61,7 @@ namespace Google.ProtocolBuffers.ProtoGen {
.Replace("\"", "\\\"") .Replace("\"", "\\\"")
+ "\""; + "\"";
} }
return string.Format("(string) {0}.Descriptor.Fields[{1}].DefaultValue", DescriptorUtil.GetClassName(Descriptor.ContainingType), Descriptor.Index); return string.Format("(string) {0}.Descriptor.Fields[{1}].DefaultValue", GetClassName(Descriptor.ContainingType), Descriptor.Index);
case FieldType.Enum: case FieldType.Enum:
return TypeName + "." + ((EnumValueDescriptor) Descriptor.DefaultValue).Name; return TypeName + "." + ((EnumValueDescriptor) Descriptor.DefaultValue).Name;
case FieldType.Message: case FieldType.Message:
...@@ -88,11 +88,11 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -88,11 +88,11 @@ namespace Google.ProtocolBuffers.ProtoGen {
} }
protected string CapitalizedName { protected string CapitalizedName {
get { return Helpers.UnderscoresToPascalCase(DescriptorUtil.GetFieldName(Descriptor)); } get { return NameHelpers.UnderscoresToPascalCase(GetFieldName(Descriptor)); }
} }
protected string Name { protected string Name {
get { return Helpers.UnderscoresToCamelCase(DescriptorUtil.GetFieldName(Descriptor)); } get { return NameHelpers.UnderscoresToCamelCase(GetFieldName(Descriptor)); }
} }
protected int Number { protected int Number {
...@@ -103,10 +103,10 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -103,10 +103,10 @@ namespace Google.ProtocolBuffers.ProtoGen {
get { get {
switch (Descriptor.FieldType) { switch (Descriptor.FieldType) {
case FieldType.Enum: case FieldType.Enum:
return DescriptorUtil.GetClassName(Descriptor.EnumType); return GetClassName(Descriptor.EnumType);
case FieldType.Message: case FieldType.Message:
case FieldType.Group: case FieldType.Group:
return DescriptorUtil.GetClassName(Descriptor.MessageType); return GetClassName(Descriptor.MessageType);
default: default:
return DescriptorUtil.GetMappedTypeName(Descriptor.MappedType); return DescriptorUtil.GetMappedTypeName(Descriptor.MappedType);
} }
......
...@@ -30,11 +30,8 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -30,11 +30,8 @@ namespace Google.ProtocolBuffers.ProtoGen {
foreach (string inputFile in options.InputFiles) { foreach (string inputFile in options.InputFiles) {
FileDescriptorSet descriptorProtos; FileDescriptorSet descriptorProtos;
ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance(); ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
extensionRegistry.Add(CSharpOptions.CSharpUmbrellaClassname); extensionRegistry.Add(CSharpFileOptions.CSharpOptions);
extensionRegistry.Add(CSharpOptions.CSharpMultipleFiles); extensionRegistry.Add(CSharpFieldOptions.CSharpOptions);
extensionRegistry.Add(CSharpOptions.CSharpNamespace);
extensionRegistry.Add(CSharpOptions.CSharpNestClasses);
extensionRegistry.Add(CSharpOptions.CSharpPublicClasses);
using (Stream inputStream = File.OpenRead(inputFile)) { using (Stream inputStream = File.OpenRead(inputFile)) {
descriptorProtos = FileDescriptorSet.ParseFrom(inputStream, extensionRegistry); descriptorProtos = FileDescriptorSet.ParseFrom(inputStream, extensionRegistry);
} }
...@@ -51,12 +48,9 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -51,12 +48,9 @@ namespace Google.ProtocolBuffers.ProtoGen {
/// already have been resolved. /// already have been resolved.
/// </summary> /// </summary>
private void Generate(FileDescriptor descriptor) { private void Generate(FileDescriptor descriptor) {
string umbrellaClass = DescriptorUtil.GetUmbrellaClassName(descriptor);
string ns = DescriptorUtil.GetNamespace(descriptor);
using (TextWriter textWriter = File.CreateText(Path.Combine(options.OutputDirectory, umbrellaClass + ".cs"))) {
TextGenerator writer = new TextGenerator(textWriter);
UmbrellaClassGenerator ucg = new UmbrellaClassGenerator(descriptor); UmbrellaClassGenerator ucg = new UmbrellaClassGenerator(descriptor);
using (TextWriter textWriter = File.CreateText(Path.Combine(options.OutputDirectory, descriptor.CSharpOptions.UmbrellaClassname + ".cs"))) {
TextGenerator writer = new TextGenerator(textWriter);
ucg.Generate(writer); ucg.Generate(writer);
/* /*
GenerateSiblings(umbrellaSource, descriptor, descriptor.MessageTypes); GenerateSiblings(umbrellaSource, descriptor, descriptor.MessageTypes);
......
...@@ -8,71 +8,11 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -8,71 +8,11 @@ namespace Google.ProtocolBuffers.ProtoGen {
/// Helpers to resolve class names etc. /// Helpers to resolve class names etc.
/// </summary> /// </summary>
internal static class Helpers { internal static class Helpers {
internal static string UnderscoresToPascalCase(string input) {
return UnderscoresToPascalOrCamelCase(input, true);
}
internal static string UnderscoresToCamelCase(string input) {
return UnderscoresToPascalOrCamelCase(input, false);
}
internal static void WriteNamespaces(TextGenerator writer) { internal static void WriteNamespaces(TextGenerator writer) {
writer.WriteLine("using pb = global::Google.ProtocolBuffers;"); writer.WriteLine("using pb = global::Google.ProtocolBuffers;");
writer.WriteLine("using pbc = global::Google.ProtocolBuffers.Collections;"); writer.WriteLine("using pbc = global::Google.ProtocolBuffers.Collections;");
writer.WriteLine("using pbd = global::Google.ProtocolBuffers.Descriptors;"); writer.WriteLine("using pbd = global::Google.ProtocolBuffers.Descriptors;");
writer.WriteLine("using scg = global::System.Collections.Generic;"); writer.WriteLine("using scg = global::System.Collections.Generic;");
} }
/// <summary>
/// Converts a string to Pascal or Camel case. The first letter is capitalized or
/// lower-cased depending on <paramref name="pascal"/> is true.
/// After the first letter, any punctuation is removed but triggers capitalization
/// of the next letter. Digits are preserved but trigger capitalization of the next
/// letter.
/// All capitalisation is done in the invariant culture.
/// </summary>
private static string UnderscoresToPascalOrCamelCase(string input, bool pascal) {
StringBuilder result = new StringBuilder();
bool capitaliseNext = pascal;
for (int i=0; i < input.Length; i++) {
char c = input[i];
if ('a' <= c && c <= 'z') {
if (capitaliseNext) {
result.Append(char.ToUpperInvariant(c));
} else {
result.Append(c);
}
capitaliseNext = false;
} else if ('A' <= c && c <= 'Z') {
if (i == 0 && !pascal) {
// Force first letter to lower-case unless explicitly told to
// capitalize it.
result.Append(char.ToLowerInvariant(c));
} else {
// Capital letters after the first are left as-is.
result.Append(c);
}
capitaliseNext = false;
} else if ('0' <= c && c <= '9') {
result.Append(c);
capitaliseNext = true;
} else {
capitaliseNext = true;
}
}
return result.ToString();
}
/// <summary>
/// Attempts to strip a suffix from a string, returning whether
/// or not the suffix was actually present.
/// </summary>
internal static bool StripSuffix(ref string text, string suffix) {
if (text.EndsWith(suffix)) {
text = text.Substring(0, text.Length - suffix.Length);
return true;
}
return false;
}
} }
} }
...@@ -15,7 +15,7 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -15,7 +15,7 @@ namespace Google.ProtocolBuffers.ProtoGen {
} }
private string FullClassName { private string FullClassName {
get { return DescriptorUtil.GetClassName(Descriptor); } get { return GetClassName(Descriptor); }
} }
/// <summary> /// <summary>
...@@ -38,7 +38,7 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -38,7 +38,7 @@ namespace Google.ProtocolBuffers.ProtoGen {
string identifier = GetUniqueFileScopeIdentifier(Descriptor); string identifier = GetUniqueFileScopeIdentifier(Descriptor);
// The descriptor for this type. // The descriptor for this type.
string access = Descriptor.File.Options.GetExtension(CSharpOptions.CSharpNestClasses) ? "private" : "internal"; string access = Descriptor.File.CSharpOptions.NestClasses ? "private" : "internal";
writer.WriteLine("{0} static readonly pbd::MessageDescriptor internal__{1}__Descriptor", access, identifier); writer.WriteLine("{0} static readonly pbd::MessageDescriptor internal__{1}__Descriptor", access, identifier);
if (Descriptor.ContainingType == null) { if (Descriptor.ContainingType == null) {
writer.WriteLine(" = Descriptor.MessageTypes[{0}];", Descriptor.Index); writer.WriteLine(" = Descriptor.MessageTypes[{0}];", Descriptor.Index);
...@@ -51,7 +51,7 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -51,7 +51,7 @@ namespace Google.ProtocolBuffers.ProtoGen {
FullClassName, identifier); FullClassName, identifier);
writer.Print(" new string[] { "); writer.Print(" new string[] { ");
foreach (FieldDescriptor field in Descriptor.Fields) { foreach (FieldDescriptor field in Descriptor.Fields) {
writer.Write("\"{0}\", ", Helpers.UnderscoresToPascalCase(DescriptorUtil.GetFieldName(field))); writer.Write("\"{0}\", ", NameHelpers.UnderscoresToPascalCase(GetFieldName(field)));
} }
writer.WriteLine("});"); writer.WriteLine("});");
...@@ -80,12 +80,12 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -80,12 +80,12 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.WriteLine("}"); writer.WriteLine("}");
writer.WriteLine(); writer.WriteLine();
writer.WriteLine("public static pbd::MessageDescriptor Descriptor {"); writer.WriteLine("public static pbd::MessageDescriptor Descriptor {");
writer.WriteLine(" get {{ return {0}.internal__{1}__Descriptor; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor.File), writer.WriteLine(" get {{ return {0}.internal__{1}__Descriptor; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor),
GetUniqueFileScopeIdentifier(Descriptor)); GetUniqueFileScopeIdentifier(Descriptor));
writer.WriteLine("}"); writer.WriteLine("}");
writer.WriteLine(); writer.WriteLine();
writer.WriteLine("protected override pb::FieldAccess.FieldAccessorTable<{0}, {0}.Builder> InternalFieldAccessors {{", ClassName); writer.WriteLine("protected override pb::FieldAccess.FieldAccessorTable<{0}, {0}.Builder> InternalFieldAccessors {{", ClassName);
writer.WriteLine(" get {{ return {0}.internal__{1}__FieldAccessorTable; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor.File), writer.WriteLine(" get {{ return {0}.internal__{1}__FieldAccessorTable; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor),
GetUniqueFileScopeIdentifier(Descriptor)); GetUniqueFileScopeIdentifier(Descriptor));
writer.WriteLine("}"); writer.WriteLine("}");
writer.WriteLine(); writer.WriteLine();
...@@ -186,7 +186,7 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -186,7 +186,7 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.WriteLine(); writer.WriteLine();
} }
private static void GenerateSerializeOneField(TextGenerator writer, FieldDescriptor fieldDescriptor) { private void GenerateSerializeOneField(TextGenerator writer, FieldDescriptor fieldDescriptor) {
SourceGenerators.CreateFieldGenerator(fieldDescriptor).GenerateSerializationCode(writer); SourceGenerators.CreateFieldGenerator(fieldDescriptor).GenerateSerializationCode(writer);
} }
...@@ -415,7 +415,7 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -415,7 +415,7 @@ namespace Google.ProtocolBuffers.ProtoGen {
// "has" fields into a single bitfield. // "has" fields into a single bitfield.
foreach (FieldDescriptor field in Descriptor.Fields) { foreach (FieldDescriptor field in Descriptor.Fields) {
if (field.IsRequired) { if (field.IsRequired) {
writer.WriteLine("if (!has{0}) return false;", Helpers.UnderscoresToPascalCase(field.Name)); writer.WriteLine("if (!has{0}) return false;", NameHelpers.UnderscoresToPascalCase(field.Name));
} }
} }
...@@ -425,9 +425,9 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -425,9 +425,9 @@ namespace Google.ProtocolBuffers.ProtoGen {
!HasRequiredFields(field.MessageType, new Dictionary<MessageDescriptor, object>())) { !HasRequiredFields(field.MessageType, new Dictionary<MessageDescriptor, object>())) {
continue; continue;
} }
string propertyName = Helpers.UnderscoresToPascalCase(DescriptorUtil.GetFieldName(field)); string propertyName = NameHelpers.UnderscoresToPascalCase(GetFieldName(field));
if (field.IsRepeated) { if (field.IsRepeated) {
writer.WriteLine("foreach ({0} element in {1}List) {{", DescriptorUtil.GetClassName(field.MessageType), propertyName); writer.WriteLine("foreach ({0} element in {1}List) {{", GetClassName(field.MessageType), propertyName);
writer.WriteLine(" if (!element.IsInitialized) return false;"); writer.WriteLine(" if (!element.IsInitialized) return false;");
writer.WriteLine("}"); writer.WriteLine("}");
} else if (field.IsOptional) { } else if (field.IsOptional) {
......
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="DescriptorUtil.cs" /> <Compile Include="DescriptorUtil.cs" />
......
...@@ -20,17 +20,17 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -20,17 +20,17 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.Indent(); writer.Indent();
foreach (MethodDescriptor method in Descriptor.Methods) { foreach (MethodDescriptor method in Descriptor.Methods) {
writer.WriteLine("{0} abstract void {1}(", ClassAccessLevel, Helpers.UnderscoresToPascalCase(method.Name)); writer.WriteLine("{0} abstract void {1}(", ClassAccessLevel, NameHelpers.UnderscoresToPascalCase(method.Name));
writer.WriteLine(" pb::IRpcController controller,"); writer.WriteLine(" pb::IRpcController controller,");
writer.WriteLine(" {0} request,", DescriptorUtil.GetClassName(method.InputType)); writer.WriteLine(" {0} request,", GetClassName(method.InputType));
writer.WriteLine(" global::System.Action<{0}> done);", DescriptorUtil.GetClassName(method.OutputType)); writer.WriteLine(" global::System.Action<{0}> done);", GetClassName(method.OutputType));
} }
// Generate Descriptor and DescriptorForType. // Generate Descriptor and DescriptorForType.
writer.WriteLine(); writer.WriteLine();
writer.WriteLine("{0} static pbd::ServiceDescriptor Descriptor {{", ClassAccessLevel); writer.WriteLine("{0} static pbd::ServiceDescriptor Descriptor {{", ClassAccessLevel);
writer.WriteLine(" get {{ return {0}.Descriptor.Services[{1}]; }}", writer.WriteLine(" get {{ return {0}.Descriptor.Services[{1}]; }}",
DescriptorUtil.GetUmbrellaClassName(Descriptor.File), Descriptor.Index); Descriptor.File.CSharpOptions.UmbrellaClassname, Descriptor.Index);
writer.WriteLine("}"); writer.WriteLine("}");
writer.WriteLine("{0} pbd::ServiceDescriptor DescriptorForType {{", ClassAccessLevel); writer.WriteLine("{0} pbd::ServiceDescriptor DescriptorForType {{", ClassAccessLevel);
writer.WriteLine(" get { return Descriptor; }"); writer.WriteLine(" get { return Descriptor; }");
...@@ -62,8 +62,8 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -62,8 +62,8 @@ namespace Google.ProtocolBuffers.ProtoGen {
foreach (MethodDescriptor method in Descriptor.Methods) { foreach (MethodDescriptor method in Descriptor.Methods) {
writer.WriteLine("case {0}:", method.Index); writer.WriteLine("case {0}:", method.Index);
writer.WriteLine(" this.{0}(controller, ({1}) request,", writer.WriteLine(" this.{0}(controller, ({1}) request,",
Helpers.UnderscoresToPascalCase(method.Name), DescriptorUtil.GetClassName(method.InputType)); NameHelpers.UnderscoresToPascalCase(method.Name), GetClassName(method.InputType));
writer.WriteLine(" pb::RpcUtil.SpecializeCallback<{0}>(", DescriptorUtil.GetClassName(method.OutputType)); writer.WriteLine(" pb::RpcUtil.SpecializeCallback<{0}>(", GetClassName(method.OutputType));
writer.WriteLine(" done));"); writer.WriteLine(" done));");
writer.WriteLine(" return;"); writer.WriteLine(" return;");
} }
...@@ -89,7 +89,7 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -89,7 +89,7 @@ namespace Google.ProtocolBuffers.ProtoGen {
foreach (MethodDescriptor method in Descriptor.Methods) { foreach (MethodDescriptor method in Descriptor.Methods) {
writer.WriteLine("case {0}:", method.Index); writer.WriteLine("case {0}:", method.Index);
writer.WriteLine(" return {0}.DefaultInstance;", writer.WriteLine(" return {0}.DefaultInstance;",
DescriptorUtil.GetClassName(which == RequestOrResponse.Request ? method.InputType : method.OutputType)); GetClassName(which == RequestOrResponse.Request ? method.InputType : method.OutputType));
} }
writer.WriteLine("default:"); writer.WriteLine("default:");
writer.WriteLine(" throw new global::System.InvalidOperationException(\"Can't get here.\");"); writer.WriteLine(" throw new global::System.InvalidOperationException(\"Can't get here.\");");
...@@ -105,7 +105,7 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -105,7 +105,7 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.WriteLine(" return new Stub(channel);"); writer.WriteLine(" return new Stub(channel);");
writer.WriteLine("}"); writer.WriteLine("}");
writer.WriteLine(); writer.WriteLine();
writer.WriteLine("{0} class Stub : {1} {{", ClassAccessLevel, DescriptorUtil.GetClassName(Descriptor)); writer.WriteLine("{0} class Stub : {1} {{", ClassAccessLevel, GetClassName(Descriptor));
writer.Indent(); writer.Indent();
writer.WriteLine("internal Stub(pb::IRpcChannel channel) {"); writer.WriteLine("internal Stub(pb::IRpcChannel channel) {");
writer.WriteLine(" this.channel = channel;"); writer.WriteLine(" this.channel = channel;");
...@@ -119,15 +119,15 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -119,15 +119,15 @@ namespace Google.ProtocolBuffers.ProtoGen {
foreach (MethodDescriptor method in Descriptor.Methods) { foreach (MethodDescriptor method in Descriptor.Methods) {
writer.WriteLine(); writer.WriteLine();
writer.WriteLine("public override void {0}(", Helpers.UnderscoresToPascalCase(method.Name)); writer.WriteLine("public override void {0}(", NameHelpers.UnderscoresToPascalCase(method.Name));
writer.WriteLine(" pb::IRpcController controller,"); writer.WriteLine(" pb::IRpcController controller,");
writer.WriteLine(" {0} request,", DescriptorUtil.GetClassName(method.InputType)); writer.WriteLine(" {0} request,", GetClassName(method.InputType));
writer.WriteLine(" global::System.Action<{0}> done) {{", DescriptorUtil.GetClassName(method.OutputType)); writer.WriteLine(" global::System.Action<{0}> done) {{", GetClassName(method.OutputType));
writer.Indent(); writer.Indent();
writer.WriteLine("channel.CallMethod(Descriptor.Methods[{0}],", method.Index); writer.WriteLine("channel.CallMethod(Descriptor.Methods[{0}],", method.Index);
writer.WriteLine(" controller, request, {0}.DefaultInstance,", DescriptorUtil.GetClassName(method.OutputType)); writer.WriteLine(" controller, request, {0}.DefaultInstance,", GetClassName(method.OutputType));
writer.WriteLine(" pb::RpcUtil.GeneralizeCallback<{0}, {0}.Builder>(done, {0}.DefaultInstance));", writer.WriteLine(" pb::RpcUtil.GeneralizeCallback<{0}, {0}.Builder>(done, {0}.DefaultInstance));",
DescriptorUtil.GetClassName(method.OutputType)); GetClassName(method.OutputType));
writer.Outdent(); writer.Outdent();
writer.WriteLine("}"); writer.WriteLine("}");
} }
......
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Google.ProtocolBuffers.DescriptorProtos;
using Google.ProtocolBuffers.Descriptors; using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.ProtoGen { namespace Google.ProtocolBuffers.ProtoGen {
...@@ -15,19 +15,51 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -15,19 +15,51 @@ namespace Google.ProtocolBuffers.ProtoGen {
get { return descriptor; } get { return descriptor; }
} }
protected string ClassAccessLevel { internal static string GetClassName(IDescriptor descriptor) {
get { return ToCSharpName(descriptor.FullName, descriptor.File);
// Default to public }
return !descriptor.File.Options.HasExtension(CSharpOptions.CSharpPublicClasses)
|| descriptor.File.Options.GetExtension(CSharpOptions.CSharpPublicClasses) ? "public" : "internal"; // Groups are hacky: The name of the field is just the lower-cased name
// of the group type. In C#, though, we would like to retain the original
// capitalization of the type name.
internal static string GetFieldName(FieldDescriptor descriptor) {
if (descriptor.FieldType == FieldType.Group) {
return descriptor.MessageType.Name;
} else {
return descriptor.Name;
} }
} }
public bool MultipleFiles { private static string ToCSharpName(string name, FileDescriptor file) {
get { return descriptor.File.Options.GetExtension(CSharpOptions.CSharpMultipleFiles); } string result = file.CSharpOptions.Namespace;
if (file.CSharpOptions.NestClasses) {
if (result != "") {
result += ".";
}
result += file.CSharpOptions.UmbrellaClassname;
}
if (result != "") {
result += '.';
}
string classname;
if (file.Package == "") {
classname = name;
} else {
// Strip the proto package from full_name since we've replaced it with
// the C# namespace.
classname = name.Substring(file.Package.Length + 1);
}
result += classname.Replace(".", ".Types.");
return "global::" + result;
}
protected string ClassAccessLevel {
get {
return descriptor.File.CSharpOptions.PublicClasses ? "public" : "internal";
}
} }
protected static void WriteChildren<TChild>(TextGenerator writer, string region, IEnumerable<TChild> children) protected void WriteChildren<TChild>(TextGenerator writer, string region, IEnumerable<TChild> children)
where TChild : IDescriptor { where TChild : IDescriptor {
// Copy the set of children; makes access easier // Copy the set of children; makes access easier
List<TChild> copy = new List<TChild>(children); List<TChild> copy = new List<TChild>(children);
......
...@@ -13,6 +13,10 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -13,6 +13,10 @@ namespace Google.ProtocolBuffers.ProtoGen {
: base(descriptor) { : base(descriptor) {
} }
public string UmbrellaClassName {
get { throw new NotImplementedException(); }
}
public void Generate(TextGenerator writer) { public void Generate(TextGenerator writer) {
WriteIntroduction(writer); WriteIntroduction(writer);
WriteDescriptor(writer); WriteDescriptor(writer);
...@@ -23,18 +27,18 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -23,18 +27,18 @@ namespace Google.ProtocolBuffers.ProtoGen {
} }
writer.WriteLine("#endregion"); writer.WriteLine("#endregion");
// The class declaration either gets closed before or after the children are written. // The class declaration either gets closed before or after the children are written.
if (!DescriptorUtil.NestClasses(Descriptor)) { if (!Descriptor.CSharpOptions.NestClasses) {
writer.Outdent(); writer.Outdent();
writer.WriteLine("}"); writer.WriteLine("}");
} }
WriteChildren(writer, "Enums", Descriptor.EnumTypes); WriteChildren(writer, "Enums", Descriptor.EnumTypes);
WriteChildren(writer, "Messages", Descriptor.MessageTypes); WriteChildren(writer, "Messages", Descriptor.MessageTypes);
WriteChildren(writer, "Services", Descriptor.Services); WriteChildren(writer, "Services", Descriptor.Services);
if (DescriptorUtil.NestClasses(Descriptor)) { if (Descriptor.CSharpOptions.NestClasses) {
writer.Outdent(); writer.Outdent();
writer.WriteLine("}"); writer.WriteLine("}");
} }
if (DescriptorUtil.GetNamespace(Descriptor) != "") { if (Descriptor.CSharpOptions.Namespace != "") {
writer.Outdent(); writer.Outdent();
writer.WriteLine("}"); writer.WriteLine("}");
} }
...@@ -45,13 +49,13 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -45,13 +49,13 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.WriteLine(); writer.WriteLine();
Helpers.WriteNamespaces(writer); Helpers.WriteNamespaces(writer);
if (DescriptorUtil.GetNamespace(Descriptor) != "") { if (Descriptor.CSharpOptions.Namespace != "") {
writer.WriteLine("namespace {0} {{", DescriptorUtil.GetNamespace(Descriptor)); writer.WriteLine("namespace {0} {{", Descriptor.CSharpOptions.Namespace);
writer.Indent(); writer.Indent();
writer.WriteLine(); writer.WriteLine();
} }
writer.WriteLine("{0} static partial class {1} {{", ClassAccessLevel, DescriptorUtil.GetUmbrellaClassName(Descriptor)); writer.WriteLine("{0} static partial class {1} {{", ClassAccessLevel, Descriptor.CSharpOptions.UmbrellaClassname);
writer.WriteLine(); writer.WriteLine();
writer.Indent(); writer.Indent();
} }
...@@ -79,11 +83,6 @@ namespace Google.ProtocolBuffers.ProtoGen { ...@@ -79,11 +83,6 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.WriteLine("new pbd::FileDescriptor[] {"); writer.WriteLine("new pbd::FileDescriptor[] {");
foreach (FileDescriptor dependency in Descriptor.Dependencies) { foreach (FileDescriptor dependency in Descriptor.Dependencies) {
// TODO(jonskeet): The normal code won't work for the bootstrapping descriptor, because we don't get unknown fields :(
if (dependency.Package == "google.protobuf" && dependency.Name.EndsWith("descriptor.proto")) {
writer.WriteLine(" global::" + typeof(DescriptorProtoFile).FullName + ".Descriptor, ");
continue;
}
writer.WriteLine(" {0}.Descriptor, ", DescriptorUtil.GetFullUmbrellaClassName(dependency)); writer.WriteLine(" {0}.Descriptor, ", DescriptorUtil.GetFullUmbrellaClassName(dependency));
} }
writer.WriteLine("});"); writer.WriteLine("});");
......
using NUnit.Framework;
namespace Google.ProtocolBuffers {
[TestFixture]
public class NameHelpersTest {
[Test]
public void UnderscoresToPascalCase() {
Assert.AreEqual("FooBar", NameHelpers.UnderscoresToPascalCase("Foo_bar"));
Assert.AreEqual("FooBar", NameHelpers.UnderscoresToPascalCase("foo_bar"));
Assert.AreEqual("Foo0Bar", NameHelpers.UnderscoresToPascalCase("Foo0bar"));
Assert.AreEqual("FooBar", NameHelpers.UnderscoresToPascalCase("Foo_+_Bar"));
}
[Test]
public void UnderscoresToCamelCase() {
Assert.AreEqual("fooBar", NameHelpers.UnderscoresToCamelCase("Foo_bar"));
Assert.AreEqual("fooBar", NameHelpers.UnderscoresToCamelCase("foo_bar"));
Assert.AreEqual("foo0Bar", NameHelpers.UnderscoresToCamelCase("Foo0bar"));
Assert.AreEqual("fooBar", NameHelpers.UnderscoresToCamelCase("Foo_+_Bar"));
}
[Test]
public void StripSuffix() {
string text = "FooBar";
Assert.IsFalse(NameHelpers.StripSuffix(ref text, "Foo"));
Assert.AreEqual("FooBar", text);
Assert.IsTrue(NameHelpers.StripSuffix(ref text, "Bar"));
Assert.AreEqual("Foo", text);
}
}
}
\ No newline at end of file
...@@ -42,6 +42,8 @@ ...@@ -42,6 +42,8 @@
<HintPath>..\..\lib\Rhino.Mocks.dll</HintPath> <HintPath>..\..\lib\Rhino.Mocks.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="AbstractMessageTest.cs" /> <Compile Include="AbstractMessageTest.cs" />
...@@ -55,6 +57,7 @@ ...@@ -55,6 +57,7 @@
<Compile Include="MessageStreamIteratorTest.cs" /> <Compile Include="MessageStreamIteratorTest.cs" />
<Compile Include="MessageStreamWriterTest.cs" /> <Compile Include="MessageStreamWriterTest.cs" />
<Compile Include="MessageTest.cs" /> <Compile Include="MessageTest.cs" />
<Compile Include="NameHelpersTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReflectionTester.cs" /> <Compile Include="ReflectionTester.cs" />
<Compile Include="ServiceTest.cs" /> <Compile Include="ServiceTest.cs" />
......
...@@ -109,9 +109,9 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -109,9 +109,9 @@ namespace Google.ProtocolBuffers.TestProtos {
"Zi5NZXNzYWdlT3B0aW9ucxjvi9IDIAEoCzIlLnByb3RvYnVmX3VuaXR0ZXN0" + "Zi5NZXNzYWdlT3B0aW9ucxjvi9IDIAEoCzIlLnByb3RvYnVmX3VuaXR0ZXN0" +
"LkNvbXBsZXhPcHRpb25UeXBlMzpXCgtjb21wbGV4b3B0NhIfLmdvb2dsZS5w" + "LkNvbXBsZXhPcHRpb25UeXBlMzpXCgtjb21wbGV4b3B0NhIfLmdvb2dsZS5w" +
"cm90b2J1Zi5NZXNzYWdlT3B0aW9ucxjMy88DIAEoCjIeLnByb3RvYnVmX3Vu" + "cm90b2J1Zi5NZXNzYWdlT3B0aW9ucxjMy88DIAEoCjIeLnByb3RvYnVmX3Vu" +
"aXR0ZXN0LkNvbXBsZXhPcHQ2QlCC4gkhR29vZ2xlLlByb3RvY29sQnVmZmVy" + "aXR0ZXN0LkNvbXBsZXhPcHQ2Qk/CPkMKIUdvb2dsZS5Qcm90b2NvbEJ1ZmZl" +
"cy5UZXN0UHJvdG9ziuIJHlVuaXRUZXN0Q3VzdG9tT3B0aW9uc1Byb3RvRmls" + "cnMuVGVzdFByb3RvcxIeVW5pdFRlc3RDdXN0b21PcHRpb25zUHJvdG9GaWxl" +
"ZfDowR3qrcDlJA=="), "8OjBHeqtwOUk"),
new pbd::FileDescriptor[] { new pbd::FileDescriptor[] {
global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor,
global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor,
......
...@@ -21,9 +21,9 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -21,9 +21,9 @@ namespace Google.ProtocolBuffers.TestProtos {
"ci5wcm90byKhAQoZVGVzdEVtYmVkT3B0aW1pemVkRm9yU2l6ZRJBChBvcHRp" + "ci5wcm90byKhAQoZVGVzdEVtYmVkT3B0aW1pemVkRm9yU2l6ZRJBChBvcHRp" +
"b25hbF9tZXNzYWdlGAEgASgLMicucHJvdG9idWZfdW5pdHRlc3QuVGVzdE9w" + "b25hbF9tZXNzYWdlGAEgASgLMicucHJvdG9idWZfdW5pdHRlc3QuVGVzdE9w" +
"dGltaXplZEZvclNpemUSQQoQcmVwZWF0ZWRfbWVzc2FnZRgCIAMoCzInLnBy" + "dGltaXplZEZvclNpemUSQQoQcmVwZWF0ZWRfbWVzc2FnZRgCIAMoCzInLnBy" +
"b3RvYnVmX3VuaXR0ZXN0LlRlc3RPcHRpbWl6ZWRGb3JTaXplQkxIAYLiCSFH" + "b3RvYnVmX3VuaXR0ZXN0LlRlc3RPcHRpbWl6ZWRGb3JTaXplQktIAcI+Rgoh" +
"b29nbGUuUHJvdG9jb2xCdWZmZXJzLlRlc3RQcm90b3OK4gkhVW5pdFRlc3RF" + "R29vZ2xlLlByb3RvY29sQnVmZmVycy5UZXN0UHJvdG9zEiFVbml0VGVzdEVt" +
"bWJlZE9wdGltaXplRm9yUHJvdG9GaWxl"), "YmVkT3B0aW1pemVGb3JQcm90b0ZpbGU="),
new pbd::FileDescriptor[] { new pbd::FileDescriptor[] {
global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor,
global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor,
......
...@@ -19,9 +19,9 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -19,9 +19,9 @@ namespace Google.ProtocolBuffers.TestProtos {
"b3B0aW9ucy5wcm90bxogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJv" + "b3B0aW9ucy5wcm90bxogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJv" +
"dG8iGgoNSW1wb3J0TWVzc2FnZRIJCgFkGAEgASgFKjwKCkltcG9ydEVudW0S" + "dG8iGgoNSW1wb3J0TWVzc2FnZRIJCgFkGAEgASgFKjwKCkltcG9ydEVudW0S" +
"DgoKSU1QT1JUX0ZPTxAHEg4KCklNUE9SVF9CQVIQCBIOCgpJTVBPUlRfQkFa" + "DgoKSU1QT1JUX0ZPTxAHEg4KCklNUE9SVF9CQVIQCBIOCgpJTVBPUlRfQkFa" +
"EAlCXAoYY29tLmdvb2dsZS5wcm90b2J1Zi50ZXN0SAGC4gkhR29vZ2xlLlBy" + "EAlCWwoYY29tLmdvb2dsZS5wcm90b2J1Zi50ZXN0SAHCPjwKIUdvb2dsZS5Q" +
"b3RvY29sQnVmZmVycy5UZXN0UHJvdG9ziuIJF1VuaXRUZXN0SW1wb3J0UHJv" + "cm90b2NvbEJ1ZmZlcnMuVGVzdFByb3RvcxIXVW5pdFRlc3RJbXBvcnRQcm90" +
"dG9GaWxl"), "b0ZpbGU="),
new pbd::FileDescriptor[] { new pbd::FileDescriptor[] {
global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor,
global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor,
......
...@@ -28,9 +28,9 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -28,9 +28,9 @@ namespace Google.ProtocolBuffers.TestProtos {
"U2V0GPm7XiABKAsyKy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWVzc2FnZVNl" + "U2V0GPm7XiABKAsyKy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWVzc2FnZVNl" +
"dEV4dGVuc2lvbjIibgoNUmF3TWVzc2FnZVNldBIzCgRpdGVtGAEgAygKMiUu" + "dEV4dGVuc2lvbjIibgoNUmF3TWVzc2FnZVNldBIzCgRpdGVtGAEgAygKMiUu" +
"cHJvdG9idWZfdW5pdHRlc3QuUmF3TWVzc2FnZVNldC5JdGVtGigKBEl0ZW0S" + "cHJvdG9idWZfdW5pdHRlc3QuUmF3TWVzc2FnZVNldC5JdGVtGigKBEl0ZW0S" +
"DwoHdHlwZV9pZBgCIAIoBRIPCgdtZXNzYWdlGAMgAigMQkZIAYLiCSFHb29n" + "DwoHdHlwZV9pZBgCIAIoBRIPCgdtZXNzYWdlGAMgAigMQkVIAcI+QAohR29v" +
"bGUuUHJvdG9jb2xCdWZmZXJzLlRlc3RQcm90b3OK4gkbVW5pdFRlc3RNZXNz" + "Z2xlLlByb3RvY29sQnVmZmVycy5UZXN0UHJvdG9zEhtVbml0VGVzdE1lc3Nh" +
"YWdlU2V0UHJvdG9GaWxl"), "Z2VTZXRQcm90b0ZpbGU="),
new pbd::FileDescriptor[] { new pbd::FileDescriptor[] {
global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor,
global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor,
......
...@@ -26,9 +26,9 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -26,9 +26,9 @@ namespace Google.ProtocolBuffers.TestProtos {
"dWZfdW5pdHRlc3QuVGVzdFJlcXVpcmVkT3B0aW1pemVkRm9yU2l6ZSIpChxU" + "dWZfdW5pdHRlc3QuVGVzdFJlcXVpcmVkT3B0aW1pemVkRm9yU2l6ZSIpChxU" +
"ZXN0UmVxdWlyZWRPcHRpbWl6ZWRGb3JTaXplEgkKAXgYASACKAUiWgocVGVz" + "ZXN0UmVxdWlyZWRPcHRpbWl6ZWRGb3JTaXplEgkKAXgYASACKAUiWgocVGVz" +
"dE9wdGlvbmFsT3B0aW1pemVkRm9yU2l6ZRI6CgFvGAEgASgLMi8ucHJvdG9i" + "dE9wdGlvbmFsT3B0aW1pemVkRm9yU2l6ZRI6CgFvGAEgASgLMi8ucHJvdG9i" +
"dWZfdW5pdHRlc3QuVGVzdFJlcXVpcmVkT3B0aW1pemVkRm9yU2l6ZUJHSAKC" + "dWZfdW5pdHRlc3QuVGVzdFJlcXVpcmVkT3B0aW1pemVkRm9yU2l6ZUJGSALC" +
"4gkhR29vZ2xlLlByb3RvY29sQnVmZmVycy5UZXN0UHJvdG9ziuIJHFVuaXRU" + "PkEKIUdvb2dsZS5Qcm90b2NvbEJ1ZmZlcnMuVGVzdFByb3RvcxIcVW5pdFRl" +
"ZXN0T3B0aW1pemVGb3JQcm90b0ZpbGU="), "c3RPcHRpbWl6ZUZvclByb3RvRmlsZQ=="),
new pbd::FileDescriptor[] { new pbd::FileDescriptor[] {
global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor,
global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor,
......
...@@ -284,9 +284,9 @@ namespace Google.ProtocolBuffers.TestProtos { ...@@ -284,9 +284,9 @@ namespace Google.ProtocolBuffers.TestProtos {
"dW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYVSABKAk6AzEyM0ICCAE6QgoT" + "dW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYVSABKAk6AzEyM0ICCAE6QgoT" +
"bXlfZXh0ZW5zaW9uX3N0cmluZxIlLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RG" + "bXlfZXh0ZW5zaW9uX3N0cmluZxIlLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RG" +
"aWVsZE9yZGVyaW5ncxgyIAEoCTo/ChBteV9leHRlbnNpb25faW50EiUucHJv" + "aWVsZE9yZGVyaW5ncxgyIAEoCTo/ChBteV9leHRlbnNpb25faW50EiUucHJv" +
"dG9idWZfdW5pdHRlc3QuVGVzdEZpZWxkT3JkZXJpbmdzGAUgASgFQktCDVVu" + "dG9idWZfdW5pdHRlc3QuVGVzdEZpZWxkT3JkZXJpbmdzGAUgASgFQkpCDVVu" +
"aXR0ZXN0UHJvdG9IAYLiCSFHb29nbGUuUHJvdG9jb2xCdWZmZXJzLlRlc3RQ" + "aXR0ZXN0UHJvdG9IAcI+NgohR29vZ2xlLlByb3RvY29sQnVmZmVycy5UZXN0" +
"cm90b3OK4gkRVW5pdFRlc3RQcm90b0ZpbGU="), "UHJvdG9zEhFVbml0VGVzdFByb3RvRmlsZQ=="),
new pbd::FileDescriptor[] { new pbd::FileDescriptor[] {
global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor,
global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor,
......
...@@ -50,6 +50,8 @@ namespace Google.ProtocolBuffers.Descriptors { ...@@ -50,6 +50,8 @@ namespace Google.ProtocolBuffers.Descriptors {
private readonly IList<FieldDescriptor> extensions; private readonly IList<FieldDescriptor> extensions;
private readonly IList<FileDescriptor> dependencies; private readonly IList<FileDescriptor> dependencies;
private readonly DescriptorPool pool; private readonly DescriptorPool pool;
private CSharpFileOptions csharpFileOptions;
private readonly object optionsLock = new object();
private FileDescriptor(FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool) { private FileDescriptor(FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool) {
this.pool = pool; this.pool = pool;
...@@ -71,6 +73,44 @@ namespace Google.ProtocolBuffers.Descriptors { ...@@ -71,6 +73,44 @@ namespace Google.ProtocolBuffers.Descriptors {
(field, index) => new FieldDescriptor(field, this, null, index, true)); (field, index) => new FieldDescriptor(field, this, null, index, true));
} }
private CSharpFileOptions BuildOrFakeCSharpOptions() {
// TODO(jonskeet): Check if we could use FileDescriptorProto.Descriptor.Name - interesting bootstrap issues
if (proto.Name == "google/protobuf/descriptor.proto") {
return new CSharpFileOptions.Builder {
Namespace = "Google.ProtocolBuffers.DescriptorProtos",
UmbrellaClassname = "DescriptorProtoFile", NestClasses = false, MultipleFiles = false, PublicClasses = true
}.Build();
}
if (proto.Name == "google/protobuf/csharp_options.proto") {
return new CSharpFileOptions.Builder {
Namespace = "Google.ProtocolBuffers.DescriptorProtos",
UmbrellaClassname = "CSharpOptions", NestClasses = false, MultipleFiles = false, PublicClasses = true
}.Build();
}
CSharpFileOptions.Builder builder = CSharpFileOptions.CreateBuilder();
if (proto.Options.HasExtension(CSharpFileOptions.CSharpOptions)) {
builder.MergeFrom(proto.Options.GetExtension(CSharpFileOptions.CSharpOptions));
}
if (!builder.HasNamespace) {
builder.Namespace = Package;
}
if (!builder.HasMultipleFiles) {
builder.MultipleFiles = false;
}
if (!builder.HasNestClasses) {
builder.NestClasses = false;
}
if (!builder.HasPublicClasses) {
builder.PublicClasses = true;
}
if (!builder.HasUmbrellaClassname) {
int lastSlash = Name.LastIndexOf('/');
string baseName = Name.Substring(lastSlash + 1);
builder.UmbrellaClassname = NameHelpers.UnderscoresToPascalCase(NameHelpers.StripProto(baseName));
}
return builder.Build();
}
/// <value> /// <value>
/// The descriptor in its protocol message representation. /// The descriptor in its protocol message representation.
/// </value> /// </value>
...@@ -85,6 +125,22 @@ namespace Google.ProtocolBuffers.Descriptors { ...@@ -85,6 +125,22 @@ namespace Google.ProtocolBuffers.Descriptors {
get { return proto.Options; } get { return proto.Options; }
} }
/// <summary>
/// Returns the C#-specific options for this file descriptor. This will always be
/// completely filled in.
/// FIXME: This isn't thread-safe. Can't do it at construction time due to bootstrapping issues.
/// </summary>
public CSharpFileOptions CSharpOptions {
get {
lock (optionsLock) {
if (csharpFileOptions == null) {
csharpFileOptions = BuildOrFakeCSharpOptions();
}
}
return csharpFileOptions;
}
}
/// <value> /// <value>
/// The file name. /// The file name.
/// </value> /// </value>
...@@ -250,7 +306,7 @@ namespace Google.ProtocolBuffers.Descriptors { ...@@ -250,7 +306,7 @@ namespace Google.ProtocolBuffers.Descriptors {
/// <summary> /// <summary>
/// This method is to be called by generated code only. It is equivalent /// This method is to be called by generated code only. It is equivalent
/// to BuilderFrom except that the FileDescriptorProto is encoded in /// to BuildFrom except that the FileDescriptorProto is encoded in
/// protocol buffer wire format. /// protocol buffer wire format.
/// </summary> /// </summary>
public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descriptorData, public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descriptorData,
......
using System;
using System.Collections.Generic;
using System.Text;
namespace Google.ProtocolBuffers {
/// <summary>
/// Helpers for converting names to pascal case etc.
/// </summary>
internal class NameHelpers {
internal static string UnderscoresToPascalCase(string input) {
return UnderscoresToPascalOrCamelCase(input, true);
}
internal static string UnderscoresToCamelCase(string input) {
return UnderscoresToPascalOrCamelCase(input, false);
}
/// <summary>
/// Converts a string to Pascal or Camel case. The first letter is capitalized or
/// lower-cased depending on <paramref name="pascal"/> is true.
/// After the first letter, any punctuation is removed but triggers capitalization
/// of the next letter. Digits are preserved but trigger capitalization of the next
/// letter.
/// All capitalisation is done in the invariant culture.
/// </summary>
private static string UnderscoresToPascalOrCamelCase(string input, bool pascal) {
StringBuilder result = new StringBuilder();
bool capitaliseNext = pascal;
for (int i = 0; i < input.Length; i++) {
char c = input[i];
if ('a' <= c && c <= 'z') {
if (capitaliseNext) {
result.Append(char.ToUpperInvariant(c));
} else {
result.Append(c);
}
capitaliseNext = false;
} else if ('A' <= c && c <= 'Z') {
if (i == 0 && !pascal) {
// Force first letter to lower-case unless explicitly told to
// capitalize it.
result.Append(char.ToLowerInvariant(c));
} else {
// Capital letters after the first are left as-is.
result.Append(c);
}
capitaliseNext = false;
} else if ('0' <= c && c <= '9') {
result.Append(c);
capitaliseNext = true;
} else {
capitaliseNext = true;
}
}
return result.ToString();
}
internal static string StripProto(string text) {
if (!StripSuffix(ref text, ".protodevel")) {
StripSuffix(ref text, ".proto");
}
return text;
}
/// <summary>
/// Attempts to strip a suffix from a string, returning whether
/// or not the suffix was actually present.
/// </summary>
internal static bool StripSuffix(ref string text, string suffix) {
if (text.EndsWith(suffix)) {
text = text.Substring(0, text.Length - suffix.Length);
return true;
}
return false;
}
}
}
...@@ -97,6 +97,7 @@ ...@@ -97,6 +97,7 @@
<Compile Include="IService.cs" /> <Compile Include="IService.cs" />
<Compile Include="MessageStreamIterator.cs" /> <Compile Include="MessageStreamIterator.cs" />
<Compile Include="MessageStreamWriter.cs" /> <Compile Include="MessageStreamWriter.cs" />
<Compile Include="NameHelpers.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RpcUtil.cs" /> <Compile Include="RpcUtil.cs" />
<Compile Include="TextFormat.cs" /> <Compile Include="TextFormat.cs" />
......
Current task list (not in order) Current task list (not in order)
- Extra unit tests for pending Java optimisation Diff stuff
- Refactor IsInitialized - Refactor IsInitialized
- Performance framework - Performance framework
- Optionally remove dependencies to core and csharp options - Optionally remove dependencies to core and csharp options
- Remove multifile support - Remove multifile support
- Remove bootstrapping hack
- Improve "regenerating descriptor.proto" hack
- Mono support - Mono support
- Docs - Docs
- Clean up protogen code - Clean up protogen code
......
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