Protobuf: Fixed stub in length-delimited fields serialization. Now related methods write size of object correctly. Added necessary methods for estimating byte-size of objects in run-time in ProtoKot runtime-library.
This commit is contained in:
@@ -26,4 +26,9 @@ clean:
|
|||||||
|
|
||||||
generate:
|
generate:
|
||||||
./protoc --kotlin_out=./ ./test/addressbook.proto
|
./protoc --kotlin_out=./ ./test/addressbook.proto
|
||||||
.PHONY: clean all generate
|
.PHONY: clean all generate
|
||||||
|
|
||||||
|
low: dummy
|
||||||
|
|
||||||
|
dummy: CXXFLAGS += -DKOTLIN_GENERATED_CODE_LANGUAGE_LEVEL_LOW
|
||||||
|
dummy: all
|
||||||
+30
-27
@@ -48,8 +48,6 @@ void ClassGenerator::generateCode(io::Printer *printer, bool isBuilder) const {
|
|||||||
// write serialization methods only for fair classes, read methods only for Builders)
|
// write serialization methods only for fair classes, read methods only for Builders)
|
||||||
printer->Print("\n");
|
printer->Print("\n");
|
||||||
generateSerializers(printer, /* isRead = */ isBuilder);
|
generateSerializers(printer, /* isRead = */ isBuilder);
|
||||||
printer->Print("\n");
|
|
||||||
generateSerializersNoTag(printer, /* isRead = */ isBuilder);
|
|
||||||
|
|
||||||
// builder, mergeFrom and only for fair classes
|
// builder, mergeFrom and only for fair classes
|
||||||
if (!isBuilder) {
|
if (!isBuilder) {
|
||||||
@@ -69,6 +67,9 @@ void ClassGenerator::generateCode(io::Printer *printer, bool isBuilder) const {
|
|||||||
generateParseMethods(printer);
|
generateParseMethods(printer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getSize()
|
||||||
|
generateGetSizeMethod(printer);
|
||||||
|
|
||||||
printer->Outdent();
|
printer->Outdent();
|
||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
}
|
}
|
||||||
@@ -172,32 +173,10 @@ void ClassGenerator::generateMergeMethods(io::Printer *printer) const {
|
|||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassGenerator::generateSerializers(io::Printer * printer, bool isRead) const {
|
|
||||||
// readFrom(input: CodedInputStream) OR
|
void ClassGenerator::generateSerializers(io::Printer *printer, bool isRead) const {
|
||||||
// writeTo(output: CodedOutputStream)
|
|
||||||
map <string, string> vars;
|
map <string, string> vars;
|
||||||
vars["funName"]= isRead ? "readFrom" : "writeTo";
|
vars["funName"]= isRead ? "readFrom" : "writeTo";
|
||||||
vars["returnType"] = isRead ? builderName : "Unit";
|
|
||||||
vars["stream"] = isRead ? "CodedInputStream" : "CodedOutputStream";
|
|
||||||
vars["arg"] = isRead ? "input" : "output";
|
|
||||||
vars["maybeSeparator"] = isRead ? "" : ", ";
|
|
||||||
vars["maybeReturn"] = isRead ? "return " : "";
|
|
||||||
|
|
||||||
// generate function header
|
|
||||||
printer->Print(vars,
|
|
||||||
"fun $funName$ ($arg$: $stream$): $returnType$ {"
|
|
||||||
"\n");
|
|
||||||
printer->Indent();
|
|
||||||
|
|
||||||
printer->Print(vars, "$maybeReturn$$funName$NoTag($arg$)\n");
|
|
||||||
|
|
||||||
printer->Outdent();
|
|
||||||
printer->Print("}\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassGenerator::generateSerializersNoTag(io::Printer *printer, bool isRead) const {
|
|
||||||
map <string, string> vars;
|
|
||||||
vars["funName"]= isRead ? "readFromNoTag" : "writeToNoTag";
|
|
||||||
vars["stream"] = isRead ? "CodedInputStream" : "CodedOutputStream";
|
vars["stream"] = isRead ? "CodedInputStream" : "CodedOutputStream";
|
||||||
vars["arg"] = isRead ? "input" : "output";
|
vars["arg"] = isRead ? "input" : "output";
|
||||||
vars["returnType"] = isRead ? builderName : "Unit";
|
vars["returnType"] = isRead ? builderName : "Unit";
|
||||||
@@ -341,6 +320,30 @@ void ClassGenerator::generateParseMethods(io::Printer *printer) const {
|
|||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClassGenerator::generateGetSizeMethod(io::Printer *printer) const {
|
||||||
|
printer->Print("fun getSize(): Int {\n");
|
||||||
|
printer->Indent();
|
||||||
|
|
||||||
|
printer->Print("var size = 0\n");
|
||||||
|
for (int i = 0; i < properties.size(); ++i) {
|
||||||
|
properties[i]->generateSizeEstimationCode(printer, "size");
|
||||||
|
}
|
||||||
|
|
||||||
|
printer->Print("return size\n");
|
||||||
|
printer->Outdent();
|
||||||
|
printer->Print("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//int ClassGenerator::getSizeWithoutHeader() {
|
||||||
|
// int size = 0;
|
||||||
|
// for (int i = 0; i < properties.size(); ++i) {
|
||||||
|
// size += properties[i].getSizeWithHeader();
|
||||||
|
// }
|
||||||
|
// return 0;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
const string ClassModifier::getName() const {
|
const string ClassModifier::getName() const {
|
||||||
string result = "";
|
string result = "";
|
||||||
|
|||||||
+1
-1
@@ -62,10 +62,10 @@ private:
|
|||||||
* both methods are structurally the same with some trivial substitutions
|
* both methods are structurally the same with some trivial substitutions
|
||||||
* (read -> write and etc.)
|
* (read -> write and etc.)
|
||||||
*/
|
*/
|
||||||
void generateSerializersNoTag(io::Printer *printer, bool isRead = false) const;
|
|
||||||
void generateSerializers(io::Printer * printer, bool isRead = false) const;
|
void generateSerializers(io::Printer * printer, bool isRead = false) const;
|
||||||
void generateMergeMethods(io::Printer *printer) const;
|
void generateMergeMethods(io::Printer *printer) const;
|
||||||
void generateParseMethods(io::Printer * printer) const;
|
void generateParseMethods(io::Printer * printer) const;
|
||||||
|
void generateGetSizeMethod(io::Printer * printer) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
|
|||||||
+137
-21
@@ -16,12 +16,10 @@ namespace kotlin {
|
|||||||
|
|
||||||
string FieldGenerator::getInitValue() const {
|
string FieldGenerator::getInitValue() const {
|
||||||
if (descriptor->is_repeated())
|
if (descriptor->is_repeated())
|
||||||
#ifndef KOTLIN_GENERATED_CODE_LANGUAGE_LEVEL_LOW
|
|
||||||
return "mutableListOf()";
|
return "mutableListOf()";
|
||||||
#else
|
else if (protoType == FieldDescriptor::TYPE_MESSAGE) {
|
||||||
return "arrayOf()";
|
return enclosingClass->builderName + "().build()";
|
||||||
#endif
|
}
|
||||||
|
|
||||||
return name_resolving::protobufTypeToInitValue(descriptor);
|
return name_resolving::protobufTypeToInitValue(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,8 +80,9 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
|
|||||||
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 listSize = input.readInt32NoTag()\n");
|
printer->Print(vars, "val expectedSize = input.readInt32NoTag()\n");
|
||||||
printer->Print(vars, "for (i in 1..listSize) {\n");
|
printer->Print("var readSize = 0\n");
|
||||||
|
printer->Print(vars, "while(readSize != expectedSize) {\n");
|
||||||
printer->Indent();
|
printer->Indent();
|
||||||
|
|
||||||
/* 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
|
||||||
@@ -99,17 +98,25 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
|
|||||||
|
|
||||||
/* Another dirty hack here: create tmp variable of a given type and read it from input stream
|
/* Another dirty hack here: create tmp variable of a given type and read it from input stream
|
||||||
then add that tmp var into list.
|
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 made because simple recursive call will generate code that tries to array[i].mergeFrom().
|
||||||
but this is incorrect, because array has old size, while 'i' iterates over new size, and of course
|
This is incorrect because array has old size, while 'i' iterates over new size, which can lead
|
||||||
they are not necessary the same.
|
to ArrayOutOfIndex errors.
|
||||||
*/
|
*/
|
||||||
// TODO: stub here, resolve name properly!
|
// TODO: stub here, resolve name properly!
|
||||||
vars["fieldType"] = underlyingType + ".Builder" + underlyingType;
|
vars["fieldType"] = underlyingType + ".Builder" + underlyingType;
|
||||||
vars["initValue"] = getUnderlyingTypeInitValue();
|
vars["initValue"] = underlyingType + ".Builder" + underlyingType + "()";
|
||||||
printer->Print(vars, "val tmp: $fieldType$ = $fieldType$()\n");
|
printer->Print(vars, "val tmp: $fieldType$ = $initValue$\n");
|
||||||
singleFieldGen.simpleName = "tmp";
|
singleFieldGen.simpleName = "tmp";
|
||||||
singleFieldGen.modifier = FieldDescriptor::LABEL_OPTIONAL;
|
singleFieldGen.modifier = FieldDescriptor::LABEL_OPTIONAL;
|
||||||
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ true);
|
|
||||||
|
// Note that primitive types are packed by default in proto3, i.e. they are should be written without tag
|
||||||
|
bool isPrimitive = descriptor->type() != FieldDescriptor::TYPE_BYTES &&
|
||||||
|
descriptor->type() != FieldDescriptor::TYPE_MESSAGE &&
|
||||||
|
descriptor->type() != FieldDescriptor::TYPE_STRING &&
|
||||||
|
descriptor->type() != FieldDescriptor::TYPE_ENUM;
|
||||||
|
|
||||||
|
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ isPrimitive);
|
||||||
|
singleFieldGen.generateSizeEstimationCode(printer, "readSize"); // add size of current element to total size
|
||||||
|
|
||||||
printer->Print(vars, "$fieldName$.add(tmp.build())\n");
|
printer->Print(vars, "$fieldName$.add(tmp.build())\n");
|
||||||
|
|
||||||
@@ -124,7 +131,9 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
|
|||||||
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, "output.writeInt32NoTag($fieldName$.size)\n");
|
printer->Print(vars, "var arrayByteSize = 0\n");
|
||||||
|
generateSizeEstimationCode(printer, "arrayByteSize", /* noTag = */ true);
|
||||||
|
printer->Print(vars, "output.writeInt32NoTag(arrayByteSize)\n");
|
||||||
|
|
||||||
// all elements
|
// all elements
|
||||||
printer->Print(vars, "for (item in $fieldName$) {\n");
|
printer->Print(vars, "for (item in $fieldName$) {\n");
|
||||||
@@ -134,7 +143,15 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
|
|||||||
FieldGenerator singleFieldGen = FieldGenerator(descriptor, enclosingClass);
|
FieldGenerator singleFieldGen = FieldGenerator(descriptor, enclosingClass);
|
||||||
singleFieldGen.simpleName = "item";
|
singleFieldGen.simpleName = "item";
|
||||||
singleFieldGen.modifier = FieldDescriptor::LABEL_OPTIONAL;
|
singleFieldGen.modifier = FieldDescriptor::LABEL_OPTIONAL;
|
||||||
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ true);
|
|
||||||
|
// TODO: maybe refactor this in name_resolving or separate method at least
|
||||||
|
// Note that primitive types are packed by default in proto3, i.e. they are should be written without tag
|
||||||
|
bool isPrimitive = descriptor->type() != FieldDescriptor::TYPE_BYTES &&
|
||||||
|
descriptor->type() != FieldDescriptor::TYPE_MESSAGE &&
|
||||||
|
descriptor->type() != FieldDescriptor::TYPE_STRING &&
|
||||||
|
descriptor->type() != FieldDescriptor::TYPE_ENUM;
|
||||||
|
|
||||||
|
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ isPrimitive);
|
||||||
|
|
||||||
printer->Outdent(); // for-loop
|
printer->Outdent(); // for-loop
|
||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
@@ -166,17 +183,42 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Then check for nested messages. Then we re-use writeTo method, that should be defined in
|
Then check for nested messages. Then we re-use writeTo method, that should be defined in
|
||||||
that message
|
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.
|
||||||
*/
|
*/
|
||||||
if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
|
if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
|
||||||
vars["maybeNoTag"] = "NoTag";
|
|
||||||
if (isRead) {
|
if (isRead) {
|
||||||
|
vars["fieldNumber"] = std::to_string(fieldNumber);
|
||||||
|
vars["dollar"] = "$";
|
||||||
|
|
||||||
|
// read tag
|
||||||
|
printer->Print(vars, "input.readTag($fieldNumber$, WireType.LENGTH_DELIMITED)\n");
|
||||||
|
|
||||||
|
// read expected size
|
||||||
|
printer->Print(vars, "val expectedSize = input.readInt32NoTag()\n");
|
||||||
|
|
||||||
|
// read message itself without tag
|
||||||
printer->Print(vars,
|
printer->Print(vars,
|
||||||
"$fieldName$.readFrom$maybeNoTag$(input)\n");
|
"$fieldName$.readFrom(input)\n");
|
||||||
|
|
||||||
|
// check that actual size equal to expected size
|
||||||
|
printer->Print(vars, "if (expectedSize != $fieldName$.getSize()) { "
|
||||||
|
"throw InvalidProtocolBufferException ("
|
||||||
|
"\"Expected size $dollar${expectedSize} got $dollar${$fieldName$.getSize()}"
|
||||||
|
"\") }\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
vars["fieldNumber"] = std::to_string(fieldNumber);
|
||||||
|
// write tag
|
||||||
|
printer->Print(vars, "output.writeTag($fieldNumber$, WireType.LENGTH_DELIMITED)\n");
|
||||||
|
|
||||||
|
// write message length via runtime-call
|
||||||
|
printer->Print(vars, "output.writeInt32NoTag($fieldName$.getSize())\n");
|
||||||
|
|
||||||
|
// write message itself without tag
|
||||||
printer->Print(vars,
|
printer->Print(vars,
|
||||||
"$fieldName$.writeTo$maybeNoTag$(output)\n");
|
"$fieldName$.writeTo(output)\n");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -224,7 +266,6 @@ void FieldGenerator::generateRepeatedMethods(io::Printer * printer, bool isBuild
|
|||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef KOTLIN_GENERATED_CODE_LANGUAGE_LEVEL_LOW
|
|
||||||
if (isBuilder) {
|
if (isBuilder) {
|
||||||
// generate single-add for builders
|
// generate single-add for builders
|
||||||
printer->Print(vars, "fun add$elementType$($arg$: $elementType$): $builderName$ {\n");
|
printer->Print(vars, "fun add$elementType$($arg$: $elementType$): $builderName$ {\n");
|
||||||
@@ -249,7 +290,6 @@ void FieldGenerator::generateRepeatedMethods(io::Printer * printer, bool isBuild
|
|||||||
printer->Outdent(); // function body
|
printer->Outdent(); // function body
|
||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string FieldGenerator::getKotlinFunctionSuffix() const {
|
string FieldGenerator::getKotlinFunctionSuffix() const {
|
||||||
@@ -257,9 +297,85 @@ string FieldGenerator::getKotlinFunctionSuffix() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string FieldGenerator::getUnderlyingTypeInitValue() const {
|
string FieldGenerator::getUnderlyingTypeInitValue() const {
|
||||||
|
if (protoType == FieldDescriptor::TYPE_MESSAGE) {
|
||||||
|
return "Builder" + underlyingType + "().build()";
|
||||||
|
}
|
||||||
return name_resolving::protobufTypeToInitValue(descriptor);
|
return name_resolving::protobufTypeToInitValue(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FieldGenerator::generateSizeEstimationCode(io::Printer *printer, string varName, bool noTag) const {
|
||||||
|
map<string, string> vars;
|
||||||
|
vars["varName"] = varName;
|
||||||
|
vars["fieldName"] = simpleName;
|
||||||
|
vars["fieldNumber"] = std::to_string(fieldNumber);
|
||||||
|
|
||||||
|
// First of all, generate code for repeated fields
|
||||||
|
if (modifier == FieldDescriptor::LABEL_REPEATED) {
|
||||||
|
// We will need total byte size of array, because that size is itself a part of the message and
|
||||||
|
// adds to total message size.
|
||||||
|
// For the sake of hygiene, temporary variables are created in anonymous scope
|
||||||
|
printer->Print("run {\n");
|
||||||
|
printer->Indent();
|
||||||
|
|
||||||
|
// Create a temporary variable that will collect array byte size
|
||||||
|
printer->Print("var arraySize = 0\n");
|
||||||
|
|
||||||
|
// iterate over all elements of array
|
||||||
|
printer->Print(vars, "for (item in $fieldName$) {\n");
|
||||||
|
printer->Indent();
|
||||||
|
|
||||||
|
// hack: reuse generateSizeEstimationCode in the same manner as in generateSerializationCode
|
||||||
|
FieldGenerator singleFieldGen = FieldGenerator(descriptor, enclosingClass);
|
||||||
|
singleFieldGen.modifier = FieldDescriptor::LABEL_OPTIONAL;
|
||||||
|
singleFieldGen.simpleName = "item";
|
||||||
|
singleFieldGen.generateSizeEstimationCode(printer, "arraySize");
|
||||||
|
|
||||||
|
printer->Outdent(); // for-loop
|
||||||
|
printer->Print("}\n");
|
||||||
|
|
||||||
|
// now add to total message size size of array, consisting of:
|
||||||
|
printer->Print(vars,
|
||||||
|
"$varName$ += arraySize"); // actual array size
|
||||||
|
if (!noTag) {
|
||||||
|
printer->Print(vars,
|
||||||
|
" + "
|
||||||
|
"WireFormat.getTagSize($fieldNumber$, WireType.LENGTH_DELIMITED)" // tag size
|
||||||
|
" + "
|
||||||
|
"WireFormat.getVarint32Size(arraySize)"); // runtime call, that will get size of varint, denoting size of array
|
||||||
|
}
|
||||||
|
printer->Print("\n");
|
||||||
|
printer->Outdent(); // anonymous scope
|
||||||
|
printer->Print("}\n");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
if (protoType == FieldDescriptor::TYPE_MESSAGE) {
|
||||||
|
// don't forget about tag and length annotation
|
||||||
|
printer->Print(vars, "$varName$ += $fieldName$.getSize()"
|
||||||
|
" + "
|
||||||
|
"WireFormat.getTagSize($fieldNumber$, WireType.LENGTH_DELIMITED)"
|
||||||
|
" + "
|
||||||
|
"WireFormat.getVarint32Size($fieldName$.getSize())\n"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, process enums as they should be casted to ints manually
|
||||||
|
if (protoType == FieldDescriptor::TYPE_ENUM) {
|
||||||
|
vars["enumName"] = fullType;
|
||||||
|
printer->Print(vars, "$varName$ += WireFormat.getEnumSize($fieldNumber$, $fieldName$.ord)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, get size of all primitive types trivially via call to WireFormat in runtime
|
||||||
|
vars["kotlinSuffix"] = name_resolving::protobufTypeToKotlinFunctionSuffix(descriptor->type());
|
||||||
|
printer->Print(vars, "$varName$ += WireFormat.get$kotlinSuffix$Size($fieldNumber$, $fieldName$)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
} // namespace compiler
|
} // namespace compiler
|
||||||
} // namespace protobuf
|
} // namespace protobuf
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ public:
|
|||||||
|
|
||||||
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) const;
|
||||||
|
void generateSizeEstimationCode(io::Printer * printer, string varName, bool noTag = false) const;
|
||||||
FieldGenerator(FieldDescriptor const * descriptor, ClassGenerator const * enclosingClass);
|
FieldGenerator(FieldDescriptor const * descriptor, ClassGenerator const * enclosingClass);
|
||||||
string getKotlinFunctionSuffix() const;
|
string getKotlinFunctionSuffix() const;
|
||||||
|
|
||||||
|
|||||||
+1
-6
@@ -83,19 +83,14 @@ string protobufToKotlinField(FieldDescriptor const * descriptor) {
|
|||||||
case FieldDescriptor::LABEL_OPTIONAL:
|
case FieldDescriptor::LABEL_OPTIONAL:
|
||||||
break;
|
break;
|
||||||
case FieldDescriptor::LABEL_REPEATED:
|
case FieldDescriptor::LABEL_REPEATED:
|
||||||
#ifndef KOTLIN_GENERATED_CODE_LANGUAGE_LEVEL_LOW
|
|
||||||
preamble = "MutableList <";
|
preamble = "MutableList <";
|
||||||
postamble = "> ";
|
postamble = "> ";
|
||||||
break;
|
break;
|
||||||
#else
|
|
||||||
preamble = "Array <";
|
|
||||||
postamble = "> ";
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return preamble + protobufToKotlinType(descriptor) + postamble;
|
return preamble + protobufToKotlinType(descriptor) + postamble;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: think about nested arrays
|
||||||
string protobufTypeToInitValue(FieldDescriptor const * descriptor) {
|
string protobufTypeToInitValue(FieldDescriptor const * descriptor) {
|
||||||
FieldDescriptor::Type type = descriptor->type();
|
FieldDescriptor::Type type = descriptor->type();
|
||||||
switch(type) {
|
switch(type) {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include "kotlin_file_generator.h"
|
#include "kotlin_file_generator.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
//#define KOTLIN_GENERATED_CODE_LANGUAGE_LEVEL_LOW
|
|
||||||
int main(int argc, const char* const * argv) {
|
int main(int argc, const char* const * argv) {
|
||||||
google::protobuf::compiler::CommandLineInterface cli;
|
google::protobuf::compiler::CommandLineInterface cli;
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,6 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun writeTo (output: CodedOutputStream): Unit {
|
fun writeTo (output: CodedOutputStream): Unit {
|
||||||
writeToNoTag(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun writeToNoTag (output: CodedOutputStream): Unit {
|
|
||||||
output.writeString (1, number)
|
output.writeString (1, number)
|
||||||
output.writeEnum (2, type.ord)
|
output.writeEnum (2, type.ord)
|
||||||
}
|
}
|
||||||
@@ -82,10 +78,6 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom (input: CodedInputStream): BuilderPhoneNumber {
|
fun readFrom (input: CodedInputStream): BuilderPhoneNumber {
|
||||||
return readFromNoTag(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun readFromNoTag (input: CodedInputStream): BuilderPhoneNumber {
|
|
||||||
number = input.readString(1)
|
number = input.readString(1)
|
||||||
type = PhoneType.fromIntToPhoneType(input.readEnum(2))
|
type = PhoneType.fromIntToPhoneType(input.readEnum(2))
|
||||||
return this
|
return this
|
||||||
@@ -110,6 +102,12 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
|
|||||||
while(parseFieldFrom(input)) {}
|
while(parseFieldFrom(input)) {}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
fun getSize(): Int {
|
||||||
|
var size = 0
|
||||||
|
size += WireFormat.getStringSize(1, number)
|
||||||
|
size += WireFormat.getEnumSize(2, type.ord)
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -121,22 +119,34 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
|
|||||||
fun mergeFrom (input: CodedInputStream) {
|
fun mergeFrom (input: CodedInputStream) {
|
||||||
val builder = BuilderPhoneNumber()
|
val builder = BuilderPhoneNumber()
|
||||||
mergeWith(builder.parseFrom(input).build())}
|
mergeWith(builder.parseFrom(input).build())}
|
||||||
|
fun getSize(): Int {
|
||||||
|
var size = 0
|
||||||
|
size += WireFormat.getStringSize(1, number)
|
||||||
|
size += WireFormat.getEnumSize(2, type.ord)
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun writeTo (output: CodedOutputStream): Unit {
|
fun writeTo (output: CodedOutputStream): Unit {
|
||||||
writeToNoTag(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun writeToNoTag (output: CodedOutputStream): Unit {
|
|
||||||
output.writeString (1, name)
|
output.writeString (1, name)
|
||||||
output.writeInt32 (2, id)
|
output.writeInt32 (2, id)
|
||||||
output.writeString (3, email)
|
output.writeString (3, email)
|
||||||
if (phones.size > 0) {
|
if (phones.size > 0) {
|
||||||
output.writeTag(4, WireType.LENGTH_DELIMITED)
|
output.writeTag(4, WireType.LENGTH_DELIMITED)
|
||||||
output.writeInt32NoTag(phones.size)
|
var arrayByteSize = 0
|
||||||
|
run {
|
||||||
|
var arraySize = 0
|
||||||
|
for (item in phones) {
|
||||||
|
arraySize += item.getSize() + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(item.getSize())
|
||||||
|
}
|
||||||
|
arrayByteSize += arraySize
|
||||||
|
}
|
||||||
|
output.writeInt32NoTag(arrayByteSize)
|
||||||
for (item in phones) {
|
for (item in phones) {
|
||||||
item.writeToNoTag(output)
|
output.writeTag(4, WireType.LENGTH_DELIMITED)
|
||||||
|
output.writeInt32NoTag(item.getSize())
|
||||||
|
item.writeTo(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
output.writeBytes (5, someBytes)
|
output.writeBytes (5, someBytes)
|
||||||
@@ -202,18 +212,19 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom (input: CodedInputStream): BuilderPerson {
|
fun readFrom (input: CodedInputStream): BuilderPerson {
|
||||||
return readFromNoTag(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun readFromNoTag (input: CodedInputStream): BuilderPerson {
|
|
||||||
name = input.readString(1)
|
name = input.readString(1)
|
||||||
id = input.readInt32(2)
|
id = input.readInt32(2)
|
||||||
email = input.readString(3)
|
email = input.readString(3)
|
||||||
val tag = input.readTag(4, WireType.LENGTH_DELIMITED)
|
val tag = input.readTag(4, WireType.LENGTH_DELIMITED)
|
||||||
val listSize = input.readInt32NoTag()
|
val expectedSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
var readSize = 0
|
||||||
|
while(readSize != expectedSize) {
|
||||||
val tmp: PhoneNumber.BuilderPhoneNumber = PhoneNumber.BuilderPhoneNumber()
|
val tmp: PhoneNumber.BuilderPhoneNumber = PhoneNumber.BuilderPhoneNumber()
|
||||||
tmp.readFromNoTag(input)
|
input.readTag(4, WireType.LENGTH_DELIMITED)
|
||||||
|
val expectedSize = input.readInt32NoTag()
|
||||||
|
tmp.readFrom(input)
|
||||||
|
if (expectedSize != tmp.getSize()) { throw InvalidProtocolBufferException ("Expected size ${expectedSize} got ${tmp.getSize()}") }
|
||||||
|
readSize += tmp.getSize() + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(tmp.getSize())
|
||||||
phones.add(tmp.build())
|
phones.add(tmp.build())
|
||||||
}
|
}
|
||||||
someBytes = input.readBytes(5)
|
someBytes = input.readBytes(5)
|
||||||
@@ -235,10 +246,15 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
|
|||||||
2 -> id = input.readInt32NoTag()
|
2 -> id = input.readInt32NoTag()
|
||||||
3 -> email = input.readStringNoTag()
|
3 -> email = input.readStringNoTag()
|
||||||
4 -> {
|
4 -> {
|
||||||
val listSize = input.readInt32NoTag()
|
val expectedSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
var readSize = 0
|
||||||
|
while(readSize != expectedSize) {
|
||||||
val tmp: PhoneNumber.BuilderPhoneNumber = PhoneNumber.BuilderPhoneNumber()
|
val tmp: PhoneNumber.BuilderPhoneNumber = PhoneNumber.BuilderPhoneNumber()
|
||||||
tmp.readFromNoTag(input)
|
input.readTag(4, WireType.LENGTH_DELIMITED)
|
||||||
|
val expectedSize = input.readInt32NoTag()
|
||||||
|
tmp.readFrom(input)
|
||||||
|
if (expectedSize != tmp.getSize()) { throw InvalidProtocolBufferException ("Expected size ${expectedSize} got ${tmp.getSize()}") }
|
||||||
|
readSize += tmp.getSize() + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(tmp.getSize())
|
||||||
phones.add(tmp.build())
|
phones.add(tmp.build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,6 +265,21 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
|
|||||||
while(parseFieldFrom(input)) {}
|
while(parseFieldFrom(input)) {}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
fun getSize(): Int {
|
||||||
|
var size = 0
|
||||||
|
size += WireFormat.getStringSize(1, name)
|
||||||
|
size += WireFormat.getInt32Size(2, id)
|
||||||
|
size += WireFormat.getStringSize(3, email)
|
||||||
|
run {
|
||||||
|
var arraySize = 0
|
||||||
|
for (item in phones) {
|
||||||
|
arraySize += item.getSize() + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(item.getSize())
|
||||||
|
}
|
||||||
|
size += arraySize + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(arraySize)
|
||||||
|
}
|
||||||
|
size += WireFormat.getBytesSize(5, someBytes)
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -263,6 +294,21 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
|
|||||||
fun mergeFrom (input: CodedInputStream) {
|
fun mergeFrom (input: CodedInputStream) {
|
||||||
val builder = BuilderPerson()
|
val builder = BuilderPerson()
|
||||||
mergeWith(builder.parseFrom(input).build())}
|
mergeWith(builder.parseFrom(input).build())}
|
||||||
|
fun getSize(): Int {
|
||||||
|
var size = 0
|
||||||
|
size += WireFormat.getStringSize(1, name)
|
||||||
|
size += WireFormat.getInt32Size(2, id)
|
||||||
|
size += WireFormat.getStringSize(3, email)
|
||||||
|
run {
|
||||||
|
var arraySize = 0
|
||||||
|
for (item in phones) {
|
||||||
|
arraySize += item.getSize() + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(item.getSize())
|
||||||
|
}
|
||||||
|
size += arraySize + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(arraySize)
|
||||||
|
}
|
||||||
|
size += WireFormat.getBytesSize(5, someBytes)
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -276,15 +322,21 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun writeTo (output: CodedOutputStream): Unit {
|
fun writeTo (output: CodedOutputStream): Unit {
|
||||||
writeToNoTag(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun writeToNoTag (output: CodedOutputStream): Unit {
|
|
||||||
if (people.size > 0) {
|
if (people.size > 0) {
|
||||||
output.writeTag(1, WireType.LENGTH_DELIMITED)
|
output.writeTag(1, WireType.LENGTH_DELIMITED)
|
||||||
output.writeInt32NoTag(people.size)
|
var arrayByteSize = 0
|
||||||
|
run {
|
||||||
|
var arraySize = 0
|
||||||
|
for (item in people) {
|
||||||
|
arraySize += item.getSize() + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(item.getSize())
|
||||||
|
}
|
||||||
|
arrayByteSize += arraySize
|
||||||
|
}
|
||||||
|
output.writeInt32NoTag(arrayByteSize)
|
||||||
for (item in people) {
|
for (item in people) {
|
||||||
item.writeToNoTag(output)
|
output.writeTag(1, WireType.LENGTH_DELIMITED)
|
||||||
|
output.writeInt32NoTag(item.getSize())
|
||||||
|
item.writeTo(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -317,15 +369,16 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom (input: CodedInputStream): BuilderAddressBook {
|
fun readFrom (input: CodedInputStream): BuilderAddressBook {
|
||||||
return readFromNoTag(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun readFromNoTag (input: CodedInputStream): BuilderAddressBook {
|
|
||||||
val tag = input.readTag(1, WireType.LENGTH_DELIMITED)
|
val tag = input.readTag(1, WireType.LENGTH_DELIMITED)
|
||||||
val listSize = input.readInt32NoTag()
|
val expectedSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
var readSize = 0
|
||||||
|
while(readSize != expectedSize) {
|
||||||
val tmp: Person.BuilderPerson = Person.BuilderPerson()
|
val tmp: Person.BuilderPerson = Person.BuilderPerson()
|
||||||
tmp.readFromNoTag(input)
|
input.readTag(1, WireType.LENGTH_DELIMITED)
|
||||||
|
val expectedSize = input.readInt32NoTag()
|
||||||
|
tmp.readFrom(input)
|
||||||
|
if (expectedSize != tmp.getSize()) { throw InvalidProtocolBufferException ("Expected size ${expectedSize} got ${tmp.getSize()}") }
|
||||||
|
readSize += tmp.getSize() + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(tmp.getSize())
|
||||||
people.add(tmp.build())
|
people.add(tmp.build())
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
@@ -343,10 +396,15 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
|
|||||||
val wireType = WireFormat.getTagWireType(tag)
|
val wireType = WireFormat.getTagWireType(tag)
|
||||||
when(fieldNumber) {
|
when(fieldNumber) {
|
||||||
1 -> {
|
1 -> {
|
||||||
val listSize = input.readInt32NoTag()
|
val expectedSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
var readSize = 0
|
||||||
|
while(readSize != expectedSize) {
|
||||||
val tmp: Person.BuilderPerson = Person.BuilderPerson()
|
val tmp: Person.BuilderPerson = Person.BuilderPerson()
|
||||||
tmp.readFromNoTag(input)
|
input.readTag(1, WireType.LENGTH_DELIMITED)
|
||||||
|
val expectedSize = input.readInt32NoTag()
|
||||||
|
tmp.readFrom(input)
|
||||||
|
if (expectedSize != tmp.getSize()) { throw InvalidProtocolBufferException ("Expected size ${expectedSize} got ${tmp.getSize()}") }
|
||||||
|
readSize += tmp.getSize() + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(tmp.getSize())
|
||||||
people.add(tmp.build())
|
people.add(tmp.build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,6 +414,17 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
|
|||||||
while(parseFieldFrom(input)) {}
|
while(parseFieldFrom(input)) {}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
fun getSize(): Int {
|
||||||
|
var size = 0
|
||||||
|
run {
|
||||||
|
var arraySize = 0
|
||||||
|
for (item in people) {
|
||||||
|
arraySize += item.getSize() + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(item.getSize())
|
||||||
|
}
|
||||||
|
size += arraySize + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(arraySize)
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -366,6 +435,17 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
|
|||||||
fun mergeFrom (input: CodedInputStream) {
|
fun mergeFrom (input: CodedInputStream) {
|
||||||
val builder = BuilderAddressBook()
|
val builder = BuilderAddressBook()
|
||||||
mergeWith(builder.parseFrom(input).build())}
|
mergeWith(builder.parseFrom(input).build())}
|
||||||
|
fun getSize(): Int {
|
||||||
|
var size = 0
|
||||||
|
run {
|
||||||
|
var arraySize = 0
|
||||||
|
for (item in people) {
|
||||||
|
arraySize += item.getSize() + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(item.getSize())
|
||||||
|
}
|
||||||
|
size += arraySize + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(arraySize)
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.nio.ByteOrder
|
import java.nio.ByteOrder
|
||||||
|
import WireFormat.VARINT_INFO_BITS_COUNT
|
||||||
|
import WireFormat.VARINT_INFO_BITS_MASK
|
||||||
|
import WireFormat.VARINT_UTIL_BIT_MASK
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Dmitry Savvinov on 7/6/16.
|
* Created by Dmitry Savvinov on 7/6/16.
|
||||||
@@ -13,7 +16,6 @@ import java.nio.ByteOrder
|
|||||||
|
|
||||||
// TODO: refactor correctness checks into readTag
|
// TODO: refactor correctness checks into readTag
|
||||||
class CodedInputStream(input: java.io.InputStream) {
|
class CodedInputStream(input: java.io.InputStream) {
|
||||||
|
|
||||||
val bufferedInput: java.io.BufferedInputStream
|
val bufferedInput: java.io.BufferedInputStream
|
||||||
init {
|
init {
|
||||||
bufferedInput = java.io.BufferedInputStream(input) // TODO: Java's realization uses hand-written buffers. Why?
|
bufferedInput = java.io.BufferedInputStream(input) // TODO: Java's realization uses hand-written buffers. Why?
|
||||||
@@ -299,11 +301,5 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
bufferedInput.reset()
|
bufferedInput.reset()
|
||||||
return byte == -1
|
return byte == -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// couple of constants for magic numbers
|
|
||||||
val VARINT_INFO_BITS_COUNT: Int = 7
|
|
||||||
val VARINT_INFO_BITS_MASK: Int = 0b01111111 // mask for separating lowest 7 bits, where actual information stored
|
|
||||||
val VARINT_UTIL_BIT_MASK: Int = 0b10000000 // mask for separating highest bit, that indicates next byte presence
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.nio.ByteOrder
|
import java.nio.ByteOrder
|
||||||
|
import WireFormat.VARINT_INFO_BITS_COUNT
|
||||||
|
import WireFormat.VARINT_INFO_BITS_MASK
|
||||||
|
import WireFormat.VARINT_UTIL_BIT_MASK
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by user on 7/6/16.
|
* Created by user on 7/6/16.
|
||||||
@@ -75,7 +78,7 @@ class CodedOutputStream(val output: java.io.OutputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun writeSInt64NoTag(value: Long) {
|
fun writeSInt64NoTag(value: Long) {
|
||||||
writeInt64NoTag((value shl 1) xor (value shr 31))
|
writeInt64NoTag((value shl 1) xor (value shr 63))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeFixed32(fieldNumber: Int, value: Int?) {
|
fun writeFixed32(fieldNumber: Int, value: Int?) {
|
||||||
@@ -148,7 +151,7 @@ class CodedOutputStream(val output: java.io.OutputStream) {
|
|||||||
|
|
||||||
fun writeStringNoTag(value: String) {
|
fun writeStringNoTag(value: String) {
|
||||||
writeInt32NoTag(value.length)
|
writeInt32NoTag(value.length)
|
||||||
output.write(value.toByteArray())
|
output.write(value.toByteArray(Charsets.UTF_8))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeBytes(fieldNumber: Int, value: ByteArray?) {
|
fun writeBytes(fieldNumber: Int, value: ByteArray?) {
|
||||||
@@ -209,7 +212,7 @@ class CodedOutputStream(val output: java.io.OutputStream) {
|
|||||||
var resSize = 0
|
var resSize = 0
|
||||||
do {
|
do {
|
||||||
// encode current 7 bits
|
// encode current 7 bits
|
||||||
var curByte = (curValue and VARINT_INFO_BITS_MASK)
|
var curByte = (curValue and WireFormat.VARINT_INFO_BITS_MASK)
|
||||||
|
|
||||||
// discard encoded bits. Note that unsigned shift is needed for cases with negative numbers
|
// discard encoded bits. Note that unsigned shift is needed for cases with negative numbers
|
||||||
curValue = curValue ushr VARINT_INFO_BITS_COUNT
|
curValue = curValue ushr VARINT_INFO_BITS_COUNT
|
||||||
@@ -251,8 +254,5 @@ class CodedOutputStream(val output: java.io.OutputStream) {
|
|||||||
output.write(res, 0, resSize)
|
output.write(res, 0, resSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// couple of constants for magic numbers
|
|
||||||
val VARINT_INFO_BITS_COUNT: Int = 7
|
|
||||||
val VARINT_INFO_BITS_MASK: Int = 0b01111111 // mask for separating lowest 7 bits, where actual information stored
|
|
||||||
val VARINT_UTIL_BIT_MASK: Int = 0b10000000 // mask for separating highest bit, that indicates next byte presence
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
class Person private constructor (name: kotlin.String? = "", id: Int? = 0, email: kotlin.String? = "", phones: MutableList <PhoneNumber> = mutableListOf(), someBytes: ByteArray? = ByteArray(0)) {
|
class Person private constructor (name: kotlin.String = "", id: Int = 0, email: kotlin.String = "", phones: MutableList <PhoneNumber> = mutableListOf(), someBytes: ByteArray = ByteArray(0)) {
|
||||||
var name : kotlin.String?
|
var name : kotlin.String
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var id : Int?
|
var id : Int
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var email : kotlin.String?
|
var email : kotlin.String
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var phones : MutableList <PhoneNumber>
|
var phones : MutableList <PhoneNumber>
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var someBytes : ByteArray?
|
var someBytes : ByteArray
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|
||||||
@@ -38,11 +38,11 @@ class Person private constructor (name: kotlin.String? = "", id: Int? = 0, email
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class PhoneNumber private constructor (number: kotlin.String? = "", type: PhoneType? = PhoneType.fromIntToPhoneType(0)) {
|
class PhoneNumber private constructor (number: kotlin.String = "", type: PhoneType = PhoneType.fromIntToPhoneType(0)) {
|
||||||
var number : kotlin.String?
|
var number : kotlin.String
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var type : PhoneType?
|
var type : PhoneType
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|
||||||
@@ -52,25 +52,21 @@ class Person private constructor (name: kotlin.String? = "", id: Int? = 0, email
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun writeTo (output: CodedOutputStream): Unit {
|
fun writeTo (output: CodedOutputStream): Unit {
|
||||||
writeToNoTag(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun writeToNoTag (output: CodedOutputStream): Unit {
|
|
||||||
output.writeString (1, number)
|
output.writeString (1, number)
|
||||||
output.writeEnum (2, type?.ord)
|
output.writeEnum (2, type.ord)
|
||||||
}
|
}
|
||||||
|
|
||||||
class BuilderPhoneNumber constructor (number: kotlin.String? = "", type: PhoneType? = PhoneType.fromIntToPhoneType(0)) {
|
class BuilderPhoneNumber constructor (number: kotlin.String = "", type: PhoneType = PhoneType.fromIntToPhoneType(0)) {
|
||||||
var number : kotlin.String?
|
var number : kotlin.String
|
||||||
private set
|
private set
|
||||||
fun setNumber(value: kotlin.String?): BuilderPhoneNumber {
|
fun setNumber(value: kotlin.String): BuilderPhoneNumber {
|
||||||
number = value
|
number = value
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
var type : PhoneType?
|
var type : PhoneType
|
||||||
private set
|
private set
|
||||||
fun setType(value: PhoneType?): BuilderPhoneNumber {
|
fun setType(value: PhoneType): BuilderPhoneNumber {
|
||||||
type = value
|
type = value
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
@@ -82,10 +78,6 @@ class Person private constructor (name: kotlin.String? = "", id: Int? = 0, email
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom (input: CodedInputStream): BuilderPhoneNumber {
|
fun readFrom (input: CodedInputStream): BuilderPhoneNumber {
|
||||||
return readFromNoTag(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun readFromNoTag (input: CodedInputStream): BuilderPhoneNumber {
|
|
||||||
number = input.readString(1)
|
number = input.readString(1)
|
||||||
type = PhoneType.fromIntToPhoneType(input.readEnum(2))
|
type = PhoneType.fromIntToPhoneType(input.readEnum(2))
|
||||||
return this
|
return this
|
||||||
@@ -110,6 +102,12 @@ class Person private constructor (name: kotlin.String? = "", id: Int? = 0, email
|
|||||||
while(parseFieldFrom(input)) {}
|
while(parseFieldFrom(input)) {}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
fun getSize(): Int {
|
||||||
|
var size = 0
|
||||||
|
size += WireFormat.getStringSize(1, number)
|
||||||
|
size += WireFormat.getEnumSize(2, type.ord)
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -121,45 +119,57 @@ class Person private constructor (name: kotlin.String? = "", id: Int? = 0, email
|
|||||||
fun mergeFrom (input: CodedInputStream) {
|
fun mergeFrom (input: CodedInputStream) {
|
||||||
val builder = BuilderPhoneNumber()
|
val builder = BuilderPhoneNumber()
|
||||||
mergeWith(builder.parseFrom(input).build())}
|
mergeWith(builder.parseFrom(input).build())}
|
||||||
|
fun getSize(): Int {
|
||||||
|
var size = 0
|
||||||
|
size += WireFormat.getStringSize(1, number)
|
||||||
|
size += WireFormat.getEnumSize(2, type.ord)
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun writeTo (output: CodedOutputStream): Unit {
|
fun writeTo (output: CodedOutputStream): Unit {
|
||||||
writeToNoTag(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun writeToNoTag (output: CodedOutputStream): Unit {
|
|
||||||
output.writeString (1, name)
|
output.writeString (1, name)
|
||||||
output.writeInt32 (2, id)
|
output.writeInt32 (2, id)
|
||||||
output.writeString (3, email)
|
output.writeString (3, email)
|
||||||
if (phones.size > 0) {
|
if (phones.size > 0) {
|
||||||
output.writeTag(4, WireType.LENGTH_DELIMITED)
|
output.writeTag(4, WireType.LENGTH_DELIMITED)
|
||||||
output.writeInt32NoTag(phones.size)
|
var arrayByteSize = 0
|
||||||
|
run {
|
||||||
|
var arraySize = 0
|
||||||
|
for (item in phones) {
|
||||||
|
arraySize += item.getSize() + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(item.getSize())
|
||||||
|
}
|
||||||
|
arrayByteSize += arraySize
|
||||||
|
}
|
||||||
|
output.writeInt32NoTag(arrayByteSize)
|
||||||
for (item in phones) {
|
for (item in phones) {
|
||||||
item.writeToNoTag(output)
|
output.writeTag(4, WireType.LENGTH_DELIMITED)
|
||||||
|
output.writeInt32NoTag(item.getSize())
|
||||||
|
item.writeTo(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
output.writeBytes (5, someBytes)
|
output.writeBytes (5, someBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
class BuilderPerson constructor (name: kotlin.String? = "", id: Int? = 0, email: kotlin.String? = "", phones: MutableList <PhoneNumber> = mutableListOf(), someBytes: ByteArray? = ByteArray(0)) {
|
class BuilderPerson constructor (name: kotlin.String = "", id: Int = 0, email: kotlin.String = "", phones: MutableList <PhoneNumber> = mutableListOf(), someBytes: ByteArray = ByteArray(0)) {
|
||||||
var name : kotlin.String?
|
var name : kotlin.String
|
||||||
private set
|
private set
|
||||||
fun setName(value: kotlin.String?): BuilderPerson {
|
fun setName(value: kotlin.String): BuilderPerson {
|
||||||
name = value
|
name = value
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
var id : Int?
|
var id : Int
|
||||||
private set
|
private set
|
||||||
fun setId(value: Int?): BuilderPerson {
|
fun setId(value: Int): BuilderPerson {
|
||||||
id = value
|
id = value
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
var email : kotlin.String?
|
var email : kotlin.String
|
||||||
private set
|
private set
|
||||||
fun setEmail(value: kotlin.String?): BuilderPerson {
|
fun setEmail(value: kotlin.String): BuilderPerson {
|
||||||
email = value
|
email = value
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
@@ -185,9 +195,9 @@ class Person private constructor (name: kotlin.String? = "", id: Int? = 0, email
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
var someBytes : ByteArray?
|
var someBytes : ByteArray
|
||||||
private set
|
private set
|
||||||
fun setSomeBytes(value: ByteArray?): BuilderPerson {
|
fun setSomeBytes(value: ByteArray): BuilderPerson {
|
||||||
someBytes = value
|
someBytes = value
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
@@ -202,18 +212,19 @@ class Person private constructor (name: kotlin.String? = "", id: Int? = 0, email
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom (input: CodedInputStream): BuilderPerson {
|
fun readFrom (input: CodedInputStream): BuilderPerson {
|
||||||
return readFromNoTag(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun readFromNoTag (input: CodedInputStream): BuilderPerson {
|
|
||||||
name = input.readString(1)
|
name = input.readString(1)
|
||||||
id = input.readInt32(2)
|
id = input.readInt32(2)
|
||||||
email = input.readString(3)
|
email = input.readString(3)
|
||||||
val tag = input.readTag(4, WireType.LENGTH_DELIMITED)
|
val tag = input.readTag(4, WireType.LENGTH_DELIMITED)
|
||||||
val listSize = input.readInt32NoTag()
|
val expectedSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
var readSize = 0
|
||||||
|
while(readSize != expectedSize) {
|
||||||
val tmp: PhoneNumber.BuilderPhoneNumber = PhoneNumber.BuilderPhoneNumber()
|
val tmp: PhoneNumber.BuilderPhoneNumber = PhoneNumber.BuilderPhoneNumber()
|
||||||
tmp.readFromNoTag(input)
|
input.readTag(4, WireType.LENGTH_DELIMITED)
|
||||||
|
val expectedSize = input.readInt32NoTag()
|
||||||
|
tmp.readFrom(input)
|
||||||
|
if (expectedSize != tmp.getSize()) { throw InvalidProtocolBufferException ("Expected size ${expectedSize} got ${tmp.getSize()}") }
|
||||||
|
readSize += tmp.getSize() + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(tmp.getSize())
|
||||||
phones.add(tmp.build())
|
phones.add(tmp.build())
|
||||||
}
|
}
|
||||||
someBytes = input.readBytes(5)
|
someBytes = input.readBytes(5)
|
||||||
@@ -235,10 +246,15 @@ class Person private constructor (name: kotlin.String? = "", id: Int? = 0, email
|
|||||||
2 -> id = input.readInt32NoTag()
|
2 -> id = input.readInt32NoTag()
|
||||||
3 -> email = input.readStringNoTag()
|
3 -> email = input.readStringNoTag()
|
||||||
4 -> {
|
4 -> {
|
||||||
val listSize = input.readInt32NoTag()
|
val expectedSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
var readSize = 0
|
||||||
|
while(readSize != expectedSize) {
|
||||||
val tmp: PhoneNumber.BuilderPhoneNumber = PhoneNumber.BuilderPhoneNumber()
|
val tmp: PhoneNumber.BuilderPhoneNumber = PhoneNumber.BuilderPhoneNumber()
|
||||||
tmp.readFromNoTag(input)
|
input.readTag(4, WireType.LENGTH_DELIMITED)
|
||||||
|
val expectedSize = input.readInt32NoTag()
|
||||||
|
tmp.readFrom(input)
|
||||||
|
if (expectedSize != tmp.getSize()) { throw InvalidProtocolBufferException ("Expected size ${expectedSize} got ${tmp.getSize()}") }
|
||||||
|
readSize += tmp.getSize() + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(tmp.getSize())
|
||||||
phones.add(tmp.build())
|
phones.add(tmp.build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,6 +265,21 @@ class Person private constructor (name: kotlin.String? = "", id: Int? = 0, email
|
|||||||
while(parseFieldFrom(input)) {}
|
while(parseFieldFrom(input)) {}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
fun getSize(): Int {
|
||||||
|
var size = 0
|
||||||
|
size += WireFormat.getStringSize(1, name)
|
||||||
|
size += WireFormat.getInt32Size(2, id)
|
||||||
|
size += WireFormat.getStringSize(3, email)
|
||||||
|
run {
|
||||||
|
var arraySize = 0
|
||||||
|
for (item in phones) {
|
||||||
|
arraySize += item.getSize() + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(item.getSize())
|
||||||
|
}
|
||||||
|
size += arraySize + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(arraySize)
|
||||||
|
}
|
||||||
|
size += WireFormat.getBytesSize(5, someBytes)
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -257,12 +288,27 @@ class Person private constructor (name: kotlin.String? = "", id: Int? = 0, email
|
|||||||
id = other.id
|
id = other.id
|
||||||
email = other.email
|
email = other.email
|
||||||
phones.addAll(other.phones)
|
phones.addAll(other.phones)
|
||||||
someBytes?.plus(other.someBytes ?: ByteArray(0))
|
someBytes.plus(other.someBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mergeFrom (input: CodedInputStream) {
|
fun mergeFrom (input: CodedInputStream) {
|
||||||
val builder = BuilderPerson()
|
val builder = BuilderPerson()
|
||||||
mergeWith(builder.parseFrom(input).build())}
|
mergeWith(builder.parseFrom(input).build())}
|
||||||
|
fun getSize(): Int {
|
||||||
|
var size = 0
|
||||||
|
size += WireFormat.getStringSize(1, name)
|
||||||
|
size += WireFormat.getInt32Size(2, id)
|
||||||
|
size += WireFormat.getStringSize(3, email)
|
||||||
|
run {
|
||||||
|
var arraySize = 0
|
||||||
|
for (item in phones) {
|
||||||
|
arraySize += item.getSize() + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(item.getSize())
|
||||||
|
}
|
||||||
|
size += arraySize + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(arraySize)
|
||||||
|
}
|
||||||
|
size += WireFormat.getBytesSize(5, someBytes)
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -276,15 +322,21 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun writeTo (output: CodedOutputStream): Unit {
|
fun writeTo (output: CodedOutputStream): Unit {
|
||||||
writeToNoTag(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun writeToNoTag (output: CodedOutputStream): Unit {
|
|
||||||
if (people.size > 0) {
|
if (people.size > 0) {
|
||||||
output.writeTag(1, WireType.LENGTH_DELIMITED)
|
output.writeTag(1, WireType.LENGTH_DELIMITED)
|
||||||
output.writeInt32NoTag(people.size)
|
var arrayByteSize = 0
|
||||||
|
run {
|
||||||
|
var arraySize = 0
|
||||||
|
for (item in people) {
|
||||||
|
arraySize += item.getSize() + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(item.getSize())
|
||||||
|
}
|
||||||
|
arrayByteSize += arraySize
|
||||||
|
}
|
||||||
|
output.writeInt32NoTag(arrayByteSize)
|
||||||
for (item in people) {
|
for (item in people) {
|
||||||
item.writeToNoTag(output)
|
output.writeTag(1, WireType.LENGTH_DELIMITED)
|
||||||
|
output.writeInt32NoTag(item.getSize())
|
||||||
|
item.writeTo(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -317,15 +369,16 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom (input: CodedInputStream): BuilderAddressBook {
|
fun readFrom (input: CodedInputStream): BuilderAddressBook {
|
||||||
return readFromNoTag(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun readFromNoTag (input: CodedInputStream): BuilderAddressBook {
|
|
||||||
val tag = input.readTag(1, WireType.LENGTH_DELIMITED)
|
val tag = input.readTag(1, WireType.LENGTH_DELIMITED)
|
||||||
val listSize = input.readInt32NoTag()
|
val expectedSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
var readSize = 0
|
||||||
|
while(readSize != expectedSize) {
|
||||||
val tmp: Person.BuilderPerson = Person.BuilderPerson()
|
val tmp: Person.BuilderPerson = Person.BuilderPerson()
|
||||||
tmp.readFromNoTag(input)
|
input.readTag(1, WireType.LENGTH_DELIMITED)
|
||||||
|
val expectedSize = input.readInt32NoTag()
|
||||||
|
tmp.readFrom(input)
|
||||||
|
if (expectedSize != tmp.getSize()) { throw InvalidProtocolBufferException ("Expected size ${expectedSize} got ${tmp.getSize()}") }
|
||||||
|
readSize += tmp.getSize() + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(tmp.getSize())
|
||||||
people.add(tmp.build())
|
people.add(tmp.build())
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
@@ -343,10 +396,15 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
|
|||||||
val wireType = WireFormat.getTagWireType(tag)
|
val wireType = WireFormat.getTagWireType(tag)
|
||||||
when(fieldNumber) {
|
when(fieldNumber) {
|
||||||
1 -> {
|
1 -> {
|
||||||
val listSize = input.readInt32NoTag()
|
val expectedSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
var readSize = 0
|
||||||
|
while(readSize != expectedSize) {
|
||||||
val tmp: Person.BuilderPerson = Person.BuilderPerson()
|
val tmp: Person.BuilderPerson = Person.BuilderPerson()
|
||||||
tmp.readFromNoTag(input)
|
input.readTag(1, WireType.LENGTH_DELIMITED)
|
||||||
|
val expectedSize = input.readInt32NoTag()
|
||||||
|
tmp.readFrom(input)
|
||||||
|
if (expectedSize != tmp.getSize()) { throw InvalidProtocolBufferException ("Expected size ${expectedSize} got ${tmp.getSize()}") }
|
||||||
|
readSize += tmp.getSize() + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(tmp.getSize())
|
||||||
people.add(tmp.build())
|
people.add(tmp.build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,6 +414,17 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
|
|||||||
while(parseFieldFrom(input)) {}
|
while(parseFieldFrom(input)) {}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
fun getSize(): Int {
|
||||||
|
var size = 0
|
||||||
|
run {
|
||||||
|
var arraySize = 0
|
||||||
|
for (item in people) {
|
||||||
|
arraySize += item.getSize() + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(item.getSize())
|
||||||
|
}
|
||||||
|
size += arraySize + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(arraySize)
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -366,6 +435,17 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
|
|||||||
fun mergeFrom (input: CodedInputStream) {
|
fun mergeFrom (input: CodedInputStream) {
|
||||||
val builder = BuilderAddressBook()
|
val builder = BuilderAddressBook()
|
||||||
mergeWith(builder.parseFrom(input).build())}
|
mergeWith(builder.parseFrom(input).build())}
|
||||||
|
fun getSize(): Int {
|
||||||
|
var size = 0
|
||||||
|
run {
|
||||||
|
var arraySize = 0
|
||||||
|
for (item in people) {
|
||||||
|
arraySize += item.getSize() + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(item.getSize())
|
||||||
|
}
|
||||||
|
size += arraySize + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(arraySize)
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ fun testMessageSerialization() {
|
|||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.build() // don't forget to call build() to produce message
|
.build() // don't forget to call build() to produce message
|
||||||
msg.writeToNoTag(outs)
|
msg.writeTo(outs)
|
||||||
|
|
||||||
// Now let's use output stream as input to read our message from it!
|
// Now let's use output stream as input to read our message from it!
|
||||||
var ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
var ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
|
|||||||
@@ -4,8 +4,14 @@
|
|||||||
|
|
||||||
|
|
||||||
object WireFormat {
|
object WireFormat {
|
||||||
|
// couple of constants for magic numbers
|
||||||
val TAG_TYPE_BITS: Int = 3
|
val TAG_TYPE_BITS: Int = 3
|
||||||
val TAG_TYPE_MASK: Int = (1 shl TAG_TYPE_BITS) - 1
|
val TAG_TYPE_MASK: Int = (1 shl TAG_TYPE_BITS) - 1
|
||||||
|
val VARINT_INFO_BITS_COUNT: Int = 7
|
||||||
|
val VARINT_INFO_BITS_MASK: Int = 0b01111111 // mask for separating lowest 7 bits, where actual information stored
|
||||||
|
val VARINT_UTIL_BIT_MASK: Int = 0b10000000 // mask for separating highest bit, that indicates next byte presence
|
||||||
|
val FIXED_32_BYTE_SIZE: Int = 4
|
||||||
|
val FIXED_64_BYTE_SIZE: Int = 8
|
||||||
|
|
||||||
fun getTagWireType(tag: Int): WireType {
|
fun getTagWireType(tag: Int): WireType {
|
||||||
return WireType from (tag and TAG_TYPE_MASK).toByte()
|
return WireType from (tag and TAG_TYPE_MASK).toByte()
|
||||||
@@ -14,4 +20,95 @@ object WireFormat {
|
|||||||
fun getTagFieldNumber(tag: Int): Int {
|
fun getTagFieldNumber(tag: Int): Int {
|
||||||
return tag ushr TAG_TYPE_BITS
|
return tag ushr TAG_TYPE_BITS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: refactor casts into function overloading as soon as translator will support it
|
||||||
|
fun getTagSize(fieldNumber: Int, wireType: WireType): Int {
|
||||||
|
return getVarint32Size((fieldNumber shl 3) or wireType.ordinal)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getVarint32Size(value: Int): Int {
|
||||||
|
var curValue = value
|
||||||
|
var size = 0
|
||||||
|
while (curValue != 0) {
|
||||||
|
size += 1
|
||||||
|
curValue = value ushr VARINT_INFO_BITS_COUNT
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getVarint64Size(value: Long): Int {
|
||||||
|
var curValue = value
|
||||||
|
var size = 0
|
||||||
|
while (curValue != 0L) {
|
||||||
|
size += 1
|
||||||
|
curValue = value ushr VARINT_INFO_BITS_COUNT
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getZigZag32Size(value: Int): Int {
|
||||||
|
return getVarint32Size((value shl 1) xor (value shr 31))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getZigZag64Size(value: Long): Int {
|
||||||
|
return getVarint64Size((value shl 1) xor (value shr 63))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getInt32Size(fieldNumber: Int, value: Int): Int {
|
||||||
|
return getTagSize(fieldNumber, WireType.VARINT) + getVarint32Size(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUInt32Size(fieldNumber: Int, value: Int): Int {
|
||||||
|
return getInt32Size(fieldNumber, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getInt64Size(fieldNumber: Int, value: Long): Int {
|
||||||
|
return getTagSize(fieldNumber, WireType.VARINT) + getVarint64Size(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUInt64Size(fieldNumber: Int, value: Long): Int {
|
||||||
|
return getInt64Size(fieldNumber, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBoolSize(fieldNumber: Int, value: Boolean): Int {
|
||||||
|
val intValue = if (value) 1 else 0
|
||||||
|
return getInt32Size(fieldNumber, intValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getEnumSize(fieldNumber: Int, value: Int): Int {
|
||||||
|
return getInt32Size(fieldNumber, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSInt32Size(fieldNumber: Int, value: Int): Int {
|
||||||
|
return getTagSize(fieldNumber, WireType.VARINT) + getZigZag32Size(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSInt64Size(fieldNumber: Int, value: Long): Int {
|
||||||
|
return getTagSize(fieldNumber, WireType.VARINT) + getZigZag64Size(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFixed32Size(fieldNumber: Int, value: Long): Int {
|
||||||
|
return getTagSize(fieldNumber, WireType.FIX_32) + FIXED_32_BYTE_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFixed64Size(fieldNumber: Int, value: Long): Int {
|
||||||
|
return getTagSize(fieldNumber, WireType.FIX_64) + FIXED_64_BYTE_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDoubleSize(fieldNumber: Int, value: Double): Int {
|
||||||
|
return getTagSize(fieldNumber, WireType.FIX_32) + FIXED_32_BYTE_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFloatSize(fieldNumber: Int, value: Float): Int {
|
||||||
|
return getTagSize(fieldNumber, WireType.FIX_64) + FIXED_64_BYTE_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getStringSize(fieldNumber: Int, value: String): Int {
|
||||||
|
val encodedStringSize = value.toByteArray(Charsets.UTF_8).size //TODO: not sure if it's the best way to do it
|
||||||
|
return encodedStringSize + getTagSize(fieldNumber, WireType.LENGTH_DELIMITED) + getVarint32Size(encodedStringSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBytesSize(fieldNumber: Int, value: ByteArray): Int {
|
||||||
|
return value.size + getTagSize(fieldNumber, WireType.LENGTH_DELIMITED) + getVarint32Size(value.size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user