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