blob: 45a096a0cf62adc2760fc85e9f8ba647a446b58e [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
csharptest272cb8a2010-11-09 20:49:12 -060045 public abstract void WriteHash(TextGenerator writer);
46 public abstract void WriteEquals(TextGenerator writer);
47 public abstract void WriteToString(TextGenerator writer);
48
Jon Skeet68036862008-10-22 13:30:34 +010049 private static bool AllPrintableAscii(string text) {
50 foreach (char c in text) {
51 if (c < 0x20 || c > 0x7e) {
52 return false;
53 }
54 }
55 return true;
56 }
57
csharptest980ba8d2010-11-07 16:30:39 -060058 /// <remarks>Copy exists in ExtensionGenerator.cs</remarks>
Jon Skeet68036862008-10-22 13:30:34 +010059 protected string DefaultValue {
60 get {
61 string suffix = "";
62 switch (Descriptor.FieldType) {
63 case FieldType.Float: suffix = "F"; break;
64 case FieldType.Double: suffix = "D"; break;
65 case FieldType.Int64: suffix = "L"; break;
66 case FieldType.UInt64: suffix = "UL"; break;
67 }
68 switch (Descriptor.FieldType) {
69 case FieldType.Float:
70 case FieldType.Double:
71 case FieldType.Int32:
72 case FieldType.Int64:
73 case FieldType.SInt32:
74 case FieldType.SInt64:
75 case FieldType.SFixed32:
76 case FieldType.SFixed64:
77 case FieldType.UInt32:
78 case FieldType.UInt64:
79 case FieldType.Fixed32:
csharptest272cb8a2010-11-09 20:49:12 -060080 case FieldType.Fixed64:
81 {
Jon Skeet68036862008-10-22 13:30:34 +010082 // The simple Object.ToString converts using the current culture.
83 // We want to always use the invariant culture so it's predictable.
84 IConvertible value = (IConvertible) Descriptor.DefaultValue;
csharptest272cb8a2010-11-09 20:49:12 -060085 //a few things that must be handled explicitly
86 if (Descriptor.FieldType == FieldType.Double && value is double) {
87 if (double.IsNaN((double) value))
88 return "double.NaN";
89 if (double.IsPositiveInfinity((double) value))
90 return "double.PositiveInfinity";
91 if (double.IsNegativeInfinity((double) value))
92 return "double.NegativeInfinity";
93 }
94 else if (Descriptor.FieldType == FieldType.Float && value is float) {
95 if (float.IsNaN((float)value))
96 return "float.NaN";
97 if (float.IsPositiveInfinity((float)value))
98 return "float.PositiveInfinity";
99 if (float.IsNegativeInfinity((float)value))
100 return "float.NegativeInfinity";
101 }
Jon Skeet68036862008-10-22 13:30:34 +0100102 return value.ToString(CultureInfo.InvariantCulture) + suffix;
csharptest272cb8a2010-11-09 20:49:12 -0600103 }
Jon Skeet68036862008-10-22 13:30:34 +0100104 case FieldType.Bool:
105 return (bool) Descriptor.DefaultValue ? "true" : "false";
106
107 case FieldType.Bytes:
108 if (!Descriptor.HasDefaultValue) {
109 return "pb::ByteString.Empty";
110 }
csharptest980ba8d2010-11-07 16:30:39 -0600111 if (UseLiteRuntime && Descriptor.DefaultValue is ByteString) {
112 string temp = Convert.ToBase64String(((ByteString)Descriptor.DefaultValue).ToByteArray());
113 return String.Format("ByteString.FromBase64(\"{0}\")", temp);
114 }
Jon Skeetd6343be2008-11-12 23:39:44 +0000115 return string.Format("(pb::ByteString) {0}.Descriptor.Fields[{1}].DefaultValue", GetClassName(Descriptor.ContainingType), Descriptor.Index);
Jon Skeet68036862008-10-22 13:30:34 +0100116 case FieldType.String:
117 if (AllPrintableAscii(Descriptor.Proto.DefaultValue)) {
118 // All chars are ASCII and printable. In this case we only
119 // need to escape quotes and backslashes.
120 return "\"" + Descriptor.Proto.DefaultValue
121 .Replace("\\", "\\\\")
122 .Replace("'", "\\'")
123 .Replace("\"", "\\\"")
124 + "\"";
125 }
csharptest980ba8d2010-11-07 16:30:39 -0600126 if (UseLiteRuntime && Descriptor.DefaultValue is String) {
127 string temp = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes((String)Descriptor.DefaultValue));
128 return String.Format("ByteString.FromBase64(\"{0}\").ToStringUtf8()", temp);
129 }
Jon Skeetd6343be2008-11-12 23:39:44 +0000130 return string.Format("(string) {0}.Descriptor.Fields[{1}].DefaultValue", GetClassName(Descriptor.ContainingType), Descriptor.Index);
Jon Skeet68036862008-10-22 13:30:34 +0100131 case FieldType.Enum:
132 return TypeName + "." + ((EnumValueDescriptor) Descriptor.DefaultValue).Name;
133 case FieldType.Message:
134 case FieldType.Group:
135 return TypeName + ".DefaultInstance";
136 default:
137 throw new InvalidOperationException("Invalid field descriptor type");
138 }
139 }
140 }
141
Jon Skeet68036862008-10-22 13:30:34 +0100142 protected string PropertyName {
143 get {
Jon Skeet1d131c92008-11-13 22:29:48 +0000144 return Descriptor.CSharpOptions.PropertyName;
Jon Skeet68036862008-10-22 13:30:34 +0100145 }
146 }
147
Jon Skeet68036862008-10-22 13:30:34 +0100148 protected string Name {
Jon Skeetd6343be2008-11-12 23:39:44 +0000149 get { return NameHelpers.UnderscoresToCamelCase(GetFieldName(Descriptor)); }
Jon Skeet68036862008-10-22 13:30:34 +0100150 }
151
152 protected int Number {
153 get { return Descriptor.FieldNumber; }
154 }
155
Jon Skeet642a8142009-01-27 12:25:21 +0000156 protected void AddNullCheck(TextGenerator writer) {
157 AddNullCheck(writer, "value");
158 }
159
160 protected void AddNullCheck(TextGenerator writer, string name) {
161 if (IsNullableType) {
162 writer.WriteLine(" pb::ThrowHelper.ThrowIfNull({0}, \"{0}\");", name);
163 }
164 }
165
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100166 protected void AddClsComplianceCheck(TextGenerator writer) {
Jon Skeet706c5f62010-05-19 22:15:45 +0100167 if (!Descriptor.IsCLSCompliant && Descriptor.File.CSharpOptions.ClsCompliance) {
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100168 writer.WriteLine("[global::System.CLSCompliant(false)]");
169 }
170 }
171
Jon Skeet25a28582009-02-18 16:06:22 +0000172 /// <summary>
173 /// For encodings with fixed sizes, returns that size in bytes. Otherwise
174 /// returns -1. TODO(jonskeet): Make this less ugly.
175 /// </summary>
176 protected int FixedSize {
177 get {
178 switch (Descriptor.FieldType) {
179 case FieldType.UInt32:
180 case FieldType.UInt64:
181 case FieldType.Int32:
182 case FieldType.Int64:
183 case FieldType.SInt32:
184 case FieldType.SInt64:
185 case FieldType.Enum:
186 case FieldType.Bytes:
187 case FieldType.String:
188 case FieldType.Message:
189 case FieldType.Group:
190 return -1;
191 case FieldType.Float:
192 return WireFormat.FloatSize;
193 case FieldType.SFixed32:
194 return WireFormat.SFixed32Size;
195 case FieldType.Fixed32:
196 return WireFormat.Fixed32Size;
197 case FieldType.Double:
198 return WireFormat.DoubleSize;
199 case FieldType.SFixed64:
200 return WireFormat.SFixed64Size;
201 case FieldType.Fixed64:
202 return WireFormat.Fixed64Size;
203 case FieldType.Bool:
204 return WireFormat.BoolSize;
205 default:
206 throw new InvalidOperationException("Invalid field descriptor type");
207 }
208 }
209 }
210
Jon Skeet642a8142009-01-27 12:25:21 +0000211 protected bool IsNullableType {
212 get {
213 switch (Descriptor.FieldType) {
214 case FieldType.Float:
215 case FieldType.Double:
216 case FieldType.Int32:
217 case FieldType.Int64:
218 case FieldType.SInt32:
219 case FieldType.SInt64:
220 case FieldType.SFixed32:
221 case FieldType.SFixed64:
222 case FieldType.UInt32:
223 case FieldType.UInt64:
224 case FieldType.Fixed32:
225 case FieldType.Fixed64:
226 case FieldType.Bool:
227 case FieldType.Enum:
228 return false;
229 case FieldType.Bytes:
230 case FieldType.String:
231 case FieldType.Message:
232 case FieldType.Group:
233 return true;
234 default:
235 throw new InvalidOperationException("Invalid field descriptor type");
236 }
237 }
238 }
239
Jon Skeet68036862008-10-22 13:30:34 +0100240 protected string TypeName {
241 get {
242 switch (Descriptor.FieldType) {
243 case FieldType.Enum:
Jon Skeetd6343be2008-11-12 23:39:44 +0000244 return GetClassName(Descriptor.EnumType);
Jon Skeet68036862008-10-22 13:30:34 +0100245 case FieldType.Message:
246 case FieldType.Group:
Jon Skeetd6343be2008-11-12 23:39:44 +0000247 return GetClassName(Descriptor.MessageType);
Jon Skeet68036862008-10-22 13:30:34 +0100248 default:
249 return DescriptorUtil.GetMappedTypeName(Descriptor.MappedType);
250 }
251 }
252 }
253
254 protected string MessageOrGroup {
255 get { return Descriptor.FieldType == FieldType.Group ? "Group" : "Message"; }
256 }
257
258 /// <summary>
259 /// Returns the type name as used in CodedInputStream method names: SFixed32, UInt32 etc.
260 /// </summary>
261 protected string CapitalizedTypeName {
262 get {
263 // Our enum names match perfectly. How serendipitous.
264 return Descriptor.FieldType.ToString();
265 }
266 }
267 }
268}