blob: 3520dc9ed7a97ce5272a70c9fd93b84b4486cdf6 [file] [log] [blame]
Jon Skeet0aac0e42009-09-09 18:48:02 +01001#region Copyright notice and license
Jon Skeetad748532009-06-25 16:55:58 +01002// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc. All rights reserved.
4// http://github.com/jskeet/dotnet-protobufs/
5// Original C++/Java/Python code:
6// http://code.google.com/p/protobuf/
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
11//
12// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18// * Neither the name of Google Inc. nor the names of its
19// contributors may be used to endorse or promote products derived from
20// this software without specific prior written permission.
21//
22// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jon Skeet0aac0e42009-09-09 18:48:02 +010033#endregion
34
Jon Skeet60c059b2008-10-23 21:17:56 +010035using System;
Jon Skeet68036862008-10-22 13:30:34 +010036using System.Globalization;
Jon Skeet642a8142009-01-27 12:25:21 +000037using Google.ProtocolBuffers.Descriptors;
Jon Skeet68036862008-10-22 13:30:34 +010038
39namespace Google.ProtocolBuffers.ProtoGen {
40 internal abstract class FieldGeneratorBase : SourceGeneratorBase<FieldDescriptor> {
41 protected FieldGeneratorBase(FieldDescriptor descriptor)
42 : base(descriptor) {
43 }
44
45 private static bool AllPrintableAscii(string text) {
46 foreach (char c in text) {
47 if (c < 0x20 || c > 0x7e) {
48 return false;
49 }
50 }
51 return true;
52 }
53
csharptest980ba8d2010-11-07 16:30:39 -060054 /// <remarks>Copy exists in ExtensionGenerator.cs</remarks>
Jon Skeet68036862008-10-22 13:30:34 +010055 protected string DefaultValue {
56 get {
57 string suffix = "";
58 switch (Descriptor.FieldType) {
59 case FieldType.Float: suffix = "F"; break;
60 case FieldType.Double: suffix = "D"; break;
61 case FieldType.Int64: suffix = "L"; break;
62 case FieldType.UInt64: suffix = "UL"; break;
63 }
64 switch (Descriptor.FieldType) {
65 case FieldType.Float:
66 case FieldType.Double:
67 case FieldType.Int32:
68 case FieldType.Int64:
69 case FieldType.SInt32:
70 case FieldType.SInt64:
71 case FieldType.SFixed32:
72 case FieldType.SFixed64:
73 case FieldType.UInt32:
74 case FieldType.UInt64:
75 case FieldType.Fixed32:
76 case FieldType.Fixed64:
77 // The simple Object.ToString converts using the current culture.
78 // We want to always use the invariant culture so it's predictable.
79 IConvertible value = (IConvertible) Descriptor.DefaultValue;
80 return value.ToString(CultureInfo.InvariantCulture) + suffix;
81 case FieldType.Bool:
82 return (bool) Descriptor.DefaultValue ? "true" : "false";
83
84 case FieldType.Bytes:
85 if (!Descriptor.HasDefaultValue) {
86 return "pb::ByteString.Empty";
87 }
csharptest980ba8d2010-11-07 16:30:39 -060088 if (UseLiteRuntime && Descriptor.DefaultValue is ByteString) {
89 string temp = Convert.ToBase64String(((ByteString)Descriptor.DefaultValue).ToByteArray());
90 return String.Format("ByteString.FromBase64(\"{0}\")", temp);
91 }
Jon Skeetd6343be2008-11-12 23:39:44 +000092 return string.Format("(pb::ByteString) {0}.Descriptor.Fields[{1}].DefaultValue", GetClassName(Descriptor.ContainingType), Descriptor.Index);
Jon Skeet68036862008-10-22 13:30:34 +010093 case FieldType.String:
94 if (AllPrintableAscii(Descriptor.Proto.DefaultValue)) {
95 // All chars are ASCII and printable. In this case we only
96 // need to escape quotes and backslashes.
97 return "\"" + Descriptor.Proto.DefaultValue
98 .Replace("\\", "\\\\")
99 .Replace("'", "\\'")
100 .Replace("\"", "\\\"")
101 + "\"";
102 }
csharptest980ba8d2010-11-07 16:30:39 -0600103 if (UseLiteRuntime && Descriptor.DefaultValue is String) {
104 string temp = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes((String)Descriptor.DefaultValue));
105 return String.Format("ByteString.FromBase64(\"{0}\").ToStringUtf8()", temp);
106 }
Jon Skeetd6343be2008-11-12 23:39:44 +0000107 return string.Format("(string) {0}.Descriptor.Fields[{1}].DefaultValue", GetClassName(Descriptor.ContainingType), Descriptor.Index);
Jon Skeet68036862008-10-22 13:30:34 +0100108 case FieldType.Enum:
109 return TypeName + "." + ((EnumValueDescriptor) Descriptor.DefaultValue).Name;
110 case FieldType.Message:
111 case FieldType.Group:
112 return TypeName + ".DefaultInstance";
113 default:
114 throw new InvalidOperationException("Invalid field descriptor type");
115 }
116 }
117 }
118
Jon Skeet68036862008-10-22 13:30:34 +0100119 protected string PropertyName {
120 get {
Jon Skeet1d131c92008-11-13 22:29:48 +0000121 return Descriptor.CSharpOptions.PropertyName;
Jon Skeet68036862008-10-22 13:30:34 +0100122 }
123 }
124
Jon Skeet68036862008-10-22 13:30:34 +0100125 protected string Name {
Jon Skeetd6343be2008-11-12 23:39:44 +0000126 get { return NameHelpers.UnderscoresToCamelCase(GetFieldName(Descriptor)); }
Jon Skeet68036862008-10-22 13:30:34 +0100127 }
128
129 protected int Number {
130 get { return Descriptor.FieldNumber; }
131 }
132
Jon Skeet642a8142009-01-27 12:25:21 +0000133 protected void AddNullCheck(TextGenerator writer) {
134 AddNullCheck(writer, "value");
135 }
136
137 protected void AddNullCheck(TextGenerator writer, string name) {
138 if (IsNullableType) {
139 writer.WriteLine(" pb::ThrowHelper.ThrowIfNull({0}, \"{0}\");", name);
140 }
141 }
142
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100143 protected void AddClsComplianceCheck(TextGenerator writer) {
Jon Skeet706c5f62010-05-19 22:15:45 +0100144 if (!Descriptor.IsCLSCompliant && Descriptor.File.CSharpOptions.ClsCompliance) {
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100145 writer.WriteLine("[global::System.CLSCompliant(false)]");
146 }
147 }
148
Jon Skeet25a28582009-02-18 16:06:22 +0000149 /// <summary>
150 /// For encodings with fixed sizes, returns that size in bytes. Otherwise
151 /// returns -1. TODO(jonskeet): Make this less ugly.
152 /// </summary>
153 protected int FixedSize {
154 get {
155 switch (Descriptor.FieldType) {
156 case FieldType.UInt32:
157 case FieldType.UInt64:
158 case FieldType.Int32:
159 case FieldType.Int64:
160 case FieldType.SInt32:
161 case FieldType.SInt64:
162 case FieldType.Enum:
163 case FieldType.Bytes:
164 case FieldType.String:
165 case FieldType.Message:
166 case FieldType.Group:
167 return -1;
168 case FieldType.Float:
169 return WireFormat.FloatSize;
170 case FieldType.SFixed32:
171 return WireFormat.SFixed32Size;
172 case FieldType.Fixed32:
173 return WireFormat.Fixed32Size;
174 case FieldType.Double:
175 return WireFormat.DoubleSize;
176 case FieldType.SFixed64:
177 return WireFormat.SFixed64Size;
178 case FieldType.Fixed64:
179 return WireFormat.Fixed64Size;
180 case FieldType.Bool:
181 return WireFormat.BoolSize;
182 default:
183 throw new InvalidOperationException("Invalid field descriptor type");
184 }
185 }
186 }
187
Jon Skeet642a8142009-01-27 12:25:21 +0000188 protected bool IsNullableType {
189 get {
190 switch (Descriptor.FieldType) {
191 case FieldType.Float:
192 case FieldType.Double:
193 case FieldType.Int32:
194 case FieldType.Int64:
195 case FieldType.SInt32:
196 case FieldType.SInt64:
197 case FieldType.SFixed32:
198 case FieldType.SFixed64:
199 case FieldType.UInt32:
200 case FieldType.UInt64:
201 case FieldType.Fixed32:
202 case FieldType.Fixed64:
203 case FieldType.Bool:
204 case FieldType.Enum:
205 return false;
206 case FieldType.Bytes:
207 case FieldType.String:
208 case FieldType.Message:
209 case FieldType.Group:
210 return true;
211 default:
212 throw new InvalidOperationException("Invalid field descriptor type");
213 }
214 }
215 }
216
Jon Skeet68036862008-10-22 13:30:34 +0100217 protected string TypeName {
218 get {
219 switch (Descriptor.FieldType) {
220 case FieldType.Enum:
Jon Skeetd6343be2008-11-12 23:39:44 +0000221 return GetClassName(Descriptor.EnumType);
Jon Skeet68036862008-10-22 13:30:34 +0100222 case FieldType.Message:
223 case FieldType.Group:
Jon Skeetd6343be2008-11-12 23:39:44 +0000224 return GetClassName(Descriptor.MessageType);
Jon Skeet68036862008-10-22 13:30:34 +0100225 default:
226 return DescriptorUtil.GetMappedTypeName(Descriptor.MappedType);
227 }
228 }
229 }
230
231 protected string MessageOrGroup {
232 get { return Descriptor.FieldType == FieldType.Group ? "Group" : "Message"; }
233 }
234
235 /// <summary>
236 /// Returns the type name as used in CodedInputStream method names: SFixed32, UInt32 etc.
237 /// </summary>
238 protected string CapitalizedTypeName {
239 get {
240 // Our enum names match perfectly. How serendipitous.
241 return Descriptor.FieldType.ToString();
242 }
243 }
244 }
245}