aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler/js/js_generator.cc
diff options
context:
space:
mode:
authorGravatar Adam Cozzette <acozzette@google.com>2016-06-29 15:23:27 -0700
committerGravatar Adam Cozzette <acozzette@google.com>2016-06-29 15:38:03 -0700
commitd64a2d9941c36a7bc2a7959ea10ab8363192ac14 (patch)
tree52330d146ad63d3d70f3baade00d5d1fea8f5e0c /src/google/protobuf/compiler/js/js_generator.cc
parentc18aa7795a2e02ef700ff8b039d94ecdcc33432f (diff)
Integrated internal changes from Google
This includes all internal changes from around May 20 to now.
Diffstat (limited to 'src/google/protobuf/compiler/js/js_generator.cc')
-rwxr-xr-xsrc/google/protobuf/compiler/js/js_generator.cc405
1 files changed, 296 insertions, 109 deletions
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index 8fb24bed..f5185ab1 100755
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -28,7 +28,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <google/protobuf/compiler/js/js_generator.h>
+#include "google/protobuf/compiler/js/js_generator.h"
#include <assert.h>
#include <algorithm>
@@ -444,6 +444,11 @@ bool IgnoreField(const FieldDescriptor* field) {
}
+// Do we ignore this message type?
+bool IgnoreMessage(const GeneratorOptions& options, const Descriptor* d) {
+ return d->options().map_entry();
+}
+
// Does JSPB ignore this entire oneof? True only if all fields are ignored.
bool IgnoreOneof(const OneofDescriptor* oneof) {
for (int i = 0; i < oneof->field_count(); i++) {
@@ -454,7 +459,8 @@ bool IgnoreOneof(const OneofDescriptor* oneof) {
return true;
}
-string JSIdent(const FieldDescriptor* field,
+string JSIdent(const GeneratorOptions& options,
+ const FieldDescriptor* field,
bool is_upper_camel,
bool is_map) {
string result;
@@ -467,16 +473,20 @@ string JSIdent(const FieldDescriptor* field,
ToUpperCamel(ParseLowerUnderscore(field->name())) :
ToLowerCamel(ParseLowerUnderscore(field->name()));
}
- if (is_map) {
+ if (is_map || (field->is_map())) {
+ // JSPB-style or proto3-style map.
result += "Map";
} else if (field->is_repeated()) {
+ // Repeated field.
result += "List";
}
return result;
}
-string JSObjectFieldName(const FieldDescriptor* field) {
+string JSObjectFieldName(const GeneratorOptions& options,
+ const FieldDescriptor* field) {
string name = JSIdent(
+ options,
field,
/* is_upper_camel = */ false,
/* is_map = */ false);
@@ -502,9 +512,10 @@ string JSByteGetterSuffix(BytesMode bytes_mode) {
// Returns the field name as a capitalized portion of a getter/setter method
// name, e.g. MyField for .getMyField().
-string JSGetterName(const FieldDescriptor* field,
+string JSGetterName(const GeneratorOptions& options,
+ const FieldDescriptor* field,
BytesMode bytes_mode = BYTES_DEFAULT) {
- string name = JSIdent(field,
+ string name = JSIdent(options, field,
/* is_upper_camel = */ true,
/* is_map = */ false);
if (field->type() == FieldDescriptor::TYPE_BYTES) {
@@ -520,8 +531,9 @@ string JSGetterName(const FieldDescriptor* field,
return name;
}
-string JSMapGetterName(const FieldDescriptor* field) {
- return JSIdent(field,
+string JSMapGetterName(const GeneratorOptions& options,
+ const FieldDescriptor* field) {
+ return JSIdent(options, field,
/* is_upper_camel = */ true,
/* is_map = */ true);
}
@@ -967,12 +979,24 @@ string JSBinaryReadWriteMethodName(const FieldDescriptor* field,
return name;
}
-string JSBinaryReaderMethodName(const FieldDescriptor* field) {
- return "read" + JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
+string JSBinaryReaderMethodName(const GeneratorOptions& options,
+ const FieldDescriptor* field) {
+ if (options.binary) {
+ return "jspb.BinaryReader.prototype.read" +
+ JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
+ } else {
+ return "null";
+ }
}
-string JSBinaryWriterMethodName(const FieldDescriptor* field) {
- return "write" + JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
+string JSBinaryWriterMethodName(const GeneratorOptions& options,
+ const FieldDescriptor* field) {
+ if (options.binary) {
+ return "jspb.BinaryWriter.prototype.write" +
+ JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
+ } else {
+ return "null";
+ }
}
string JSReturnClause(const FieldDescriptor* desc) {
@@ -986,7 +1010,7 @@ string JSReturnDoc(const GeneratorOptions& options,
bool HasRepeatedFields(const Descriptor* desc) {
for (int i = 0; i < desc->field_count(); i++) {
- if (desc->field(i)->is_repeated()) {
+ if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) {
return true;
}
}
@@ -1021,7 +1045,7 @@ string OneofFieldsArrayName(const GeneratorOptions& options,
string RepeatedFieldNumberList(const Descriptor* desc) {
std::vector<string> numbers;
for (int i = 0; i < desc->field_count(); i++) {
- if (desc->field(i)->is_repeated()) {
+ if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) {
numbers.push_back(JSFieldIndex(desc->field(i)));
}
}
@@ -1092,27 +1116,58 @@ string JSExtensionsObjectName(const GeneratorOptions& options,
}
}
+static const int kMapKeyField = 1;
+static const int kMapValueField = 2;
+
+const FieldDescriptor* MapFieldKey(const FieldDescriptor* field) {
+ assert(field->is_map());
+ return field->message_type()->FindFieldByNumber(kMapKeyField);
+}
+
+const FieldDescriptor* MapFieldValue(const FieldDescriptor* field) {
+ assert(field->is_map());
+ return field->message_type()->FindFieldByNumber(kMapValueField);
+}
+
string FieldDefinition(const GeneratorOptions& options,
const FieldDescriptor* field) {
- string qualifier = field->is_repeated() ? "repeated" :
- (field->is_optional() ? "optional" : "required");
- string type, name;
- if (field->type() == FieldDescriptor::TYPE_ENUM ||
- field->type() == FieldDescriptor::TYPE_MESSAGE) {
- type = RelativeTypeName(field);
- name = field->name();
- } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
- type = "group";
- name = field->message_type()->name();
+ if (field->is_map()) {
+ const FieldDescriptor* key_field = MapFieldKey(field);
+ const FieldDescriptor* value_field = MapFieldValue(field);
+ string key_type = ProtoTypeName(options, key_field);
+ string value_type;
+ if (value_field->type() == FieldDescriptor::TYPE_ENUM ||
+ value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ value_type = RelativeTypeName(value_field);
+ } else {
+ value_type = ProtoTypeName(options, value_field);
+ }
+ return StringPrintf("map<%s, %s> %s = %d;",
+ key_type.c_str(),
+ value_type.c_str(),
+ field->name().c_str(),
+ field->number());
} else {
- type = ProtoTypeName(options, field);
- name = field->name();
+ string qualifier = field->is_repeated() ? "repeated" :
+ (field->is_optional() ? "optional" : "required");
+ string type, name;
+ if (field->type() == FieldDescriptor::TYPE_ENUM ||
+ field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ type = RelativeTypeName(field);
+ name = field->name();
+ } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
+ type = "group";
+ name = field->message_type()->name();
+ } else {
+ type = ProtoTypeName(options, field);
+ name = field->name();
+ }
+ return StringPrintf("%s %s %s = %d;",
+ qualifier.c_str(),
+ type.c_str(),
+ name.c_str(),
+ field->number());
}
- return StringPrintf("%s %s %s = %d;",
- qualifier.c_str(),
- type.c_str(),
- name.c_str(),
- field->number());
}
string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) {
@@ -1417,6 +1472,10 @@ void Generator::FindProvidesForMessage(
io::Printer* printer,
const Descriptor* desc,
std::set<string>* provided) const {
+ if (IgnoreMessage(options, desc)) {
+ return;
+ }
+
string name = GetPath(options, desc);
provided->insert(name);
@@ -1451,7 +1510,8 @@ void Generator::FindProvidesForFields(
}
string name =
- GetPath(options, field->file()) + "." + JSObjectFieldName(field);
+ GetPath(options, field->file()) + "." +
+ JSObjectFieldName(options, field);
provided->insert(name);
}
}
@@ -1494,10 +1554,13 @@ void Generator::GenerateRequiresForLibrary(
for (int i = 0; i < files.size(); i++) {
for (int j = 0; j < files[i]->message_type_count(); j++) {
- FindRequiresForMessage(options,
- files[i]->message_type(j),
- &required, &forwards, &have_message);
+ const Descriptor* desc = files[i]->message_type(j);
+ if (!IgnoreMessage(options, desc)) {
+ FindRequiresForMessage(options, desc, &required, &forwards,
+ &have_message);
+ }
}
+
if (!have_extensions && HasExtensions(files[i])) {
have_extensions = true;
}
@@ -1632,7 +1695,9 @@ void Generator::FindRequiresForField(const GeneratorOptions& options,
forwards->insert(GetPath(options, field->enum_type()));
}
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- required->insert(GetPath(options, field->message_type()));
+ if (!IgnoreMessage(options, field->message_type())) {
+ required->insert(GetPath(options, field->message_type()));
+ }
}
}
@@ -1668,6 +1733,10 @@ void Generator::GenerateClassesAndEnums(const GeneratorOptions& options,
void Generator::GenerateClass(const GeneratorOptions& options,
io::Printer* printer,
const Descriptor* desc) const {
+ if (IgnoreMessage(options, desc)) {
+ return;
+ }
+
if (!NamespaceOnly(desc)) {
printer->Print("\n");
GenerateClassConstructor(options, printer, desc);
@@ -1932,21 +2001,24 @@ void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
io::Printer* printer,
const FieldDescriptor* field) const {
printer->Print("$fieldname$: ",
- "fieldname", JSObjectFieldName(field));
+ "fieldname", JSObjectFieldName(options, field));
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (field->is_map()) {
+ printer->Print("(f = msg.get$name$(true)) ? f.toArray() : []",
+ "name", JSGetterName(options, field));
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
// Message field.
if (field->is_repeated()) {
{
printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n"
" $type$.toObject, includeInstance)",
- "getter", JSGetterName(field),
+ "getter", JSGetterName(options, field),
"type", SubmessageTypeRef(options, field));
}
} else {
printer->Print("(f = msg.get$getter$()) && "
"$type$.toObject(includeInstance, f)",
- "getter", JSGetterName(field),
+ "getter", JSGetterName(options, field),
"type", SubmessageTypeRef(options, field));
}
} else {
@@ -1956,7 +2028,7 @@ void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
// Delegate to the generated get<field>() method in order not to duplicate
// the proto3-field-default-value or byte-coercion logic here.
printer->Print("msg.get$getter$()",
- "getter", JSGetterName(field, BYTES_B64));
+ "getter", JSGetterName(options, field, BYTES_B64));
} else {
if (field->has_default_value()) {
printer->Print("jspb.Message.getField(msg, $index$) == null ? "
@@ -2017,7 +2089,17 @@ void Generator::GenerateClassFieldFromObject(
const GeneratorOptions& options,
io::Printer* printer,
const FieldDescriptor* field) const {
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+
+ if (field->is_map()) {
+ // `msg` is a newly-constructed message object that has not yet built any
+ // map containers wrapping underlying arrays, so we can simply directly set
+ // the array here without fear of a stale wrapper.
+ printer->Print(
+ " goog.isDef(obj.$name$) && "
+ "jspb.Message.setField(msg, $index$, obj.$name$);\n",
+ "name", JSObjectFieldName(options, field),
+ "index", JSFieldIndex(field));
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
// Message field (singular or repeated)
if (field->is_repeated()) {
{
@@ -2027,7 +2109,7 @@ void Generator::GenerateClassFieldFromObject(
" msg, $index$, goog.array.map(obj.$name$, function(i) {\n"
" return $fieldclass$.fromObject(i);\n"
" }));\n",
- "name", JSObjectFieldName(field),
+ "name", JSObjectFieldName(options, field),
"index", JSFieldIndex(field),
"fieldclass", SubmessageTypeRef(options, field));
}
@@ -2035,7 +2117,7 @@ void Generator::GenerateClassFieldFromObject(
printer->Print(
" goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n"
" msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
- "name", JSObjectFieldName(field),
+ "name", JSObjectFieldName(options, field),
"index", JSFieldIndex(field),
"fieldclass", SubmessageTypeRef(options, field));
}
@@ -2044,7 +2126,7 @@ void Generator::GenerateClassFieldFromObject(
printer->Print(
" goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, "
"obj.$name$);\n",
- "name", JSObjectFieldName(field),
+ "name", JSObjectFieldName(options, field),
"index", JSFieldIndex(field));
}
}
@@ -2114,17 +2196,93 @@ void GenerateBytesWrapper(const GeneratorOptions& options,
"comment", FieldComments(field, bytes_mode),
"type", type,
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field, bytes_mode),
+ "name", JSGetterName(options, field, bytes_mode),
"list", field->is_repeated() ? "List" : "",
"suffix", JSByteGetterSuffix(bytes_mode),
- "defname", JSGetterName(field, BYTES_DEFAULT));
+ "defname", JSGetterName(options, field, BYTES_DEFAULT));
}
void Generator::GenerateClassField(const GeneratorOptions& options,
io::Printer* printer,
const FieldDescriptor* field) const {
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (field->is_map()) {
+ const FieldDescriptor* key_field = MapFieldKey(field);
+ const FieldDescriptor* value_field = MapFieldValue(field);
+ // Map field: special handling to instantiate the map object on demand.
+ string key_type =
+ JSFieldTypeAnnotation(
+ options, key_field,
+ /* force_optional = */ false,
+ /* force_present = */ true,
+ /* singular_if_not_packed = */ false);
+ string value_type =
+ JSFieldTypeAnnotation(
+ options, value_field,
+ /* force_optional = */ false,
+ /* force_present = */ true,
+ /* singular_if_not_packed = */ false);
+
+ printer->Print(
+ "/**\n"
+ " * $fielddef$\n"
+ " * @param {boolean=} opt_noLazyCreate Do not create the map if\n"
+ " * empty, instead returning `undefined`\n"
+ " * @return {!jspb.Map<$keytype$,$valuetype$>}\n"
+ " */\n",
+ "fielddef", FieldDefinition(options, field),
+ "keytype", key_type,
+ "valuetype", value_type);
+ printer->Print(
+ "$class$.prototype.get$name$ = function(opt_noLazyCreate) {\n"
+ " return /** @type {!jspb.Map<$keytype$,$valuetype$>} */ (\n",
+ "class", GetPath(options, field->containing_type()),
+ "name", JSGetterName(options, field),
+ "keytype", key_type,
+ "valuetype", value_type);
+ printer->Print(
+ " jspb.Message.getMapField(this, $index$, opt_noLazyCreate",
+ "index", JSFieldIndex(field));
+
+ if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ printer->Print(",\n"
+ " $messageType$",
+ "messageType", GetPath(options, value_field->message_type()));
+ } else if (options.binary) {
+ printer->Print(",\n"
+ " null");
+ }
+
+ if (options.binary) {
+ printer->Print(",\n"
+ " $keyWriterFn$,\n"
+ " $keyReaderFn$,\n"
+ " $valueWriterFn$,\n"
+ " $valueReaderFn$",
+ "keyWriterFn", JSBinaryWriterMethodName(options, key_field),
+ "keyReaderFn", JSBinaryReaderMethodName(options, key_field),
+ "valueWriterFn", JSBinaryWriterMethodName(options, value_field),
+ "valueReaderFn", JSBinaryReaderMethodName(options, value_field));
+
+ if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ printer->Print(",\n"
+ " $messageType$.serializeBinaryToWriter,\n"
+ " $messageType$.deserializeBinaryFromReader",
+ "messageType", GetPath(options, value_field->message_type()));
+ }
+ }
+
+ printer->Print(
+ "));\n");
+
+ printer->Print(
+ "};\n"
+ "\n"
+ "\n");
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ // Message field: special handling in order to wrap the underlying data
+ // array with a message object.
+
printer->Print(
"/**\n"
" * $fielddef$\n"
@@ -2146,7 +2304,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"\n"
"\n",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field),
+ "name", JSGetterName(options, field),
"type", JSFieldTypeAnnotation(options, field,
/* force_optional = */ false,
/* force_present = */ false,
@@ -2167,7 +2325,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
/* singular_if_not_packed = */ false),
"returndoc", JSReturnDoc(options, field),
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field),
+ "name", JSGetterName(options, field),
"oneoftag", (field->containing_oneof() ? "Oneof" : ""),
"repeatedtag", (field->is_repeated() ? "Repeated" : ""));
@@ -2188,7 +2346,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"\n"
"\n",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field),
+ "name", JSGetterName(options, field),
"clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
"returnvalue", JSReturnClause(field));
@@ -2230,7 +2388,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
printer->Print(
"$class$.prototype.get$name$ = function() {\n",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field));
+ "name", JSGetterName(options, field));
if (untyped) {
printer->Print(
@@ -2315,7 +2473,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"$class$.prototype.set$name$ = function(value) {\n"
" jspb.Message.set$oneoftag$Field(this, $index$",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field),
+ "name", JSGetterName(options, field),
"oneoftag", (field->containing_oneof() ? "Oneof" : ""),
"index", JSFieldIndex(field));
printer->Print(
@@ -2345,7 +2503,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"$class$.prototype.clear$name$ = function() {\n"
" jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field),
+ "name", JSGetterName(options, field),
"oneoftag", (field->containing_oneof() ? "Oneof" : ""),
"oneofgroup", (field->containing_oneof() ?
(", " + JSOneofArray(options, field)) : ""),
@@ -2461,40 +2619,49 @@ void Generator::GenerateClassDeserializeBinaryField(
printer->Print(" case $num$:\n",
"num", SimpleItoa(field->number()));
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- printer->Print(
- " var value = new $fieldclass$;\n"
- " reader.read$msgOrGroup$($grpfield$value,"
- "$fieldclass$.deserializeBinaryFromReader);\n",
- "fieldclass", SubmessageTypeRef(options, field),
- "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ?
- "Group" : "Message",
- "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ?
- (SimpleItoa(field->number()) + ", ") : "");
- } else {
+ if (field->is_map()) {
printer->Print(
- " var value = /** @type {$fieldtype$} */ (reader.$reader$());\n",
- "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
- /* singular_if_not_packed = */ true,
- BYTES_U8),
- "reader", JSBinaryReaderMethodName(field));
- }
-
- if (field->is_repeated() && !field->is_packed()) {
- // Repeated fields receive a |value| one at at a time; append to array
- // returned by get$name$(). Annoyingly, we have to call 'set' after
- // changing the array.
- printer->Print(" msg.get$name$().push(value);\n", "name",
- JSGetterName(field));
- printer->Print(" msg.set$name$(msg.get$name$());\n", "name",
- JSGetterName(field));
+ " var value = msg.get$name$();\n"
+ " reader.readMessage(value, jspb.Map.deserializeBinary);\n",
+ "name", JSGetterName(options, field));
} else {
- // Singular fields, and packed repeated fields, receive a |value| either as
- // the field's value or as the array of all the field's values; set this as
- // the field's value directly.
- printer->Print(
- " msg.set$name$(value);\n",
- "name", JSGetterName(field));
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ printer->Print(
+ " var value = new $fieldclass$;\n"
+ " reader.read$msgOrGroup$($grpfield$value,"
+ "$fieldclass$.deserializeBinaryFromReader);\n",
+ "fieldclass", SubmessageTypeRef(options, field),
+ "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ?
+ "Group" : "Message",
+ "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ?
+ (SimpleItoa(field->number()) + ", ") : "");
+ } else {
+ printer->Print(
+ " var value = /** @type {$fieldtype$} */ "
+ "(reader.read$reader$());\n",
+ "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
+ /* singular_if_not_packed */ true,
+ BYTES_U8),
+ "reader",
+ JSBinaryReadWriteMethodName(field, /* is_writer = */ false));
+ }
+
+ if (field->is_repeated() && !field->is_packed()) {
+ // Repeated fields receive a |value| one at at a time; append to array
+ // returned by get$name$(). Annoyingly, we have to call 'set' after
+ // changing the array.
+ printer->Print(" msg.get$name$().push(value);\n", "name",
+ JSGetterName(options, field));
+ printer->Print(" msg.set$name$(msg.get$name$());\n", "name",
+ JSGetterName(options, field));
+ } else {
+ // Singular fields, and packed repeated fields, receive a |value| either
+ // as the field's value or as the array of all the field's values; set
+ // this as the field's value directly.
+ printer->Print(
+ " msg.set$name$(value);\n",
+ "name", JSGetterName(options, field));
+ }
}
printer->Print(" break;\n");
@@ -2559,10 +2726,18 @@ void Generator::GenerateClassSerializeBinaryField(
io::Printer* printer,
const FieldDescriptor* field) const {
printer->Print(
- " f = this.get$name$();\n",
- "name", JSGetterName(field, BYTES_U8));
+ " f = this.get$name$($nolazy$);\n",
+ "name", JSGetterName(options, field, BYTES_U8),
+ // No lazy creation for maps containers -- fastpath the empty case.
+ "nolazy", (field->is_map()) ? "true" : "");
- if (field->is_repeated()) {
+
+ // Print an `if (condition)` statement that evaluates to true if the field
+ // goes on the wire.
+ if (field->is_map()) {
+ printer->Print(
+ " if (f && f.getLength() > 0) {\n");
+ } else if (field->is_repeated()) {
printer->Print(
" if (f.length > 0) {\n");
} else {
@@ -2605,23 +2780,35 @@ void Generator::GenerateClassSerializeBinaryField(
}
}
- printer->Print(
- " writer.$writer$(\n"
- " $index$,\n"
- " f",
- "writer", JSBinaryWriterMethodName(field),
- "index", SimpleItoa(field->number()));
-
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ // Write the field on the wire.
+ if (field->is_map()) {
printer->Print(
- ",\n"
- " $submsg$.serializeBinaryToWriter\n",
- "submsg", SubmessageTypeRef(options, field));
+ " f.serializeBinary($index$, writer);\n",
+ "index", SimpleItoa(field->number()));
} else {
- printer->Print("\n");
+ printer->Print(
+ " writer.write$method$(\n"
+ " $index$,\n"
+ " f",
+ "method", JSBinaryReadWriteMethodName(field, /* is_writer = */ true),
+ "index", SimpleItoa(field->number()));
+
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+ !(field->is_map())) {
+ printer->Print(
+ ",\n"
+ " $submsg$.serializeBinaryToWriter\n",
+ "submsg", SubmessageTypeRef(options, field));
+ } else {
+ printer->Print("\n");
+ }
+
+ printer->Print(
+ " );\n");
}
+
+ // Close the `if`.
printer->Print(
- " );\n"
" }\n");
}
@@ -2665,7 +2852,7 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
" * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n"
" */\n"
"$class$.$name$ = new jspb.ExtensionFieldInfo(\n",
- "name", JSObjectFieldName(field),
+ "name", JSObjectFieldName(options, field),
"class", extension_scope,
"extensionType", JSFieldTypeAnnotation(
options, field,
@@ -2681,7 +2868,7 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
" $toObject$),\n"
" $repeated$",
"index", SimpleItoa(field->number()),
- "name", JSObjectFieldName(field),
+ "name", JSObjectFieldName(options, field),
"ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
SubmessageTypeRef(options, field) : string("null")),
"toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
@@ -2692,13 +2879,13 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
if (options.binary) {
printer->Print(
",\n"
- " jspb.BinaryReader.prototype.$binaryReaderFn$,\n"
- " jspb.BinaryWriter.prototype.$binaryWriterFn$,\n"
+ " $binaryReaderFn$,\n"
+ " $binaryWriterFn$,\n"
" $binaryMessageSerializeFn$,\n"
" $binaryMessageDeserializeFn$,\n"
" $isPacked$);\n",
- "binaryReaderFn", JSBinaryReaderMethodName(field),
- "binaryWriterFn", JSBinaryWriterMethodName(field),
+ "binaryReaderFn", JSBinaryReaderMethodName(options, field),
+ "binaryWriterFn", JSBinaryWriterMethodName(options, field),
"binaryMessageSerializeFn",
(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
(SubmessageTypeRef(options, field) +
@@ -2721,7 +2908,7 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
field->containing_type()),
"index", SimpleItoa(field->number()),
"class", extension_scope,
- "name", JSObjectFieldName(field));
+ "name", JSObjectFieldName(options, field));
}
bool GeneratorOptions::ParseFromOptions(