FieldGeneratorBase.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. #region Copyright notice and license
  2. // 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.
  33. #endregion
  34. using System;
  35. using System.Globalization;
  36. using Google.ProtocolBuffers.Descriptors;
  37. namespace Google.ProtocolBuffers.ProtoGen
  38. {
  39. internal abstract class FieldGeneratorBase : SourceGeneratorBase<FieldDescriptor>
  40. {
  41. private readonly int _fieldOrdinal;
  42. protected FieldGeneratorBase(FieldDescriptor descriptor, int fieldOrdinal)
  43. : base(descriptor)
  44. {
  45. _fieldOrdinal = fieldOrdinal;
  46. }
  47. public abstract void WriteHash(TextGenerator writer);
  48. public abstract void WriteEquals(TextGenerator writer);
  49. public abstract void WriteToString(TextGenerator writer);
  50. public int FieldOrdinal { get { return _fieldOrdinal; } }
  51. private static bool AllPrintableAscii(string text)
  52. {
  53. foreach (char c in text)
  54. {
  55. if (c < 0x20 || c > 0x7e)
  56. {
  57. return false;
  58. }
  59. }
  60. return true;
  61. }
  62. protected bool HasDefaultValue
  63. {
  64. get
  65. {
  66. switch (Descriptor.FieldType)
  67. {
  68. case FieldType.Float:
  69. case FieldType.Double:
  70. case FieldType.Int32:
  71. case FieldType.Int64:
  72. case FieldType.SInt32:
  73. case FieldType.SInt64:
  74. case FieldType.SFixed32:
  75. case FieldType.SFixed64:
  76. case FieldType.UInt32:
  77. case FieldType.UInt64:
  78. case FieldType.Fixed32:
  79. case FieldType.Fixed64:
  80. {
  81. IConvertible value = (IConvertible) Descriptor.DefaultValue;
  82. return value.ToString(CultureInfo.InvariantCulture) != "0";
  83. }
  84. case FieldType.Bool:
  85. return ((bool) Descriptor.DefaultValue) == true;
  86. default:
  87. return true;
  88. }
  89. }
  90. }
  91. /// <remarks>Copy exists in ExtensionGenerator.cs</remarks>
  92. protected string DefaultValue
  93. {
  94. get
  95. {
  96. string suffix = "";
  97. switch (Descriptor.FieldType)
  98. {
  99. case FieldType.Float:
  100. suffix = "F";
  101. break;
  102. case FieldType.Double:
  103. suffix = "D";
  104. break;
  105. case FieldType.Int64:
  106. suffix = "L";
  107. break;
  108. case FieldType.UInt64:
  109. suffix = "UL";
  110. break;
  111. }
  112. switch (Descriptor.FieldType)
  113. {
  114. case FieldType.Float:
  115. case FieldType.Double:
  116. case FieldType.Int32:
  117. case FieldType.Int64:
  118. case FieldType.SInt32:
  119. case FieldType.SInt64:
  120. case FieldType.SFixed32:
  121. case FieldType.SFixed64:
  122. case FieldType.UInt32:
  123. case FieldType.UInt64:
  124. case FieldType.Fixed32:
  125. case FieldType.Fixed64:
  126. {
  127. // The simple Object.ToString converts using the current culture.
  128. // We want to always use the invariant culture so it's predictable.
  129. IConvertible value = (IConvertible) Descriptor.DefaultValue;
  130. //a few things that must be handled explicitly
  131. if (Descriptor.FieldType == FieldType.Double && value is double)
  132. {
  133. if (double.IsNaN((double) value))
  134. return "double.NaN";
  135. if (double.IsPositiveInfinity((double) value))
  136. return "double.PositiveInfinity";
  137. if (double.IsNegativeInfinity((double) value))
  138. return "double.NegativeInfinity";
  139. }
  140. else if (Descriptor.FieldType == FieldType.Float && value is float)
  141. {
  142. if (float.IsNaN((float) value))
  143. return "float.NaN";
  144. if (float.IsPositiveInfinity((float) value))
  145. return "float.PositiveInfinity";
  146. if (float.IsNegativeInfinity((float) value))
  147. return "float.NegativeInfinity";
  148. }
  149. return value.ToString(CultureInfo.InvariantCulture) + suffix;
  150. }
  151. case FieldType.Bool:
  152. return (bool) Descriptor.DefaultValue ? "true" : "false";
  153. case FieldType.Bytes:
  154. if (!Descriptor.HasDefaultValue)
  155. {
  156. return "pb::ByteString.Empty";
  157. }
  158. if (UseLiteRuntime && Descriptor.DefaultValue is ByteString)
  159. {
  160. string temp = (((ByteString) Descriptor.DefaultValue).ToBase64());
  161. return String.Format("ByteString.FromBase64(\"{0}\")", temp);
  162. }
  163. return string.Format("(pb::ByteString) {0}.Descriptor.Fields[{1}].DefaultValue",
  164. GetClassName(Descriptor.ContainingType), Descriptor.Index);
  165. case FieldType.String:
  166. if (AllPrintableAscii(Descriptor.Proto.DefaultValue))
  167. {
  168. // All chars are ASCII and printable. In this case we only
  169. // need to escape quotes and backslashes.
  170. return "\"" + Descriptor.Proto.DefaultValue
  171. .Replace("\\", "\\\\")
  172. .Replace("'", "\\'")
  173. .Replace("\"", "\\\"")
  174. + "\"";
  175. }
  176. if (UseLiteRuntime && Descriptor.DefaultValue is String)
  177. {
  178. string temp =
  179. Convert.ToBase64String(
  180. System.Text.Encoding.UTF8.GetBytes((String) Descriptor.DefaultValue));
  181. return String.Format("ByteString.FromBase64(\"{0}\").ToStringUtf8()", temp);
  182. }
  183. return string.Format("(string) {0}.Descriptor.Fields[{1}].DefaultValue",
  184. GetClassName(Descriptor.ContainingType), Descriptor.Index);
  185. case FieldType.Enum:
  186. return TypeName + "." + ((EnumValueDescriptor) Descriptor.DefaultValue).Name;
  187. case FieldType.Message:
  188. case FieldType.Group:
  189. return TypeName + ".DefaultInstance";
  190. default:
  191. throw new InvalidOperationException("Invalid field descriptor type");
  192. }
  193. }
  194. }
  195. protected string PropertyName
  196. {
  197. get { return Descriptor.CSharpOptions.PropertyName; }
  198. }
  199. protected string Name
  200. {
  201. get { return NameHelpers.UnderscoresToCamelCase(GetFieldName(Descriptor)); }
  202. }
  203. protected int Number
  204. {
  205. get { return Descriptor.FieldNumber; }
  206. }
  207. protected void AddNullCheck(TextGenerator writer)
  208. {
  209. AddNullCheck(writer, "value");
  210. }
  211. protected void AddNullCheck(TextGenerator writer, string name)
  212. {
  213. if (IsNullableType)
  214. {
  215. writer.WriteLine(" pb::ThrowHelper.ThrowIfNull({0}, \"{0}\");", name);
  216. }
  217. }
  218. protected void AddClsComplianceCheck(TextGenerator writer)
  219. {
  220. if (!Descriptor.IsCLSCompliant && Descriptor.File.CSharpOptions.ClsCompliance)
  221. {
  222. writer.WriteLine("[global::System.CLSCompliant(false)]");
  223. }
  224. }
  225. /// <summary>
  226. /// For encodings with fixed sizes, returns that size in bytes. Otherwise
  227. /// returns -1. TODO(jonskeet): Make this less ugly.
  228. /// </summary>
  229. protected int FixedSize
  230. {
  231. get
  232. {
  233. switch (Descriptor.FieldType)
  234. {
  235. case FieldType.UInt32:
  236. case FieldType.UInt64:
  237. case FieldType.Int32:
  238. case FieldType.Int64:
  239. case FieldType.SInt32:
  240. case FieldType.SInt64:
  241. case FieldType.Enum:
  242. case FieldType.Bytes:
  243. case FieldType.String:
  244. case FieldType.Message:
  245. case FieldType.Group:
  246. return -1;
  247. case FieldType.Float:
  248. return WireFormat.FloatSize;
  249. case FieldType.SFixed32:
  250. return WireFormat.SFixed32Size;
  251. case FieldType.Fixed32:
  252. return WireFormat.Fixed32Size;
  253. case FieldType.Double:
  254. return WireFormat.DoubleSize;
  255. case FieldType.SFixed64:
  256. return WireFormat.SFixed64Size;
  257. case FieldType.Fixed64:
  258. return WireFormat.Fixed64Size;
  259. case FieldType.Bool:
  260. return WireFormat.BoolSize;
  261. default:
  262. throw new InvalidOperationException("Invalid field descriptor type");
  263. }
  264. }
  265. }
  266. protected bool IsNullableType
  267. {
  268. get
  269. {
  270. switch (Descriptor.FieldType)
  271. {
  272. case FieldType.Float:
  273. case FieldType.Double:
  274. case FieldType.Int32:
  275. case FieldType.Int64:
  276. case FieldType.SInt32:
  277. case FieldType.SInt64:
  278. case FieldType.SFixed32:
  279. case FieldType.SFixed64:
  280. case FieldType.UInt32:
  281. case FieldType.UInt64:
  282. case FieldType.Fixed32:
  283. case FieldType.Fixed64:
  284. case FieldType.Bool:
  285. case FieldType.Enum:
  286. return false;
  287. case FieldType.Bytes:
  288. case FieldType.String:
  289. case FieldType.Message:
  290. case FieldType.Group:
  291. return true;
  292. default:
  293. throw new InvalidOperationException("Invalid field descriptor type");
  294. }
  295. }
  296. }
  297. protected string TypeName
  298. {
  299. get
  300. {
  301. switch (Descriptor.FieldType)
  302. {
  303. case FieldType.Enum:
  304. return GetClassName(Descriptor.EnumType);
  305. case FieldType.Message:
  306. case FieldType.Group:
  307. return GetClassName(Descriptor.MessageType);
  308. default:
  309. return DescriptorUtil.GetMappedTypeName(Descriptor.MappedType);
  310. }
  311. }
  312. }
  313. protected string MessageOrGroup
  314. {
  315. get { return Descriptor.FieldType == FieldType.Group ? "Group" : "Message"; }
  316. }
  317. /// <summary>
  318. /// Returns the type name as used in CodedInputStream method names: SFixed32, UInt32 etc.
  319. /// </summary>
  320. protected string CapitalizedTypeName
  321. {
  322. get
  323. {
  324. // Our enum names match perfectly. How serendipitous.
  325. return Descriptor.FieldType.ToString();
  326. }
  327. }
  328. }
  329. }