java_enum_field.cc revision fbaaef999ba563838ebd00874ed8a1c01fbf286d
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Protocol Buffers - Google's data interchange format
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Copyright 2008 Google Inc.  All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// http://code.google.com/p/protobuf/
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Redistribution and use in source and binary forms, with or without
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// modification, are permitted provided that the following conditions are
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// met:
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//     * Redistributions of source code must retain the above copyright
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// notice, this list of conditions and the following disclaimer.
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//     * Redistributions in binary form must reproduce the above
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// in the documentation and/or other materials provided with the
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// distribution.
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//     * Neither the name of Google Inc. nor the names of its
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// contributors may be used to endorse or promote products derived from
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// this software without specific prior written permission.
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
31e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)// Author: kenton@google.com (Kenton Varda)
32e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)//  Based on original Protocol Buffers design by
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)//  Sanjay Ghemawat, Jeff Dean, and others.
34e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)
35e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)#include <map>
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <string>
3751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <google/protobuf/compiler/java/java_enum_field.h>
398abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)#include <google/protobuf/stubs/common.h>
40e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)#include <google/protobuf/compiler/java/java_helpers.h>
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <google/protobuf/io/printer.h>
42e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)#include <google/protobuf/wire_format.h>
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <google/protobuf/stubs/strutil.h>
44e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace google {
46e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)namespace protobuf {
47e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)namespace compiler {
488abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)namespace java {
498abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace {
51e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)
52e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)// TODO(kenton):  Factor out a "SetCommonFieldVariables()" to get rid of
53e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)//   repeat code between this and the other field types.
54e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)void SetEnumVariables(const FieldDescriptor* descriptor,
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      map<string, string>* variables) {
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  (*variables)["name"] =
5751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    UnderscoresToCamelCase(descriptor);
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  (*variables)["capitalized_name"] =
59e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)    UnderscoresToCapitalizedCamelCase(descriptor);
60  (*variables)["number"] = SimpleItoa(descriptor->number());
61  (*variables)["type"] = ClassName(descriptor->enum_type());
62  (*variables)["default"] = DefaultValue(descriptor);
63  (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
64  (*variables)["tag_size"] = SimpleItoa(
65      internal::WireFormat::TagSize(descriptor->number(), descriptor->type()));
66}
67
68}  // namespace
69
70// ===================================================================
71
72EnumFieldGenerator::
73EnumFieldGenerator(const FieldDescriptor* descriptor)
74  : descriptor_(descriptor) {
75  SetEnumVariables(descriptor, &variables_);
76}
77
78EnumFieldGenerator::~EnumFieldGenerator() {}
79
80void EnumFieldGenerator::
81GenerateMembers(io::Printer* printer) const {
82  printer->Print(variables_,
83    "private boolean has$capitalized_name$;\n"
84    "private $type$ $name$_ = $default$;\n"
85    "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
86    "public $type$ get$capitalized_name$() { return $name$_; }\n");
87}
88
89void EnumFieldGenerator::
90GenerateBuilderMembers(io::Printer* printer) const {
91  printer->Print(variables_,
92    "public boolean has$capitalized_name$() {\n"
93    "  return result.has$capitalized_name$();\n"
94    "}\n"
95    "public $type$ get$capitalized_name$() {\n"
96    "  return result.get$capitalized_name$();\n"
97    "}\n"
98    "public Builder set$capitalized_name$($type$ value) {\n"
99    "  if (value == null) {\n"
100    "    throw new NullPointerException();\n"
101    "  }\n"
102    "  result.has$capitalized_name$ = true;\n"
103    "  result.$name$_ = value;\n"
104    "  return this;\n"
105    "}\n"
106    "public Builder clear$capitalized_name$() {\n"
107    "  result.has$capitalized_name$ = false;\n"
108    "  result.$name$_ = $default$;\n"
109    "  return this;\n"
110    "}\n");
111}
112
113void EnumFieldGenerator::
114GenerateMergingCode(io::Printer* printer) const {
115  printer->Print(variables_,
116    "if (other.has$capitalized_name$()) {\n"
117    "  set$capitalized_name$(other.get$capitalized_name$());\n"
118    "}\n");
119}
120
121void EnumFieldGenerator::
122GenerateBuildingCode(io::Printer* printer) const {
123  // Nothing to do here for enum types.
124}
125
126void EnumFieldGenerator::
127GenerateParsingCode(io::Printer* printer) const {
128  printer->Print(variables_,
129    "int rawValue = input.readEnum();\n"
130    "$type$ value = $type$.valueOf(rawValue);\n");
131  if (HasUnknownFields(descriptor_->containing_type())) {
132    printer->Print(variables_,
133      "if (value == null) {\n"
134      "  unknownFields.mergeVarintField($number$, rawValue);\n"
135      "} else {\n");
136  } else {
137    printer->Print(variables_,
138      "if (value != null) {\n");
139  }
140  printer->Print(variables_,
141    "  set$capitalized_name$(value);\n"
142    "}\n");
143}
144
145void EnumFieldGenerator::
146GenerateSerializationCode(io::Printer* printer) const {
147  printer->Print(variables_,
148    "if (has$capitalized_name$()) {\n"
149    "  output.writeEnum($number$, get$capitalized_name$().getNumber());\n"
150    "}\n");
151}
152
153void EnumFieldGenerator::
154GenerateSerializedSizeCode(io::Printer* printer) const {
155  printer->Print(variables_,
156    "if (has$capitalized_name$()) {\n"
157    "  size += com.google.protobuf.CodedOutputStream\n"
158    "    .computeEnumSize($number$, get$capitalized_name$().getNumber());\n"
159    "}\n");
160}
161
162string EnumFieldGenerator::GetBoxedType() const {
163  return ClassName(descriptor_->enum_type());
164}
165
166// ===================================================================
167
168RepeatedEnumFieldGenerator::
169RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor)
170  : descriptor_(descriptor) {
171  SetEnumVariables(descriptor, &variables_);
172}
173
174RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
175
176void RepeatedEnumFieldGenerator::
177GenerateMembers(io::Printer* printer) const {
178  printer->Print(variables_,
179    "private java.util.List<$type$> $name$_ =\n"
180    "  java.util.Collections.emptyList();\n"
181    "public java.util.List<$type$> get$capitalized_name$List() {\n"
182    "  return $name$_;\n"   // note:  unmodifiable list
183    "}\n"
184    "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
185    "public $type$ get$capitalized_name$(int index) {\n"
186    "  return $name$_.get(index);\n"
187    "}\n");
188
189  if (descriptor_->options().packed() &&
190      HasGeneratedMethods(descriptor_->containing_type())) {
191    printer->Print(variables_,
192      "private int $name$MemoizedSerializedSize;\n");
193  }
194}
195
196void RepeatedEnumFieldGenerator::
197GenerateBuilderMembers(io::Printer* printer) const {
198  printer->Print(variables_,
199    // Note:  We return an unmodifiable list because otherwise the caller
200    //   could hold on to the returned list and modify it after the message
201    //   has been built, thus mutating the message which is supposed to be
202    //   immutable.
203    "public java.util.List<$type$> get$capitalized_name$List() {\n"
204    "  return java.util.Collections.unmodifiableList(result.$name$_);\n"
205    "}\n"
206    "public int get$capitalized_name$Count() {\n"
207    "  return result.get$capitalized_name$Count();\n"
208    "}\n"
209    "public $type$ get$capitalized_name$(int index) {\n"
210    "  return result.get$capitalized_name$(index);\n"
211    "}\n"
212    "public Builder set$capitalized_name$(int index, $type$ value) {\n"
213    "  if (value == null) {\n"
214    "    throw new NullPointerException();\n"
215    "  }\n"
216    "  result.$name$_.set(index, value);\n"
217    "  return this;\n"
218    "}\n"
219    "public Builder add$capitalized_name$($type$ value) {\n"
220    "  if (value == null) {\n"
221    "    throw new NullPointerException();\n"
222    "  }\n"
223    "  if (result.$name$_.isEmpty()) {\n"
224    "    result.$name$_ = new java.util.ArrayList<$type$>();\n"
225    "  }\n"
226    "  result.$name$_.add(value);\n"
227    "  return this;\n"
228    "}\n"
229    "public Builder addAll$capitalized_name$(\n"
230    "    java.lang.Iterable<? extends $type$> values) {\n"
231    "  if (result.$name$_.isEmpty()) {\n"
232    "    result.$name$_ = new java.util.ArrayList<$type$>();\n"
233    "  }\n"
234    "  super.addAll(values, result.$name$_);\n"
235    "  return this;\n"
236    "}\n"
237    "public Builder clear$capitalized_name$() {\n"
238    "  result.$name$_ = java.util.Collections.emptyList();\n"
239    "  return this;\n"
240    "}\n");
241}
242
243void RepeatedEnumFieldGenerator::
244GenerateMergingCode(io::Printer* printer) const {
245  printer->Print(variables_,
246    "if (!other.$name$_.isEmpty()) {\n"
247    "  if (result.$name$_.isEmpty()) {\n"
248    "    result.$name$_ = new java.util.ArrayList<$type$>();\n"
249    "  }\n"
250    "  result.$name$_.addAll(other.$name$_);\n"
251    "}\n");
252}
253
254void RepeatedEnumFieldGenerator::
255GenerateBuildingCode(io::Printer* printer) const {
256  printer->Print(variables_,
257    "if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n"
258    "  result.$name$_ =\n"
259    "    java.util.Collections.unmodifiableList(result.$name$_);\n"
260    "}\n");
261}
262
263void RepeatedEnumFieldGenerator::
264GenerateParsingCode(io::Printer* printer) const {
265  // If packed, set up the while loop
266  if (descriptor_->options().packed()) {
267    printer->Print(variables_,
268      "int length = input.readRawVarint32();\n"
269      "int oldLimit = input.pushLimit(length);\n"
270      "while(input.getBytesUntilLimit() > 0) {\n");
271    printer->Indent();
272  }
273
274  // Read and store the enum
275  printer->Print(variables_,
276    "int rawValue = input.readEnum();\n"
277    "$type$ value = $type$.valueOf(rawValue);\n");
278  if (HasUnknownFields(descriptor_->containing_type())) {
279    printer->Print(variables_,
280      "if (value == null) {\n"
281      "  unknownFields.mergeVarintField($number$, rawValue);\n"
282      "} else {\n");
283  } else {
284    printer->Print(variables_,
285      "if (value != null) {\n");
286  }
287  printer->Print(variables_,
288    "  add$capitalized_name$(value);\n"
289    "}\n");
290
291  if (descriptor_->options().packed()) {
292    printer->Outdent();
293    printer->Print(variables_,
294      "}\n"
295      "input.popLimit(oldLimit);\n");
296  }
297}
298
299void RepeatedEnumFieldGenerator::
300GenerateSerializationCode(io::Printer* printer) const {
301  if (descriptor_->options().packed()) {
302    printer->Print(variables_,
303      "if (get$capitalized_name$List().size() > 0) {\n"
304      "  output.writeRawVarint32($tag$);\n"
305      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
306      "}\n"
307      "for ($type$ element : get$capitalized_name$List()) {\n"
308      "  output.writeEnumNoTag(element.getNumber());\n"
309      "}\n");
310  } else {
311    printer->Print(variables_,
312      "for ($type$ element : get$capitalized_name$List()) {\n"
313      "  output.writeEnum($number$, element.getNumber());\n"
314      "}\n");
315  }
316}
317
318void RepeatedEnumFieldGenerator::
319GenerateSerializedSizeCode(io::Printer* printer) const {
320  printer->Print(variables_,
321    "{\n"
322    "  int dataSize = 0;\n");
323  printer->Indent();
324
325  printer->Print(variables_,
326    "for ($type$ element : get$capitalized_name$List()) {\n"
327    "  dataSize += com.google.protobuf.CodedOutputStream\n"
328    "    .computeEnumSizeNoTag(element.getNumber());\n"
329    "}\n");
330  printer->Print(
331    "size += dataSize;\n");
332  if (descriptor_->options().packed()) {
333    printer->Print(variables_,
334      "if (!get$capitalized_name$List().isEmpty()) {"
335      "  size += $tag_size$;\n"
336      "  size += com.google.protobuf.CodedOutputStream\n"
337      "    .computeRawVarint32Size(dataSize);\n"
338      "}");
339  } else {
340    printer->Print(variables_,
341      "size += $tag_size$ * get$capitalized_name$List().size();\n");
342  }
343
344  // cache the data size for packed fields.
345  if (descriptor_->options().packed()) {
346    printer->Print(variables_,
347      "$name$MemoizedSerializedSize = dataSize;\n");
348  }
349
350  printer->Outdent();
351  printer->Print("}\n");
352}
353
354string RepeatedEnumFieldGenerator::GetBoxedType() const {
355  return ClassName(descriptor_->enum_type());
356}
357
358}  // namespace java
359}  // namespace compiler
360}  // namespace protobuf
361}  // namespace google
362