Protobuf: changed all arrays in generated code into primitive arrays
This commit is contained in:
Binary file not shown.
+1
-1
@@ -149,7 +149,7 @@ void ClassGenerator::generateMergeMethods(io::Printer *printer) const {
|
|||||||
|
|
||||||
// concatenate repeated fields
|
// concatenate repeated fields
|
||||||
if (properties[i]->getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
|
if (properties[i]->getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
|
||||||
printer->Print(vars, "$fieldName$.addAll(other.$fieldName$)\n");
|
printer->Print(vars, "$fieldName$ = $fieldName$.plus((other.$fieldName$))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bytes type is handled separately
|
// Bytes type is handled separately
|
||||||
|
|||||||
+84
-177
@@ -17,7 +17,7 @@ namespace kotlin {
|
|||||||
|
|
||||||
string FieldGenerator::getInitValue() const {
|
string FieldGenerator::getInitValue() const {
|
||||||
if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
|
if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
|
||||||
return "mutableListOf()";
|
return getFullType() + "(0)";
|
||||||
}
|
}
|
||||||
if (getProtoType() == FieldDescriptor::TYPE_MESSAGE) {
|
if (getProtoType() == FieldDescriptor::TYPE_MESSAGE) {
|
||||||
return getBuilderFullType() + "().build()";
|
return getBuilderFullType() + "().build()";
|
||||||
@@ -58,12 +58,13 @@ FieldGenerator::FieldGenerator(FieldDescriptor const * descriptor, ClassGenerato
|
|||||||
, protoLabel(descriptor->label())
|
, protoLabel(descriptor->label())
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool isRead, bool noTag) const {
|
void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool isRead, bool noTag, bool isField) const {
|
||||||
map <string, string> vars;
|
map <string, string> vars;
|
||||||
vars["fieldNumber"] = std::to_string(getFieldNumber());
|
vars["fieldNumber"] = std::to_string(getFieldNumber());
|
||||||
vars["builderType"] = getUnderlyingTypeGenerator().getFullType();
|
vars["underlyingType"] = getUnderlyingTypeGenerator().getFullType();
|
||||||
vars["initValue"] = getUnderlyingTypeGenerator().getInitValue();
|
vars["initValue"] = getUnderlyingTypeGenerator().getInitValue();
|
||||||
vars["fieldName"] = simpleName;
|
vars["fieldName"] = simpleName;
|
||||||
|
vars["arrayType"] = getFullType();
|
||||||
|
|
||||||
bool isPrimitive = descriptor->type() != FieldDescriptor::TYPE_BYTES &&
|
bool isPrimitive = descriptor->type() != FieldDescriptor::TYPE_BYTES &&
|
||||||
descriptor->type() != FieldDescriptor::TYPE_MESSAGE &&
|
descriptor->type() != FieldDescriptor::TYPE_MESSAGE &&
|
||||||
@@ -74,10 +75,12 @@ void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool i
|
|||||||
if (!noTag) {
|
if (!noTag) {
|
||||||
printer->Print(vars, "val tag = input.readTag($fieldNumber$, WireType.LENGTH_DELIMITED)\n");
|
printer->Print(vars, "val tag = input.readTag($fieldNumber$, WireType.LENGTH_DELIMITED)\n");
|
||||||
}
|
}
|
||||||
printer->Print(vars, "val expectedSize = input.readInt32NoTag()\n");
|
printer->Print(vars, "val expectedByteSize = input.readInt32NoTag()\n");
|
||||||
printer->Print("var readSize = 0\n");
|
|
||||||
printer->Print(vars, "while(readSize != expectedSize) {\n");
|
/* Now we want to compute element size of array. For this, we are estimating byte size of a single element,
|
||||||
printer->Indent();
|
* and then divide byte size of whole array by byte size of single element.
|
||||||
|
*/
|
||||||
|
printer->Print(vars, "var singleElemSize = 0\n");
|
||||||
|
|
||||||
/* hack: copy current FieldGenerator and change label to OPTIONAL. Also change name to
|
/* hack: copy current FieldGenerator and change label to OPTIONAL. Also change name to
|
||||||
name of iterator in for-loop.
|
name of iterator in for-loop.
|
||||||
@@ -89,40 +92,44 @@ void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool i
|
|||||||
(then writing CodedOutputStream.writeMessage will be possible).
|
(then writing CodedOutputStream.writeMessage will be possible).
|
||||||
*/
|
*/
|
||||||
FieldGenerator singleFieldGen = getUnderlyingTypeGenerator();
|
FieldGenerator singleFieldGen = getUnderlyingTypeGenerator();
|
||||||
|
singleFieldGen.simpleName = "singleElemSize";
|
||||||
|
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ true, /* isField = */ false);
|
||||||
|
|
||||||
/* Another dirty hack here: create tmp variable of a given type and read it from input stream
|
printer->Print(vars, "val arraySize = expectedByteSize / singleElemSize\n");
|
||||||
then add that tmp var into list.
|
|
||||||
This is made because simple recursive call will generate code that tries to array[i].mergeFrom().
|
// Allocate new array of estimated size
|
||||||
This is incorrect because array has old size, while 'i' iterates over new size, which can lead
|
printer->Print(vars, "val newArray = $arrayType$(arraySize)\n");
|
||||||
to ArrayOutOfIndex errors.
|
|
||||||
*/
|
printer->Print("var i = 0\n");
|
||||||
printer->Print(vars, "var tmp: $builderType$ = $initValue$\n");
|
printer->Print(vars, "while(i < arraySize) {\n");
|
||||||
|
printer->Indent();
|
||||||
|
|
||||||
|
printer->Print(vars, "var tmp: $underlyingType$ = $initValue$\n");
|
||||||
singleFieldGen.simpleName = "tmp";
|
singleFieldGen.simpleName = "tmp";
|
||||||
singleFieldGen.protoLabel = FieldDescriptor::LABEL_OPTIONAL;
|
singleFieldGen.protoLabel = FieldDescriptor::LABEL_OPTIONAL;
|
||||||
|
|
||||||
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ true);
|
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ true, /* isField = */ false);
|
||||||
singleFieldGen.generateSizeEstimationCode(printer, /* varName = */
|
|
||||||
"readSize"); // add size of current element to total size //TODO: think is it's ok that we estimate size with tag here
|
|
||||||
|
|
||||||
printer->Print(vars, "$fieldName$.add(tmp)\n");
|
printer->Print(vars, "$fieldName$[i] = tmp\n");
|
||||||
|
printer->Print("i += 1\n");
|
||||||
|
|
||||||
printer->Outdent();
|
printer->Outdent();
|
||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/**
|
/**
|
||||||
* Protobuf format:
|
* Protobuf format:
|
||||||
* - Check if size of array is > 0, because empty repeated fields shouldn't appear in message
|
* - Check if size of array is > 0, because empty repeated fields shouldn't appear in message
|
||||||
* - Write tag explicitly
|
* - Write tag explicitly
|
||||||
* - Write length as int32 (note that tag shouldn't be added)
|
* - Write length as int32 (note that tag shouldn't be added)
|
||||||
* - Write all repeated elements via recursive call (for primitive types without tags)
|
* - Write all repeated elements via recursive call (for primitive types without tags)
|
||||||
*/
|
*/
|
||||||
// tag
|
// tag
|
||||||
printer->Print(vars, "output.writeTag($fieldNumber$, WireType.LENGTH_DELIMITED)\n");
|
printer->Print(vars, "output.writeTag($fieldNumber$, WireType.LENGTH_DELIMITED)\n");
|
||||||
|
|
||||||
// length
|
// length
|
||||||
printer->Print(vars, "var arrayByteSize = 0\n");
|
printer->Print(vars, "var arrayByteSize = 0\n");
|
||||||
generateSizeEstimationCode(printer, "arrayByteSize", /* noTag = */ true);
|
generateSizeEstimationCode(printer, "arrayByteSize", /* noTag = */ true, /* isField = */ false);
|
||||||
printer->Print(vars, "output.writeInt32NoTag(arrayByteSize)\n");
|
printer->Print(vars, "output.writeInt32NoTag(arrayByteSize)\n");
|
||||||
|
|
||||||
// all elements
|
// all elements
|
||||||
@@ -134,75 +141,14 @@ void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool i
|
|||||||
singleFieldGen.simpleName = "item";
|
singleFieldGen.simpleName = "item";
|
||||||
singleFieldGen.protoLabel = FieldDescriptor::LABEL_OPTIONAL;
|
singleFieldGen.protoLabel = FieldDescriptor::LABEL_OPTIONAL;
|
||||||
|
|
||||||
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ isPrimitive);
|
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ isPrimitive, /* isField = */ false);
|
||||||
|
|
||||||
printer->Outdent(); // for-loop
|
printer->Outdent(); // for-loop
|
||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldGenerator::generateSerializationForRepeated(io::Printer *printer, bool isRead, bool noTag) const {
|
void FieldGenerator::generateSerializationForEnums(io::Printer * printer, bool isRead, bool noTag, bool isField) const {
|
||||||
map <string, string> vars;
|
|
||||||
vars["fieldNumber"] = std::to_string(getFieldNumber());
|
|
||||||
vars["builderType"] = getUnderlyingTypeGenerator().getFullType();
|
|
||||||
vars["initValue"] = getUnderlyingTypeGenerator().getInitValue();
|
|
||||||
vars["fieldName"] = simpleName;
|
|
||||||
|
|
||||||
if (isRead) {
|
|
||||||
printer->Print("var readSize = 0\n");
|
|
||||||
/* hack: copy current FieldGenerator and change label to OPTIONAL. Also change name to
|
|
||||||
name of iterator in for-loop.
|
|
||||||
This will allow to re-use this function for generating serialization code for elements of array.
|
|
||||||
More importantly, this will care about nested types too.
|
|
||||||
Efficiently, it inlines serialization code for all underlying types.
|
|
||||||
This hack isn't necessary from the architectural point of view and could be safely
|
|
||||||
removed as soon as target code will support inheritance and interfaces.
|
|
||||||
(then writing CodedOutputStream.writeMessage will be possible).
|
|
||||||
*/
|
|
||||||
FieldGenerator singleFieldGen = getUnderlyingTypeGenerator();
|
|
||||||
|
|
||||||
/* Another dirty hack here: create tmp variable of a given type and read it from input stream
|
|
||||||
then add that tmp var into list.
|
|
||||||
This is made because simple recursive call will generate code that tries to array[i].mergeFrom().
|
|
||||||
This is incorrect because array has old size, while 'i' iterates over new size, which can lead
|
|
||||||
to ArrayOutOfIndex errors.
|
|
||||||
*/
|
|
||||||
printer->Print(vars, "var tmp: $builderType$ = $initValue$\n");
|
|
||||||
singleFieldGen.simpleName = "tmp";
|
|
||||||
singleFieldGen.protoLabel = FieldDescriptor::LABEL_OPTIONAL;
|
|
||||||
|
|
||||||
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ true);
|
|
||||||
singleFieldGen.generateSizeEstimationCode(printer, /* varName = */
|
|
||||||
"readSize", /* noTag = */ true); // add size of current element to total size. Note that
|
|
||||||
|
|
||||||
printer->Print(vars, "$fieldName$.add(tmp)\n");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/**
|
|
||||||
* Protobuf format:
|
|
||||||
* - Check if size of array is > 0, because empty repeated fields shouldn't appear in message
|
|
||||||
* - Write tag explicitly
|
|
||||||
* - Write length as int32 (note that tag shouldn't be added)
|
|
||||||
* - Write all repeated elements via recursive call (for primitive types without tags)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// all elements
|
|
||||||
printer->Print(vars, "for (item in $fieldName$) {\n");
|
|
||||||
printer->Indent();
|
|
||||||
|
|
||||||
// hack: see above
|
|
||||||
FieldGenerator singleFieldGen = FieldGenerator(descriptor, enclosingClass, nameResolver);
|
|
||||||
singleFieldGen.simpleName = "item";
|
|
||||||
singleFieldGen.protoLabel = FieldDescriptor::LABEL_OPTIONAL;
|
|
||||||
|
|
||||||
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ true);
|
|
||||||
|
|
||||||
printer->Outdent(); // for-loop
|
|
||||||
printer->Print("}\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FieldGenerator::generateSerializationForEnums(io::Printer * printer, bool isRead, bool noTag) const {
|
|
||||||
|
|
||||||
map <string, string> vars;
|
map <string, string> vars;
|
||||||
vars["converter"] = getEnumFromIntConverter();
|
vars["converter"] = getEnumFromIntConverter();
|
||||||
@@ -229,7 +175,7 @@ void FieldGenerator::generateSerializationForEnums(io::Printer * printer, bool i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldGenerator::generateSerializationForMessages(io::Printer * printer, bool isRead, bool noTag) const {
|
void FieldGenerator::generateSerializationForMessages(io::Printer * printer, bool isRead, bool noTag, bool isField) const {
|
||||||
map <string, string> vars;
|
map <string, string> vars;
|
||||||
vars["fieldNumber"] = std::to_string(getFieldNumber());
|
vars["fieldNumber"] = std::to_string(getFieldNumber());
|
||||||
vars["dollar"] = "$";
|
vars["dollar"] = "$";
|
||||||
@@ -274,7 +220,7 @@ void FieldGenerator::generateSerializationForMessages(io::Printer * printer, boo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldGenerator::generateSerializationForPrimitives(io::Printer * printer, bool isRead, bool noTag) const {
|
void FieldGenerator::generateSerializationForPrimitives(io::Printer * printer, bool isRead, bool noTag, bool isField) const {
|
||||||
map <string, string> vars;
|
map <string, string> vars;
|
||||||
vars["fieldName"] = simpleName;
|
vars["fieldName"] = simpleName;
|
||||||
vars["suffix"] = getKotlinFunctionSuffix();
|
vars["suffix"] = getKotlinFunctionSuffix();
|
||||||
@@ -297,7 +243,7 @@ void FieldGenerator::generateSerializationForPrimitives(io::Printer * printer, b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead, bool noTag) const {
|
void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead, bool noTag, bool isField) const {
|
||||||
map <string, string> vars;
|
map <string, string> vars;
|
||||||
vars["fieldName"] = simpleName;
|
vars["fieldName"] = simpleName;
|
||||||
vars["initValue"] = getInitValue();
|
vars["initValue"] = getInitValue();
|
||||||
@@ -307,60 +253,50 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
|
|||||||
* Note that it should be first check because of Google's FieldDescriptor structure */
|
* Note that it should be first check because of Google's FieldDescriptor structure */
|
||||||
if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
|
if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
|
||||||
// we shouldn't write fields with default values when writing
|
// we shouldn't write fields with default values when writing
|
||||||
if (!isRead) {
|
if (!isRead && isField) {
|
||||||
printer->Print(vars, "if ($fieldName$.size > 0) {\n");
|
printer->Print(vars, "if ($fieldName$.size > 0) {\n");
|
||||||
printer->Indent();
|
printer->Indent();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPrimitive = descriptor->type() != FieldDescriptor::TYPE_BYTES &&
|
bool isPrimitive = descriptor->type() != FieldDescriptor::TYPE_BYTES &&
|
||||||
descriptor->type() != FieldDescriptor::TYPE_MESSAGE &&
|
descriptor->type() != FieldDescriptor::TYPE_MESSAGE &&
|
||||||
descriptor->type() != FieldDescriptor::TYPE_STRING &&
|
descriptor->type() != FieldDescriptor::TYPE_STRING;
|
||||||
descriptor->type() != FieldDescriptor::TYPE_ENUM;
|
|
||||||
if (isPrimitive) {
|
if (isPrimitive) {
|
||||||
generateSerializationForPacked(printer, isRead, noTag);
|
generateSerializationForPacked(printer, isRead, noTag, isField);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
generateSerializationForRepeated(printer, isRead, noTag);
|
throw UnreachableStateException("Arrays of non-primitive types are not supported");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Then check is current field is enum. We have to handle it separately too, because
|
|
||||||
* we have to pass enums as Int's to CodedStreams as per protobuf-format */
|
|
||||||
else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
|
|
||||||
// we shouldn't write fields with default values when writing
|
|
||||||
if (!isRead) {
|
|
||||||
printer->Print(vars, "if ($fieldName$ != $initValue$) {\n");
|
|
||||||
printer->Indent();
|
|
||||||
}
|
|
||||||
|
|
||||||
generateSerializationForEnums(printer, isRead, noTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Then check for nested messages. Here we re-use writeTo method, that should be defined in
|
|
||||||
* that message.
|
|
||||||
* Note that readFrom/writeTo methods write message as it's top-level message, i.e. without
|
|
||||||
* any tags. Therefore, we have to prepend tags and size manually. */
|
|
||||||
else if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
|
|
||||||
// we shouldn't write fields with default values when writing
|
|
||||||
if (!isRead) {
|
|
||||||
printer->Print(vars, "if ($fieldName$ != $initValue$) {\n");
|
|
||||||
printer->Indent();
|
|
||||||
}
|
|
||||||
|
|
||||||
generateSerializationForMessages(printer, isRead, noTag);
|
|
||||||
}
|
|
||||||
/* Finally, serialize trivial cases */
|
|
||||||
else {
|
else {
|
||||||
// we shouldn't write fields with default values when writing
|
// we shouldn't write fair fields with default values
|
||||||
if (!isRead) {
|
if (!isRead && isField) {
|
||||||
printer->Print(vars, "if ($fieldName$ != $initValue$) {\n");
|
printer->Print(vars, "if ($fieldName$ != $initValue$) {\n");
|
||||||
printer->Indent();
|
printer->Indent();
|
||||||
}
|
}
|
||||||
|
|
||||||
generateSerializationForPrimitives(printer, isRead, noTag);
|
/* Then check is current field is enum. We have to handle it separately too, because
|
||||||
|
* we have to pass enums as Int's to CodedStreams as per protobuf-format */
|
||||||
|
if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
|
||||||
|
generateSerializationForEnums(printer, isRead, noTag, isField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then check for nested messages. Here we re-use writeTo method, that should be defined in
|
||||||
|
* that message.
|
||||||
|
* Note that readFrom/writeTo methods write message as it's top-level message, i.e. without
|
||||||
|
* any tags. Therefore, we have to prepend tags and size manually. */
|
||||||
|
else if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
|
||||||
|
generateSerializationForMessages(printer, isRead, noTag, isField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finally, serialize trivial cases */
|
||||||
|
else {
|
||||||
|
generateSerializationForPrimitives(printer, isRead, noTag, isField);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isRead) {
|
if (!isRead && isField) {
|
||||||
printer->Outdent();
|
printer->Outdent();
|
||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
}
|
}
|
||||||
@@ -392,45 +328,20 @@ void FieldGenerator::generateRepeatedMethods(io::Printer * printer, bool isBuild
|
|||||||
|
|
||||||
// generate indexed setter for builders
|
// generate indexed setter for builders
|
||||||
if (isBuilder) {
|
if (isBuilder) {
|
||||||
printer->Print(vars, "fun set$elementType$(index: Int, $arg$: $elementType$): $builderName$ {\n");
|
printer->Print(vars, "fun set$fieldName$ByIndex(index: Int, $arg$: $elementType$): $builderName$ {\n");
|
||||||
printer->Indent();
|
printer->Indent();
|
||||||
printer->Print(vars, "$fieldName$[index] = $arg$\n");
|
printer->Print(vars, "$fieldName$[index] = $arg$\n");
|
||||||
printer->Print(vars, "return this\n");
|
printer->Print(vars, "return this\n");
|
||||||
printer->Outdent();
|
printer->Outdent();
|
||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBuilder) {
|
|
||||||
// generate single-add for builders
|
|
||||||
printer->Print(vars, "fun add$elementType$($arg$: $elementType$): $builderName$ {\n");
|
|
||||||
printer->Indent();
|
|
||||||
printer->Print(vars, "$fieldName$.add($arg$)\n"
|
|
||||||
"return this\n");
|
|
||||||
printer->Outdent();
|
|
||||||
printer->Print(vars, "}\n");
|
|
||||||
|
|
||||||
// generate addAll for builders
|
|
||||||
printer->Print(vars, "fun addAll$elementType$($arg$: Iterable<$elementType$>): $builderName$ {\n");
|
|
||||||
printer->Indent();
|
|
||||||
printer->Print(vars, "for (item in $arg$) {\n");
|
|
||||||
printer->Indent();
|
|
||||||
printer->Print(vars, "$fieldName$.add(item)\n");
|
|
||||||
|
|
||||||
printer->Outdent(); // for-loop
|
|
||||||
printer->Print("}\n");
|
|
||||||
|
|
||||||
printer->Print("return this\n");
|
|
||||||
|
|
||||||
printer->Outdent(); // function body
|
|
||||||
printer->Print("}\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string FieldGenerator::getKotlinFunctionSuffix() const {
|
string FieldGenerator::getKotlinFunctionSuffix() const {
|
||||||
return name_resolving::protobufTypeToKotlinFunctionSuffix(descriptor->type());
|
return name_resolving::protobufTypeToKotlinFunctionSuffix(descriptor->type());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldGenerator::generateSizeEstimationCode(io::Printer *printer, string varName, bool noTag) const {
|
void FieldGenerator::generateSizeEstimationCode(io::Printer *printer, string varName, bool noTag, bool isField) const {
|
||||||
map<string, string> vars;
|
map<string, string> vars;
|
||||||
vars["varName"] = varName;
|
vars["varName"] = varName;
|
||||||
vars["fieldName"] = simpleName;
|
vars["fieldName"] = simpleName;
|
||||||
@@ -459,7 +370,7 @@ void FieldGenerator::generateSizeEstimationCode(io::Printer *printer, string var
|
|||||||
FieldGenerator singleFieldGen = FieldGenerator(descriptor, enclosingClass, nameResolver);
|
FieldGenerator singleFieldGen = FieldGenerator(descriptor, enclosingClass, nameResolver);
|
||||||
singleFieldGen.protoLabel = FieldDescriptor::LABEL_OPTIONAL;
|
singleFieldGen.protoLabel = FieldDescriptor::LABEL_OPTIONAL;
|
||||||
singleFieldGen.simpleName = "item";
|
singleFieldGen.simpleName = "item";
|
||||||
singleFieldGen.generateSizeEstimationCode(printer, "arraySize", noTag);
|
singleFieldGen.generateSizeEstimationCode(printer, "arraySize", noTag, /* isField = */ false);
|
||||||
|
|
||||||
printer->Outdent(); // for-loop
|
printer->Outdent(); // for-loop
|
||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
@@ -477,42 +388,38 @@ void FieldGenerator::generateSizeEstimationCode(io::Printer *printer, string var
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we are generating code for fair field (not for dummy), then we should check for default value
|
||||||
|
// Note that we can't lift that check up, because repeated fields should be treated separately
|
||||||
|
if (isField) {
|
||||||
|
printer->Print(vars, "if ($fieldName$ != $initValue$) {\n");
|
||||||
|
printer->Indent();
|
||||||
|
}
|
||||||
|
|
||||||
// Then, call getSize recursively for nested messages
|
// Then, call getSize recursively for nested messages
|
||||||
// TODO: currently suboptimal repeatative calls getSize() are being made. We can optimize it later via caching calls to getSize()
|
// TODO: currently suboptimal repeatative calls getSize() are being made. We can optimize it later via caching calls to getSize()
|
||||||
if (getProtoType() == FieldDescriptor::TYPE_MESSAGE) {
|
if (getProtoType() == FieldDescriptor::TYPE_MESSAGE) {
|
||||||
printer->Print(vars, "if ($fieldName$ != $initValue$) {\n");
|
|
||||||
printer->Indent();
|
|
||||||
vars["maybeNoTag"] = noTag ? "NoTag" : "";
|
vars["maybeNoTag"] = noTag ? "NoTag" : "";
|
||||||
vars["maybeFieldNumber"] = noTag ? "" : std::to_string(getFieldNumber());
|
vars["maybeFieldNumber"] = noTag ? "" : std::to_string(getFieldNumber());
|
||||||
printer->Print(vars, "$varName$ += $fieldName$.getSize$maybeNoTag$($maybeFieldNumber$)"
|
printer->Print(vars, "$varName$ += $fieldName$.getSize$maybeNoTag$($maybeFieldNumber$)"
|
||||||
"\n");
|
"\n");
|
||||||
printer->Outdent(); // if-clause
|
|
||||||
printer->Print("}\n");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Next, process enums as they should be casted to ints manually
|
// Next, process enums as they should be casted to ints manually
|
||||||
if (getProtoType() == FieldDescriptor::TYPE_ENUM) {
|
else if (getProtoType() == FieldDescriptor::TYPE_ENUM) {
|
||||||
printer->Print(vars, "if ($fieldName$ != $initValue$) {\n");
|
|
||||||
printer->Indent();
|
|
||||||
|
|
||||||
printer->Print(vars, "$varName$ += WireFormat.getEnumSize($fieldNumber$, $fieldName$.ord)\n");
|
printer->Print(vars, "$varName$ += WireFormat.getEnumSize($fieldNumber$, $fieldName$.ord)\n");
|
||||||
|
|
||||||
printer->Outdent(); // if-clause
|
|
||||||
printer->Print("}\n");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, get size of all primitive types trivially via call to WireFormat in runtime
|
// Finally, get size of all primitive types trivially via call to WireFormat in runtime
|
||||||
vars["kotlinSuffix"] = getKotlinFunctionSuffix();
|
else {
|
||||||
printer->Print(vars, "if ($fieldName$ != $initValue$) {\n");
|
vars["kotlinSuffix"] = getKotlinFunctionSuffix();
|
||||||
printer->Indent();
|
printer->Print(vars, "$varName$ += WireFormat.get$kotlinSuffix$Size($fieldNumber$, $fieldName$)\n");
|
||||||
|
}
|
||||||
|
|
||||||
printer->Print(vars, "$varName$ += WireFormat.get$kotlinSuffix$Size($fieldNumber$, $fieldName$)\n");
|
if (isField) {
|
||||||
|
printer->Outdent(); // if-clause
|
||||||
printer->Outdent(); // if-clause
|
printer->Print("}\n");
|
||||||
printer->Print("}\n");
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldDescriptor::Label FieldGenerator::getProtoLabel() const {
|
FieldDescriptor::Label FieldGenerator::getProtoLabel() const {
|
||||||
@@ -543,7 +450,7 @@ string FieldGenerator::getSimpleType() const {
|
|||||||
|
|
||||||
string FieldGenerator::getFullType() const {
|
string FieldGenerator::getFullType() const {
|
||||||
if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
|
if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
|
||||||
return "MutableList <" + getUnderlyingTypeGenerator().getFullType() + ">";
|
return getUnderlyingTypeGenerator().getFullType() + "Array";
|
||||||
}
|
}
|
||||||
if (getProtoType() == FieldDescriptor::TYPE_MESSAGE ||
|
if (getProtoType() == FieldDescriptor::TYPE_MESSAGE ||
|
||||||
getProtoType() == FieldDescriptor::TYPE_ENUM) {
|
getProtoType() == FieldDescriptor::TYPE_ENUM) {
|
||||||
|
|||||||
+7
-7
@@ -27,11 +27,11 @@ private:
|
|||||||
void generateSetter(io::Printer * printer) const;
|
void generateSetter(io::Printer * printer) const;
|
||||||
void generateRepeatedMethods(io::Printer * printer, bool isBuilder) const;
|
void generateRepeatedMethods(io::Printer * printer, bool isBuilder) const;
|
||||||
|
|
||||||
void generateSerializationForPacked (io::Printer * printer, bool isRead, bool noTag) const;
|
void generateSerializationForPacked (io::Printer * printer, bool isRead, bool noTag, bool isField) const;
|
||||||
void generateSerializationForRepeated (io::Printer * printer, bool isRead, bool noTag) const;
|
void generateSerializationForRepeated (io::Printer * printer, bool isRead, bool noTag, bool isField) const;
|
||||||
void generateSerializationForEnums (io::Printer * printer, bool isRead, bool noTag) const;
|
void generateSerializationForEnums (io::Printer * printer, bool isRead, bool noTag, bool isField) const;
|
||||||
void generateSerializationForMessages (io::Printer * printer, bool isRead, bool noTag) const;
|
void generateSerializationForMessages (io::Printer * printer, bool isRead, bool noTag, bool isField) const;
|
||||||
void generateSerializationForPrimitives (io::Printer * printer, bool isRead, bool noTag) const;
|
void generateSerializationForPrimitives (io::Printer * printer, bool isRead, bool noTag, bool isField) const;
|
||||||
public:
|
public:
|
||||||
ClassGenerator const * enclosingClass; // class, in which that field is defined
|
ClassGenerator const * enclosingClass; // class, in which that field is defined
|
||||||
NameResolver * nameResolver;
|
NameResolver * nameResolver;
|
||||||
@@ -84,8 +84,8 @@ public:
|
|||||||
|
|
||||||
string getWireType() const;
|
string getWireType() const;
|
||||||
void generateCode(io::Printer * printer, bool isBuilder) const;
|
void generateCode(io::Printer * printer, bool isBuilder) const;
|
||||||
void generateSerializationCode(io::Printer * printer, bool isRead = false, bool noTag = false) const;
|
void generateSerializationCode (io::Printer * printer, bool isRead = false, bool noTag = false, bool isField = true) const;
|
||||||
void generateSizeEstimationCode(io::Printer * printer, string varName, bool noTag = false) const;
|
void generateSizeEstimationCode(io::Printer * printer, string varName, bool noTag = false, bool isField = true) const;
|
||||||
FieldGenerator(FieldDescriptor const * descriptor, ClassGenerator const * enclosingClass, NameResolver * nameResolver);
|
FieldGenerator(FieldDescriptor const * descriptor, ClassGenerator const * enclosingClass, NameResolver * nameResolver);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,8 @@ option java_package = "proto.car";
|
|||||||
option java_outer_classname = "Route";
|
option java_outer_classname = "Route";
|
||||||
|
|
||||||
message RouteRequest {
|
message RouteRequest {
|
||||||
repeated WayPoint way_points = 1;
|
repeated int32 dinstances = 1;
|
||||||
|
repeated int32 angle_deltas = 2;
|
||||||
message WayPoint {
|
|
||||||
int32 distance = 2;
|
|
||||||
int32 angle_delta = 3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message RouteResponse {
|
message RouteResponse {
|
||||||
|
|||||||
Reference in New Issue
Block a user