Added support for bytes type. Fixed a bit messages serialization. Made some refactoring
This commit is contained in:
@@ -22,7 +22,7 @@ In folder /src/ you can find sources for ProtoKot-runtime, that will be used by
|
|||||||
## Using generated code
|
## Using generated code
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
// Messages work only with CodedStream classes, provided by ProtoKot-runtime library.
|
// Messages work only with CodedStream classes, provided by ProtoKot-runtime library.
|
||||||
// One can create CodedStream passing any instance of corresponding Stream from Java's library.
|
// One can create CodedStream passing any instance of corresponding Stream from Java's library.
|
||||||
val s = ByteArrayOutputStream()
|
val s = ByteArrayOutputStream()
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
bin/kotlin_class_generator.o: src/kotlin_class_generator.cc \
|
|
||||||
src/kotlin_class_generator.h src/kotlin_field_generator.h \
|
|
||||||
src/kotlin_enum_generator.h
|
|
||||||
BIN
Binary file not shown.
@@ -1,2 +0,0 @@
|
|||||||
bin/kotlin_enum_generator.o: src/kotlin_enum_generator.cc \
|
|
||||||
src/kotlin_enum_generator.h
|
|
||||||
Binary file not shown.
@@ -1,2 +0,0 @@
|
|||||||
bin/kotlin_field_generator.o: src/kotlin_field_generator.cc \
|
|
||||||
src/kotlin_field_generator.h
|
|
||||||
BIN
Binary file not shown.
@@ -1,3 +0,0 @@
|
|||||||
bin/kotlin_file_generator.o: src/kotlin_file_generator.cc \
|
|
||||||
src/kotlin_file_generator.h src/kotlin_class_generator.h \
|
|
||||||
src/kotlin_field_generator.h src/kotlin_enum_generator.h
|
|
||||||
Binary file not shown.
@@ -1,3 +0,0 @@
|
|||||||
bin/main.o: src/main.cc src/kotlin_file_generator.h \
|
|
||||||
src/kotlin_class_generator.h src/kotlin_field_generator.h \
|
|
||||||
src/kotlin_enum_generator.h
|
|
||||||
Binary file not shown.
Binary file not shown.
+2
-14
@@ -22,7 +22,7 @@ void ClassGenerator::generateCode(io::Printer *printer, bool isBuilder) const {
|
|||||||
* Also note that fields should be declared before init section.
|
* Also note that fields should be declared before init section.
|
||||||
*/
|
*/
|
||||||
for (FieldGenerator *gen: properties) {
|
for (FieldGenerator *gen: properties) {
|
||||||
gen->generateCode(printer, isBuilder);
|
gen->generateCode(printer, isBuilder, simpleName);
|
||||||
printer->Print("\n");
|
printer->Print("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,9 +61,6 @@ void ClassGenerator::generateCode(io::Printer *printer, bool isBuilder) const {
|
|||||||
if (isBuilder) {
|
if (isBuilder) {
|
||||||
printer->Print("\n");
|
printer->Print("\n");
|
||||||
generateBuildMethod(printer);
|
generateBuildMethod(printer);
|
||||||
|
|
||||||
printer->Print("\n");
|
|
||||||
generateSetters(printer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printer->Outdent();
|
printer->Outdent();
|
||||||
@@ -72,7 +69,7 @@ void ClassGenerator::generateCode(io::Printer *printer, bool isBuilder) const {
|
|||||||
|
|
||||||
ClassGenerator::ClassGenerator(Descriptor const *descriptor)
|
ClassGenerator::ClassGenerator(Descriptor const *descriptor)
|
||||||
: descriptor(descriptor) {
|
: descriptor(descriptor) {
|
||||||
simpleName = descriptor->name(); // TODO: think about more careful class naming
|
simpleName = descriptor->name();
|
||||||
|
|
||||||
int field_count = descriptor->field_count();
|
int field_count = descriptor->field_count();
|
||||||
for (int i = 0; i < field_count; ++i) {
|
for (int i = 0; i < field_count; ++i) {
|
||||||
@@ -143,7 +140,6 @@ void ClassGenerator::generateSerializers(io::Printer * printer, bool isRead) con
|
|||||||
"\n");
|
"\n");
|
||||||
printer->Indent();
|
printer->Indent();
|
||||||
|
|
||||||
//TODO: write message tag and size
|
|
||||||
printer->Print(vars, "$maybeReturn$$funName$NoTag($arg$)\n");
|
printer->Print(vars, "$maybeReturn$$funName$NoTag($arg$)\n");
|
||||||
|
|
||||||
printer->Outdent();
|
printer->Outdent();
|
||||||
@@ -234,14 +230,6 @@ void ClassGenerator::generateInitSection(io::Printer * printer) const {
|
|||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassGenerator::generateSetters(io::Printer *printer) const {
|
|
||||||
for (int i = 0; i < properties.size(); ++i) {
|
|
||||||
properties[i]->generateSetter(printer, "Builder" + simpleName);
|
|
||||||
printer->Print("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const string ClassModifier::getName() const {
|
const string ClassModifier::getName() const {
|
||||||
string result = "";
|
string result = "";
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|||||||
+1
-2
@@ -47,7 +47,6 @@ private:
|
|||||||
void generateBuilder (io::Printer * printer) const;
|
void generateBuilder (io::Printer * printer) const;
|
||||||
void generateBuildMethod (io::Printer * printer) const;
|
void generateBuildMethod (io::Printer * printer) const;
|
||||||
void generateInitSection (io::Printer * printer) const;
|
void generateInitSection (io::Printer * printer) const;
|
||||||
void generateSetters (io::Printer * printer) const;
|
|
||||||
/**
|
/**
|
||||||
* Flag isBuilder used for reducing code repeating, as code for class itself
|
* Flag isBuilder used for reducing code repeating, as code for class itself
|
||||||
* and for its inner builder are structurally very alike and can be generated
|
* and for its inner builder are structurally very alike and can be generated
|
||||||
@@ -67,7 +66,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
} // namspace compiler
|
} // namespace compiler
|
||||||
} // namespace protobuf
|
} // namespace protobuf
|
||||||
} // namespace google
|
} // namespace google
|
||||||
#endif //SRC_KOTLIN_CLASS_GENERATOR_H
|
#endif //SRC_KOTLIN_CLASS_GENERATOR_H
|
||||||
|
|||||||
+1
-1
@@ -114,6 +114,6 @@ EnumGenerator::EnumGenerator(EnumDescriptor const *descriptor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
} // namspace compiler
|
} // namespace compiler
|
||||||
} // namespace protobuf
|
} // namespace protobuf
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
} // namspace compiler
|
} // namespace compiler
|
||||||
} // namespace protobuf
|
} // namespace protobuf
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|
||||||
|
|||||||
+131
-31
@@ -6,6 +6,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <google/protobuf/io/printer.h>
|
#include <google/protobuf/io/printer.h>
|
||||||
#include <google/protobuf/descriptor.h>
|
#include <google/protobuf/descriptor.h>
|
||||||
|
#include "kotlin_name_resolver.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
@@ -28,12 +29,19 @@ string FieldGenerator::protobufToKotlinField() const {
|
|||||||
postamble = "?";
|
postamble = "?";
|
||||||
break;
|
break;
|
||||||
case FieldDescriptor::LABEL_REPEATED:
|
case FieldDescriptor::LABEL_REPEATED:
|
||||||
|
#ifndef KOTLIN_GENERATED_CODE_LANGUAGE_LEVEL_LOW
|
||||||
|
preamble = "MutableList <";
|
||||||
|
postamble = "> ";
|
||||||
|
break;
|
||||||
|
#else
|
||||||
preamble = "Array <";
|
preamble = "Array <";
|
||||||
postamble = "> ";
|
postamble = "> ";
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return preamble + protobufToKotlinType() + postamble;
|
return preamble + protobufToKotlinType() + postamble;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simply maps protobuf field type to corresponding Kotlin.
|
* Simply maps protobuf field type to corresponding Kotlin.
|
||||||
*/
|
*/
|
||||||
@@ -43,7 +51,7 @@ string FieldGenerator::protobufToKotlinType() const {
|
|||||||
case FieldDescriptor::TYPE_BOOL:
|
case FieldDescriptor::TYPE_BOOL:
|
||||||
return "Boolean";
|
return "Boolean";
|
||||||
case FieldDescriptor::TYPE_BYTES:
|
case FieldDescriptor::TYPE_BYTES:
|
||||||
return ""; // TODO: support bytes type
|
return "ByteArray";
|
||||||
case FieldDescriptor::TYPE_DOUBLE:
|
case FieldDescriptor::TYPE_DOUBLE:
|
||||||
return "Double";
|
return "Double";
|
||||||
case FieldDescriptor::TYPE_ENUM:
|
case FieldDescriptor::TYPE_ENUM:
|
||||||
@@ -56,8 +64,6 @@ string FieldGenerator::protobufToKotlinType() const {
|
|||||||
return "Long";
|
return "Long";
|
||||||
case FieldDescriptor::TYPE_FLOAT:
|
case FieldDescriptor::TYPE_FLOAT:
|
||||||
return "Float";
|
return "Float";
|
||||||
case FieldDescriptor::TYPE_GROUP:
|
|
||||||
return ""; // @deprecated //TODO: make proper error handling there
|
|
||||||
case FieldDescriptor::TYPE_INT32:
|
case FieldDescriptor::TYPE_INT32:
|
||||||
return "Int";
|
return "Int";
|
||||||
case FieldDescriptor::TYPE_INT64:
|
case FieldDescriptor::TYPE_INT64:
|
||||||
@@ -82,25 +88,73 @@ string FieldGenerator::protobufToKotlinType() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string FieldGenerator::getInitValue() const {
|
string FieldGenerator::getInitValue() const {
|
||||||
if (descriptor->is_optional()) {
|
|
||||||
return "null";
|
|
||||||
}
|
|
||||||
if (descriptor->is_repeated())
|
if (descriptor->is_repeated())
|
||||||
|
#ifndef KOTLIN_GENERATED_CODE_LANGUAGE_LEVEL_LOW
|
||||||
|
return "mutableListOf()";
|
||||||
|
#else
|
||||||
return "arrayOf()";
|
return "arrayOf()";
|
||||||
return fullType + "()";
|
#endif
|
||||||
|
|
||||||
|
FieldDescriptor::Type type = descriptor->type();
|
||||||
|
switch(type) {
|
||||||
|
case FieldDescriptor::TYPE_BOOL:
|
||||||
|
return "false";
|
||||||
|
case FieldDescriptor::TYPE_BYTES:
|
||||||
|
return "ByteArray(0)";
|
||||||
|
case FieldDescriptor::TYPE_DOUBLE:
|
||||||
|
return "0.0";
|
||||||
|
case FieldDescriptor::TYPE_ENUM: {
|
||||||
|
string enumType = descriptor->enum_type()->name();
|
||||||
|
return enumType + ".fromIntTo" + enumType + "(0)"; // produce enum from 0, as demanded by Google
|
||||||
|
}
|
||||||
|
case FieldDescriptor::TYPE_FIXED32:
|
||||||
|
return "0";
|
||||||
|
case FieldDescriptor::TYPE_FIXED64:
|
||||||
|
return "0L";
|
||||||
|
case FieldDescriptor::TYPE_FLOAT:
|
||||||
|
return "0f";
|
||||||
|
case FieldDescriptor::TYPE_INT32:
|
||||||
|
return "0";
|
||||||
|
case FieldDescriptor::TYPE_INT64:
|
||||||
|
return "0L";
|
||||||
|
case FieldDescriptor::TYPE_MESSAGE:
|
||||||
|
return string(descriptor->message_type()->name()) + "()";
|
||||||
|
case FieldDescriptor::TYPE_SFIXED32:
|
||||||
|
return "0";
|
||||||
|
case FieldDescriptor::TYPE_SFIXED64:
|
||||||
|
return "0L";
|
||||||
|
case FieldDescriptor::TYPE_SINT32:
|
||||||
|
return "0";
|
||||||
|
case FieldDescriptor::TYPE_SINT64:
|
||||||
|
return "0L";
|
||||||
|
case FieldDescriptor::TYPE_STRING:
|
||||||
|
return "\"\"";
|
||||||
|
case FieldDescriptor::TYPE_UINT32:
|
||||||
|
return "0"; // see notes for TYPE_FIXED32
|
||||||
|
case FieldDescriptor::TYPE_UINT64:
|
||||||
|
return "0L"; // see notes for TYPE_FIXED64
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldGenerator::generateCode(io::Printer *printer, bool isBuilder) const {
|
void FieldGenerator::generateCode(io::Printer *printer, bool isBuilder, string className) const {
|
||||||
map<string, string> vars;
|
map<string, string> vars;
|
||||||
vars["name"] = simpleName;
|
vars["name"] = simpleName;
|
||||||
vars["field"] = protobufToKotlinField();
|
vars["field"] = protobufToKotlinField();
|
||||||
printer->Print(vars, "var $name$ : $field$\n");
|
printer->Print(vars, "var $name$ : $field$\n");
|
||||||
|
|
||||||
// make setter private for fair classes
|
// make setter private
|
||||||
if (!isBuilder) {
|
printer->Indent();
|
||||||
printer->Indent();
|
printer->Print("private set\n");
|
||||||
printer->Print("private set\n");
|
printer->Outdent();
|
||||||
printer->Outdent();
|
|
||||||
|
// generate setter for builder
|
||||||
|
if (isBuilder) {
|
||||||
|
generateSetter(printer, /* builderName = */ "Builder" + className);
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate additional methods for repeated fields
|
||||||
|
if (modifier == FieldDescriptor::LABEL_REPEATED) {
|
||||||
|
generateRepeatedMethods(printer, isBuilder, /* builderName = */ "Builder" + className);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +191,7 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
|
|||||||
//TODO: dirty stub here! Normally, reading from input should be delegated to Parsers, with proper error handling and etc.
|
//TODO: dirty stub here! Normally, reading from input should be delegated to Parsers, with proper error handling and etc.
|
||||||
//Currently tag is ignored, and work of the library relies heavily on the field order guarantees.
|
//Currently tag is ignored, and work of the library relies heavily on the field order guarantees.
|
||||||
//Thus, backward-compability and extensions are not supported.
|
//Thus, backward-compability and extensions are not supported.
|
||||||
printer->Print(vars, "val tag = input.readTag()\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 listSize = input.readInt32NoTag()\n");
|
||||||
printer->Print(vars, "for (i in 1..listSize) {\n");
|
printer->Print(vars, "for (i in 1..listSize) {\n");
|
||||||
printer->Indent();
|
printer->Indent();
|
||||||
@@ -146,8 +200,12 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
|
|||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// tag
|
||||||
|
printer->Print(vars, "output.writeTag($fieldNumber$, WireType.LENGTH_DELIMITED)\n");
|
||||||
|
|
||||||
// length
|
// length
|
||||||
printer->Print(vars, "$arg$.writeInt32NoTag($fieldName$.size)\n");
|
printer->Print(vars, "output.writeInt32NoTag($fieldName$.size)\n");
|
||||||
|
printer->Print(vars, "output.writeInt32NoTag($fieldName$.size)\n");
|
||||||
|
|
||||||
// all elements
|
// all elements
|
||||||
printer->Print(vars, "for (item in $fieldName$) {\n");
|
printer->Print(vars, "for (item in $fieldName$) {\n");
|
||||||
@@ -201,11 +259,16 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
|
|||||||
if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
|
if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
|
||||||
vars["fieldName"] = noTag ? "item" : simpleName;
|
vars["fieldName"] = noTag ? "item" : simpleName;
|
||||||
vars["maybeNoTag"] = noTag ? "NoTag" : "";
|
vars["maybeNoTag"] = noTag ? "NoTag" : "";
|
||||||
|
vars["fieldNumber"] = std::to_string(descriptor->number());
|
||||||
if (isRead) {
|
if (isRead) {
|
||||||
printer->Print(vars, "$fieldName$.readFrom$maybeNoTag$(input)\n");
|
printer->Print(vars,
|
||||||
|
"val tag = input.readTag($fieldNumber$, WireType.LENGTH_DELIMITED)\n"
|
||||||
|
"$fieldName$.readFrom$maybeNoTag$(input)\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printer->Print(vars, "$fieldName$.writeTo$maybeNoTag$(output)\n");
|
printer->Print(vars,
|
||||||
|
"output.writeTag($fieldNumber$, WireType.LENGTH_DELIMITED)\n"
|
||||||
|
"$fieldName$.writeTo$maybeNoTag$(output)\n");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -217,9 +280,6 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
|
|||||||
else {
|
else {
|
||||||
printer->Print(vars, "output.write$type$ ($fieldNumber$, $fieldName$)\n");
|
printer->Print(vars, "output.write$type$ ($fieldNumber$, $fieldName$)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: support tricky types like enums/messages/repeated fields/etc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string FieldGenerator::protobufTypeToKotlinFunctionSuffix(FieldDescriptor::Type type) const {
|
string FieldGenerator::protobufTypeToKotlinFunctionSuffix(FieldDescriptor::Type type) const {
|
||||||
@@ -242,12 +302,10 @@ string FieldGenerator::protobufTypeToKotlinFunctionSuffix(FieldDescriptor::Type
|
|||||||
return "Bool";
|
return "Bool";
|
||||||
case FieldDescriptor::TYPE_STRING:
|
case FieldDescriptor::TYPE_STRING:
|
||||||
return "String";
|
return "String";
|
||||||
case FieldDescriptor::TYPE_GROUP:
|
|
||||||
return ""; // deprecated // TODO: think about proper error handling here
|
|
||||||
case FieldDescriptor::TYPE_MESSAGE:
|
case FieldDescriptor::TYPE_MESSAGE:
|
||||||
return "Message"; // TODO: support messages
|
return "Message";
|
||||||
case FieldDescriptor::TYPE_BYTES:
|
case FieldDescriptor::TYPE_BYTES:
|
||||||
return ""; // TODO: support bytes
|
return "Bytes";
|
||||||
case FieldDescriptor::TYPE_UINT32:
|
case FieldDescriptor::TYPE_UINT32:
|
||||||
return "UInt32";
|
return "UInt32";
|
||||||
case FieldDescriptor::TYPE_ENUM:
|
case FieldDescriptor::TYPE_ENUM:
|
||||||
@@ -265,25 +323,67 @@ string FieldGenerator::protobufTypeToKotlinFunctionSuffix(FieldDescriptor::Type
|
|||||||
|
|
||||||
void FieldGenerator::generateSetter(io::Printer *printer, string builderName) const {
|
void FieldGenerator::generateSetter(io::Printer *printer, string builderName) const {
|
||||||
map <string, string> vars;
|
map <string, string> vars;
|
||||||
// TODO: refactor work with names into separate class
|
vars["camelCaseName"] = name_resolving::makeFirstLetterUpper(simpleName);
|
||||||
string camelCaseName = simpleName;
|
vars["fieldName"] = simpleName;
|
||||||
camelCaseName[0] = char(std::toupper(camelCaseName[0]));
|
|
||||||
vars["camelCaseName"] = camelCaseName;
|
|
||||||
vars["name"] = simpleName;
|
|
||||||
vars["builderName"] = builderName;
|
vars["builderName"] = builderName;
|
||||||
vars["type"] = fullType;
|
vars["type"] = fullType;
|
||||||
printer->Print(vars,
|
printer->Print(vars,
|
||||||
"fun set$camelCaseName$(value: $type$): $builderName$ {\n");
|
"fun set$camelCaseName$(value: $type$): $builderName$ {\n");
|
||||||
printer->Indent();
|
printer->Indent();
|
||||||
printer->Print(vars,
|
printer->Print(vars,
|
||||||
"$name$ = value\n"
|
"$fieldName$ = value\n"
|
||||||
"return this\n");
|
"return this\n");
|
||||||
printer->Outdent();
|
printer->Outdent();
|
||||||
printer->Print("}\n");
|
printer->Print("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FieldGenerator::generateRepeatedMethods(io::Printer * printer, bool isBuilder, string builderName) const {
|
||||||
|
map <string, string> vars;
|
||||||
|
vars["elementType"] = underlyingType;
|
||||||
|
vars["arg"] = "value";
|
||||||
|
vars["fieldName"] = simpleName;
|
||||||
|
vars["builderName"] = builderName;
|
||||||
|
|
||||||
|
// generate indexed setter for builders
|
||||||
|
if (isBuilder) {
|
||||||
|
printer->Print(vars, "fun set$elementType$(index: Int, $arg$: $elementType$): $builderName$ {\n");
|
||||||
|
printer->Indent();
|
||||||
|
printer->Print(vars, "$fieldName$[index] = $arg$\n");
|
||||||
|
printer->Print(vars, "return this\n");
|
||||||
|
printer->Outdent();
|
||||||
|
printer->Print("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef KOTLIN_GENERATED_CODE_LANGUAGE_LEVEL_LOW
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
} // namspace compiler
|
} // namespace compiler
|
||||||
} // namespace protobuf
|
} // namespace protobuf
|
||||||
} // namespace google
|
} // namespace google
|
||||||
+4
-4
@@ -30,7 +30,8 @@ private:
|
|||||||
* CodedInputStream.readSFixed32(fieldNumber: Int)
|
* CodedInputStream.readSFixed32(fieldNumber: Int)
|
||||||
*/
|
*/
|
||||||
string protobufTypeToKotlinFunctionSuffix(FieldDescriptor::Type type) const;
|
string protobufTypeToKotlinFunctionSuffix(FieldDescriptor::Type type) const;
|
||||||
|
void generateSetter(io::Printer * printer, string builderName) const;
|
||||||
|
void generateRepeatedMethods(io::Printer * printer, bool isBuilder, string builderName) const;
|
||||||
public:
|
public:
|
||||||
FieldDescriptor::Label modifier;
|
FieldDescriptor::Label modifier;
|
||||||
string simpleName;
|
string simpleName;
|
||||||
@@ -45,15 +46,14 @@ public:
|
|||||||
string fullType;
|
string fullType;
|
||||||
|
|
||||||
string initValue;
|
string initValue;
|
||||||
void generateCode(io::Printer * printer, bool isBuilder = false) const;
|
void generateCode(io::Printer * printer, bool isBuilder, string className) 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 generateSetter(io::Printer * printer, string builderName) const;
|
|
||||||
FieldGenerator(FieldDescriptor const * descriptor);
|
FieldGenerator(FieldDescriptor const * descriptor);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace kotlin
|
} // namespace kotlin
|
||||||
} // namspace compiler
|
} // namespace compiler
|
||||||
} // namespace protobuf
|
} // namespace protobuf
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|
||||||
|
|||||||
+2
-8
@@ -10,6 +10,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "kotlin_file_generator.h"
|
#include "kotlin_file_generator.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "kotlin_name_resolver.h"
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
namespace protobuf {
|
namespace protobuf {
|
||||||
@@ -26,14 +27,7 @@ void FileGenerator::generateCode(io::Printer *printer, std::vector<ClassGenerato
|
|||||||
bool FileGenerator::Generate(const FileDescriptor *file, const string ¶meter, GeneratorContext *context,
|
bool FileGenerator::Generate(const FileDescriptor *file, const string ¶meter, GeneratorContext *context,
|
||||||
string *error) const {
|
string *error) const {
|
||||||
std::vector<ClassGenerator *> classes;
|
std::vector<ClassGenerator *> classes;
|
||||||
|
string const file_name = name_resolving::getKotlinOutputByProtoName(file->name());
|
||||||
//TODO: maybe wrap work with class names and stuff in separate class (like in Java implementation)
|
|
||||||
// Get output file name
|
|
||||||
string const proto_file_name = file->name();
|
|
||||||
size_t file_extension_index = proto_file_name.find(".proto");
|
|
||||||
string const file_name = proto_file_name.substr(0, file_extension_index) + ".kt";
|
|
||||||
|
|
||||||
|
|
||||||
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(file_name));
|
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(file_name));
|
||||||
io::Printer printer(output.get(), '$', /* annotation_collector = */ NULL);
|
io::Printer printer(output.get(), '$', /* annotation_collector = */ NULL);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// Created by user on 7/14/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "kotlin_name_resolver.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace google {
|
||||||
|
namespace protobuf {
|
||||||
|
namespace compiler {
|
||||||
|
namespace kotlin {
|
||||||
|
|
||||||
|
namespace name_resolving {
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
string makeFirstLetterUpper(std::string s) {
|
||||||
|
s[0] = std::toupper(s[0]);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
string getFileNameWithoutExtension(string fullName) {
|
||||||
|
size_t file_extension_index = fullName.find_last_of(".");
|
||||||
|
return fullName.substr(0, file_extension_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
string getKotlinOutputByProtoName(string protoName) {
|
||||||
|
string justName = getFileNameWithoutExtension(protoName);
|
||||||
|
return justName + ".kt";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace name_resolving
|
||||||
|
} // namespace kotlin
|
||||||
|
} // namespace compiler
|
||||||
|
} // namespace protobuf
|
||||||
|
} // namespace google
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// Created by user on 7/14/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GOOGLE_KOTLIN_NAME_RESOLVER_H
|
||||||
|
#define GOOGLE_KOTLIN_NAME_RESOLVER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace google {
|
||||||
|
namespace protobuf {
|
||||||
|
namespace compiler {
|
||||||
|
namespace kotlin {
|
||||||
|
namespace name_resolving {
|
||||||
|
|
||||||
|
std::string makeFirstLetterUpper(std::string s);
|
||||||
|
|
||||||
|
std::string getFileNameWithoutExtension(std::string fullName);
|
||||||
|
|
||||||
|
std::string getKotlinOutputByProtoName(std::string protoName);
|
||||||
|
|
||||||
|
} // namespace name_resolving
|
||||||
|
} // namespace kotlin
|
||||||
|
} // namespace compiler
|
||||||
|
} // namespace protobuf
|
||||||
|
} // namespace google
|
||||||
|
|
||||||
|
|
||||||
|
#endif //GOOGLE_KOTLIN_NAME_RESOLVER_H
|
||||||
@@ -3,8 +3,6 @@
|
|||||||
#include <google/protobuf/compiler/python/python_generator.h>
|
#include <google/protobuf/compiler/python/python_generator.h>
|
||||||
#include <google/protobuf/compiler/java/java_generator.h>
|
#include <google/protobuf/compiler/java/java_generator.h>
|
||||||
#include <google/protobuf/compiler/javanano/javanano_generator.h>
|
#include <google/protobuf/compiler/javanano/javanano_generator.h>
|
||||||
// TODO(teboring): Add it back when php implementation is ready
|
|
||||||
// #include <google/protobuf/compiler/php/php_generator.h>
|
|
||||||
#include <google/protobuf/compiler/ruby/ruby_generator.h>
|
#include <google/protobuf/compiler/ruby/ruby_generator.h>
|
||||||
#include <google/protobuf/compiler/csharp/csharp_generator.h>
|
#include <google/protobuf/compiler/csharp/csharp_generator.h>
|
||||||
#include <google/protobuf/compiler/objectivec/objectivec_generator.h>
|
#include <google/protobuf/compiler/objectivec/objectivec_generator.h>
|
||||||
@@ -12,6 +10,7 @@
|
|||||||
#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;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
class Person private constructor (name: kotlin.String? = null, id: Int? = null, email: kotlin.String? = null, phones: Array <PhoneNumber> = arrayOf()) {
|
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
|
||||||
|
|
||||||
@@ -8,7 +8,10 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
var email : kotlin.String?
|
var email : kotlin.String?
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var phones : Array <PhoneNumber>
|
var phones : MutableList <PhoneNumber>
|
||||||
|
private set
|
||||||
|
|
||||||
|
var someBytes : ByteArray?
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|
||||||
@@ -17,6 +20,7 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
this.id = id
|
this.id = id
|
||||||
this.email = email
|
this.email = email
|
||||||
this.phones = phones
|
this.phones = phones
|
||||||
|
this.someBytes = someBytes
|
||||||
}
|
}
|
||||||
enum class PhoneType(val ord: Int) {
|
enum class PhoneType(val ord: Int) {
|
||||||
MOBILE (0),
|
MOBILE (0),
|
||||||
@@ -34,7 +38,7 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class PhoneNumber private constructor (number: kotlin.String? = null, type: PhoneType? = null) {
|
class PhoneNumber private constructor (number: kotlin.String? = "", type: PhoneType? = PhoneType.fromIntToPhoneType(0)) {
|
||||||
var number : kotlin.String?
|
var number : kotlin.String?
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -47,19 +51,29 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
this.type = type
|
this.type = type
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeTo (output: CodedOutputStream) {
|
fun writeTo (output: CodedOutputStream): Unit {
|
||||||
writeToNoTag(output)
|
writeToNoTag(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeToNoTag (output: CodedOutputStream) {
|
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? = null, type: PhoneType? = null) {
|
class BuilderPhoneNumber constructor (number: kotlin.String? = "", type: PhoneType? = PhoneType.fromIntToPhoneType(0)) {
|
||||||
var number : kotlin.String?
|
var number : kotlin.String?
|
||||||
|
private set
|
||||||
|
fun setNumber(value: kotlin.String?): BuilderPhoneNumber {
|
||||||
|
number = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
var type : PhoneType?
|
var type : PhoneType?
|
||||||
|
private set
|
||||||
|
fun setType(value: PhoneType?): BuilderPhoneNumber {
|
||||||
|
type = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -67,29 +81,19 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
this.type = type
|
this.type = type
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom (input: CodedInputStream) {
|
fun readFrom (input: CodedInputStream): BuilderPhoneNumber {
|
||||||
readFromNoTag(input)
|
return readFromNoTag(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFromNoTag (input: CodedInputStream) {
|
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
|
||||||
|
}
|
||||||
|
|
||||||
fun build(): PhoneNumber {
|
fun build(): PhoneNumber {
|
||||||
return PhoneNumber(number, type)
|
return PhoneNumber(number, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setNumber(value: kotlin.String?): BuilderPhoneNumber {
|
|
||||||
number = value
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setType(value: PhoneType?): BuilderPhoneNumber {
|
|
||||||
type = value
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mergeFrom (input: CodedInputStream) {
|
fun mergeFrom (input: CodedInputStream) {
|
||||||
@@ -99,30 +103,75 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun writeTo (output: CodedOutputStream) {
|
fun writeTo (output: CodedOutputStream): Unit {
|
||||||
writeToNoTag(output)
|
writeToNoTag(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeToNoTag (output: CodedOutputStream) {
|
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.writeInt32NoTag(phones.size)
|
||||||
output.writeInt32NoTag(phones.size)
|
output.writeInt32NoTag(phones.size)
|
||||||
for (item in phones) {
|
for (item in phones) {
|
||||||
|
output.writeTag(4, WireType.LENGTH_DELIMITED)
|
||||||
item.writeToNoTag(output)
|
item.writeToNoTag(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
output.writeBytes (5, someBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
class BuilderPerson constructor (name: kotlin.String? = null, id: Int? = null, email: kotlin.String? = null, phones: Array <PhoneNumber> = arrayOf()) {
|
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
|
||||||
|
fun setName(value: kotlin.String?): BuilderPerson {
|
||||||
|
name = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
var id : Int?
|
var id : Int?
|
||||||
|
private set
|
||||||
|
fun setId(value: Int?): BuilderPerson {
|
||||||
|
id = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
var email : kotlin.String?
|
var email : kotlin.String?
|
||||||
|
private set
|
||||||
|
fun setEmail(value: kotlin.String?): BuilderPerson {
|
||||||
|
email = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
var phones : Array <PhoneNumber>
|
var phones : MutableList <PhoneNumber>
|
||||||
|
private set
|
||||||
|
fun setPhones(value: MutableList <PhoneNumber> ): BuilderPerson {
|
||||||
|
phones = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun setPhoneNumber(index: Int, value: PhoneNumber): BuilderPerson {
|
||||||
|
phones[index] = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun addPhoneNumber(value: PhoneNumber): BuilderPerson {
|
||||||
|
phones.add(value)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun addAllPhoneNumber(value: Iterable<PhoneNumber>): BuilderPerson {
|
||||||
|
for (item in value) {
|
||||||
|
phones.add(item)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
var someBytes : ByteArray?
|
||||||
|
private set
|
||||||
|
fun setSomeBytes(value: ByteArray?): BuilderPerson {
|
||||||
|
someBytes = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -130,49 +179,31 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
this.id = id
|
this.id = id
|
||||||
this.email = email
|
this.email = email
|
||||||
this.phones = phones
|
this.phones = phones
|
||||||
|
this.someBytes = someBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom (input: CodedInputStream) {
|
fun readFrom (input: CodedInputStream): BuilderPerson {
|
||||||
readFromNoTag(input)
|
return readFromNoTag(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFromNoTag (input: CodedInputStream) {
|
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)
|
||||||
if (phones.size > 0) {
|
if (phones.size > 0) {
|
||||||
val tag = input.readTag()
|
val tag = input.readTag(4, WireType.LENGTH_DELIMITED)
|
||||||
val listSize = input.readInt32NoTag()
|
val listSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
for (i in 1..listSize) {
|
||||||
phones[i - 1].mergeFrom(input)
|
phones[i - 1].mergeFrom(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
someBytes = input.readBytes(5)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
fun build(): Person {
|
fun build(): Person {
|
||||||
return Person(name, id, email, phones)
|
return Person(name, id, email, phones, someBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setName(value: kotlin.String?): BuilderPerson {
|
|
||||||
name = value
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setId(value: Int?): BuilderPerson {
|
|
||||||
id = value
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setEmail(value: kotlin.String?): BuilderPerson {
|
|
||||||
email = value
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setPhones(value: Array <PhoneNumber> ): BuilderPerson {
|
|
||||||
phones = value
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mergeFrom (input: CodedInputStream) {
|
fun mergeFrom (input: CodedInputStream) {
|
||||||
@@ -180,18 +211,19 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
id = input.readInt32(2)
|
id = input.readInt32(2)
|
||||||
email = input.readString(3)
|
email = input.readString(3)
|
||||||
if (phones.size > 0) {
|
if (phones.size > 0) {
|
||||||
val tag = input.readTag()
|
val tag = input.readTag(4, WireType.LENGTH_DELIMITED)
|
||||||
val listSize = input.readInt32NoTag()
|
val listSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
for (i in 1..listSize) {
|
||||||
phones[i - 1].mergeFrom(input)
|
phones[i - 1].mergeFrom(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
someBytes = input.readBytes(5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AddressBook private constructor (people: Array <Person> = arrayOf()) {
|
class AddressBook private constructor (people: MutableList <Person> = mutableListOf()) {
|
||||||
var people : Array <Person>
|
var people : MutableList <Person>
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|
||||||
@@ -199,55 +231,72 @@ class AddressBook private constructor (people: Array <Person> = arrayOf()) {
|
|||||||
this.people = people
|
this.people = people
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeTo (output: CodedOutputStream) {
|
fun writeTo (output: CodedOutputStream): Unit {
|
||||||
writeToNoTag(output)
|
writeToNoTag(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeToNoTag (output: CodedOutputStream) {
|
fun writeToNoTag (output: CodedOutputStream): Unit {
|
||||||
if (people.size > 0) {
|
if (people.size > 0) {
|
||||||
|
output.writeTag(1, WireType.LENGTH_DELIMITED)
|
||||||
|
output.writeInt32NoTag(people.size)
|
||||||
output.writeInt32NoTag(people.size)
|
output.writeInt32NoTag(people.size)
|
||||||
for (item in people) {
|
for (item in people) {
|
||||||
|
output.writeTag(1, WireType.LENGTH_DELIMITED)
|
||||||
item.writeToNoTag(output)
|
item.writeToNoTag(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BuilderAddressBook constructor (people: Array <Person> = arrayOf()) {
|
class BuilderAddressBook constructor (people: MutableList <Person> = mutableListOf()) {
|
||||||
var people : Array <Person>
|
var people : MutableList <Person>
|
||||||
|
private set
|
||||||
|
fun setPeople(value: MutableList <Person> ): BuilderAddressBook {
|
||||||
|
people = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun setPerson(index: Int, value: Person): BuilderAddressBook {
|
||||||
|
people[index] = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun addPerson(value: Person): BuilderAddressBook {
|
||||||
|
people.add(value)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun addAllPerson(value: Iterable<Person>): BuilderAddressBook {
|
||||||
|
for (item in value) {
|
||||||
|
people.add(item)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
this.people = people
|
this.people = people
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom (input: CodedInputStream) {
|
fun readFrom (input: CodedInputStream): BuilderAddressBook {
|
||||||
readFromNoTag(input)
|
return readFromNoTag(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFromNoTag (input: CodedInputStream) {
|
fun readFromNoTag (input: CodedInputStream): BuilderAddressBook {
|
||||||
if (people.size > 0) {
|
if (people.size > 0) {
|
||||||
val tag = input.readTag()
|
val tag = input.readTag(1, WireType.LENGTH_DELIMITED)
|
||||||
val listSize = input.readInt32NoTag()
|
val listSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
for (i in 1..listSize) {
|
||||||
people[i - 1].mergeFrom(input)
|
people[i - 1].mergeFrom(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
fun build(): AddressBook {
|
fun build(): AddressBook {
|
||||||
return AddressBook(people)
|
return AddressBook(people)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setPeople(value: Array <Person> ): BuilderAddressBook {
|
|
||||||
people = value
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mergeFrom (input: CodedInputStream) {
|
fun mergeFrom (input: CodedInputStream) {
|
||||||
if (people.size > 0) {
|
if (people.size > 0) {
|
||||||
val tag = input.readTag()
|
val tag = input.readTag(1, WireType.LENGTH_DELIMITED)
|
||||||
val listSize = input.readInt32NoTag()
|
val listSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
for (i in 1..listSize) {
|
||||||
people[i - 1].mergeFrom(input)
|
people[i - 1].mergeFrom(input)
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ message Person {
|
|||||||
}
|
}
|
||||||
|
|
||||||
repeated PhoneNumber phones = 4;
|
repeated PhoneNumber phones = 4;
|
||||||
|
|
||||||
|
bytes someBytes = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our address book file is just one of these.
|
// Our address book file is just one of these.
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import java.nio.ByteOrder
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: decide, if we want to optimize for performance (then we have to deal with spaghetti-code)
|
// 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
|
||||||
@@ -20,7 +20,7 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readInt32(expectedFieldNumber: Int): Int {
|
fun readInt32(expectedFieldNumber: Int): Int {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.VARINT)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
val actualWireType = WireFormat.getTagWireType(tag)
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.VARINT, actualWireType)
|
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.VARINT, actualWireType)
|
||||||
@@ -31,10 +31,7 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
// simply stored in the sign bit - similar to Java's protobuf implementation. Hence, all
|
// simply stored in the sign bit - similar to Java's protobuf implementation. Hence, all
|
||||||
// methods reading unsigned ints simply redirect call to corresponding signed-reading method
|
// methods reading unsigned ints simply redirect call to corresponding signed-reading method
|
||||||
fun readUInt32(expectedFieldNumber: Int): Int {
|
fun readUInt32(expectedFieldNumber: Int): Int {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.VARINT)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.VARINT, actualWireType)
|
|
||||||
return readUInt32NoTag()
|
return readUInt32NoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,19 +40,13 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readInt64(expectedFieldNumber: Int): Long {
|
fun readInt64(expectedFieldNumber: Int): Long {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.VARINT)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, actualWireType, WireType.VARINT)
|
|
||||||
return readInt64NoTag()
|
return readInt64NoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
// See note on unsigned integers implementations above
|
// See note on unsigned integers implementations above
|
||||||
fun readUInt64(expectedFieldNumber: Int): Long {
|
fun readUInt64(expectedFieldNumber: Int): Long {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.VARINT)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, actualWireType, WireType.VARINT)
|
|
||||||
return readUInt64NoTag()
|
return readUInt64NoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,10 +55,7 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readBool(expectedFieldNumber: Int): Boolean {
|
fun readBool(expectedFieldNumber: Int): Boolean {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.VARINT)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, actualWireType, WireType.VARINT)
|
|
||||||
return readBoolNoTag()
|
return readBoolNoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,10 +71,7 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
|
|
||||||
// Reading enums is like reading one int32 number. Caller is responsible for converting this ordinal to enum-object
|
// Reading enums is like reading one int32 number. Caller is responsible for converting this ordinal to enum-object
|
||||||
fun readEnum(expectedFieldNumber: Int): Int {
|
fun readEnum(expectedFieldNumber: Int): Int {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.VARINT)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.VARINT, actualWireType)
|
|
||||||
return readEnumNoTag()
|
return readEnumNoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,10 +80,7 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readSInt32(expectedFieldNumber: Int): Int {
|
fun readSInt32(expectedFieldNumber: Int): Int {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.VARINT)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.VARINT, actualWireType)
|
|
||||||
return readSInt32NoTag()
|
return readSInt32NoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,18 +89,12 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readSInt64(expectedFieldNumber: Int): Long {
|
fun readSInt64(expectedFieldNumber: Int): Long {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.VARINT)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.VARINT, actualWireType)
|
|
||||||
return readZigZag64NoTag()
|
return readZigZag64NoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFixed32(expectedFieldNumber: Int): Int {
|
fun readFixed32(expectedFieldNumber: Int): Int {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.FIX_32)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.FIX_32, actualWireType)
|
|
||||||
return readFixed32NoInt()
|
return readFixed32NoInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,10 +103,7 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readSFixed32(expectedFieldNumber: Int): Int {
|
fun readSFixed32(expectedFieldNumber: Int): Int {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.FIX_32)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.FIX_32, actualWireType)
|
|
||||||
return readSFixed32NoTag()
|
return readSFixed32NoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,10 +112,7 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readFixed64(expectedFieldNumber: Int): Long {
|
fun readFixed64(expectedFieldNumber: Int): Long {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.FIX_64)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.FIX_64, actualWireType)
|
|
||||||
return readFixed64NoTag()
|
return readFixed64NoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,10 +121,7 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readSFixed64(expectedFieldNumber: Int): Long {
|
fun readSFixed64(expectedFieldNumber: Int): Long {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.FIX_64)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.FIX_64, actualWireType)
|
|
||||||
return readSFixed64NoTag()
|
return readSFixed64NoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,10 +130,7 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readDouble(expectedFieldNumber: Int): Double {
|
fun readDouble(expectedFieldNumber: Int): Double {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.FIX_64)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.FIX_64, actualWireType)
|
|
||||||
return readDoubleNoTag()
|
return readDoubleNoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,10 +139,7 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readFloat(expectedFieldNumber: Int): Float {
|
fun readFloat(expectedFieldNumber: Int): Float {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.FIX_32)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.FIX_32, actualWireType)
|
|
||||||
return readFloatNoTag()
|
return readFloatNoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,10 +148,7 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readString(expectedFieldNumber: Int): String {
|
fun readString(expectedFieldNumber: Int): String {
|
||||||
val tag = readTag()
|
val tag = readTag(expectedFieldNumber, WireType.LENGTH_DELIMITED)
|
||||||
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
|
||||||
val actualWireType = WireFormat.getTagWireType(tag)
|
|
||||||
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.LENGTH_DELIMITED, actualWireType)
|
|
||||||
return readStringNoTag()
|
return readStringNoTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,6 +157,17 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
val value = String(readRawBytes(length))
|
val value = String(readRawBytes(length))
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun readBytes(expectedFieldNumber: Int): ByteArray {
|
||||||
|
val tag = readTag(expectedFieldNumber, WireType.LENGTH_DELIMITED)
|
||||||
|
return readBytesNoTag()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readBytesNoTag(): ByteArray {
|
||||||
|
val length = readInt32NoTag()
|
||||||
|
return readRawBytes(length)
|
||||||
|
}
|
||||||
|
|
||||||
/** ============ Utility methods ==================
|
/** ============ Utility methods ==================
|
||||||
* They are left non-private for cases when one wants to implement her/his own protocol format.
|
* They are left non-private for cases when one wants to implement her/his own protocol format.
|
||||||
* Then she/he can re-use low-level methods for operating with raw values, that are not annotated with Protobuf tags.
|
* Then she/he can re-use low-level methods for operating with raw values, that are not annotated with Protobuf tags.
|
||||||
@@ -254,7 +223,7 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// reads tag. Note that it returns 0 for the end of message!
|
// reads tag. Note that it returns 0 for the end of message!
|
||||||
fun readTag(): Int {
|
fun readTag(expectedFieldNumber: Int, expectedWireType: WireType): Int {
|
||||||
if (isAtEnd()) {
|
if (isAtEnd()) {
|
||||||
return 0 // we can safely return 0 as sign of end of message, because 0-tags are illegal
|
return 0 // we can safely return 0 as sign of end of message, because 0-tags are illegal
|
||||||
}
|
}
|
||||||
@@ -262,6 +231,10 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
if (tag == 0) { // if we somehow had read 0-tag, then message is corrupted
|
if (tag == 0) { // if we somehow had read 0-tag, then message is corrupted
|
||||||
throw InvalidProtocolBufferException("Invalid tag 0")
|
throw InvalidProtocolBufferException("Invalid tag 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
||||||
|
val actualWireType = WireFormat.getTagWireType(tag)
|
||||||
|
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.LENGTH_DELIMITED, actualWireType)
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -151,6 +151,22 @@ class CodedOutputStream(val output: java.io.OutputStream) {
|
|||||||
output.write(value.toByteArray())
|
output.write(value.toByteArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun writeBytes(fieldNumber: Int, value: ByteArray?) {
|
||||||
|
value ?: return
|
||||||
|
writeTag(fieldNumber, WireType.LENGTH_DELIMITED)
|
||||||
|
writeBytesNoTag(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun writeBytesNoTag(value: ByteArray) {
|
||||||
|
writeInt32NoTag(value.size)
|
||||||
|
output.write(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ============ Utility methods ==================
|
||||||
|
* They are left non-private for cases when one wants to implement her/his own protocol format.
|
||||||
|
* Then she/he can re-use low-level methods for operating with raw values, that are not annotated with Protobuf tags.
|
||||||
|
*/
|
||||||
|
|
||||||
fun writeLittleEndian(value: Int?) {
|
fun writeLittleEndian(value: Int?) {
|
||||||
value ?: return
|
value ?: return
|
||||||
val bb = ByteBuffer.allocate(4)
|
val bb = ByteBuffer.allocate(4)
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
package Addressbook;
|
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? = null, id: Int? = null, email: kotlin.String? = null, phones: Array <PhoneNumber> = arrayOf()) {
|
|
||||||
var name : kotlin.String?
|
var name : kotlin.String?
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -10,7 +8,10 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
var email : kotlin.String?
|
var email : kotlin.String?
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var phones : Array <PhoneNumber>
|
var phones : MutableList <PhoneNumber>
|
||||||
|
private set
|
||||||
|
|
||||||
|
var someBytes : ByteArray?
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|
||||||
@@ -19,8 +20,8 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
this.id = id
|
this.id = id
|
||||||
this.email = email
|
this.email = email
|
||||||
this.phones = phones
|
this.phones = phones
|
||||||
|
this.someBytes = someBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class PhoneType(val ord: Int) {
|
enum class PhoneType(val ord: Int) {
|
||||||
MOBILE (0),
|
MOBILE (0),
|
||||||
HOME (1),
|
HOME (1),
|
||||||
@@ -37,7 +38,7 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class PhoneNumber private constructor (number: kotlin.String? = null, type: PhoneType? = null) {
|
class PhoneNumber private constructor (number: kotlin.String? = "", type: PhoneType? = PhoneType.fromIntToPhoneType(0)) {
|
||||||
var number : kotlin.String?
|
var number : kotlin.String?
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -50,19 +51,29 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
this.type = type
|
this.type = type
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeTo (output: CodedOutputStream) {
|
fun writeTo (output: CodedOutputStream): Unit {
|
||||||
writeToNoTag(output)
|
writeToNoTag(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeToNoTag (output: CodedOutputStream) {
|
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? = null, type: PhoneType? = null) {
|
class BuilderPhoneNumber constructor (number: kotlin.String? = "", type: PhoneType? = PhoneType.fromIntToPhoneType(0)) {
|
||||||
var number : kotlin.String?
|
var number : kotlin.String?
|
||||||
|
private set
|
||||||
|
fun setNumber(value: kotlin.String?): BuilderPhoneNumber {
|
||||||
|
number = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
var type : PhoneType?
|
var type : PhoneType?
|
||||||
|
private set
|
||||||
|
fun setType(value: PhoneType?): BuilderPhoneNumber {
|
||||||
|
type = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -70,13 +81,14 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
this.type = type
|
this.type = type
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom (input: CodedInputStream) {
|
fun readFrom (input: CodedInputStream): BuilderPhoneNumber {
|
||||||
readFromNoTag(input)
|
return readFromNoTag(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFromNoTag (input: CodedInputStream) {
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(): PhoneNumber {
|
fun build(): PhoneNumber {
|
||||||
@@ -91,30 +103,75 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun writeTo (output: CodedOutputStream) {
|
fun writeTo (output: CodedOutputStream): Unit {
|
||||||
writeToNoTag(output)
|
writeToNoTag(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeToNoTag (output: CodedOutputStream) {
|
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.writeInt32NoTag(phones.size)
|
||||||
output.writeInt32NoTag(phones.size)
|
output.writeInt32NoTag(phones.size)
|
||||||
for (item in phones) {
|
for (item in phones) {
|
||||||
|
output.writeTag(4, WireType.LENGTH_DELIMITED)
|
||||||
item.writeToNoTag(output)
|
item.writeToNoTag(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
output.writeBytes (5, someBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
class BuilderPerson constructor (name: kotlin.String? = null, id: Int? = null, email: kotlin.String? = null, phones: Array <PhoneNumber> = arrayOf()) {
|
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
|
||||||
|
fun setName(value: kotlin.String?): BuilderPerson {
|
||||||
|
name = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
var id : Int?
|
var id : Int?
|
||||||
|
private set
|
||||||
|
fun setId(value: Int?): BuilderPerson {
|
||||||
|
id = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
var email : kotlin.String?
|
var email : kotlin.String?
|
||||||
|
private set
|
||||||
|
fun setEmail(value: kotlin.String?): BuilderPerson {
|
||||||
|
email = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
var phones : Array <PhoneNumber>
|
var phones : MutableList <PhoneNumber>
|
||||||
|
private set
|
||||||
|
fun setPhones(value: MutableList <PhoneNumber> ): BuilderPerson {
|
||||||
|
phones = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun setPhoneNumber(index: Int, value: PhoneNumber): BuilderPerson {
|
||||||
|
phones[index] = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun addPhoneNumber(value: PhoneNumber): BuilderPerson {
|
||||||
|
phones.add(value)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun addAllPhoneNumber(value: Iterable<PhoneNumber>): BuilderPerson {
|
||||||
|
for (item in value) {
|
||||||
|
phones.add(item)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
var someBytes : ByteArray?
|
||||||
|
private set
|
||||||
|
fun setSomeBytes(value: ByteArray?): BuilderPerson {
|
||||||
|
someBytes = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -122,27 +179,30 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
this.id = id
|
this.id = id
|
||||||
this.email = email
|
this.email = email
|
||||||
this.phones = phones
|
this.phones = phones
|
||||||
|
this.someBytes = someBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom (input: CodedInputStream) {
|
fun readFrom (input: CodedInputStream): BuilderPerson {
|
||||||
readFromNoTag(input)
|
return readFromNoTag(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFromNoTag (input: CodedInputStream) {
|
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)
|
||||||
if (phones.size > 0) {
|
if (phones.size > 0) {
|
||||||
val tag = input.readTag()
|
val tag = input.readTag(4, WireType.LENGTH_DELIMITED)
|
||||||
val listSize = input.readInt32NoTag()
|
val listSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
for (i in 1..listSize) {
|
||||||
phones[i - 1].mergeFrom(input)
|
phones[i - 1].mergeFrom(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
someBytes = input.readBytes(5)
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(): Person {
|
fun build(): Person {
|
||||||
return Person(name, id, email, phones)
|
return Person(name, id, email, phones, someBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,18 +211,19 @@ class Person private constructor (name: kotlin.String? = null, id: Int? = null,
|
|||||||
id = input.readInt32(2)
|
id = input.readInt32(2)
|
||||||
email = input.readString(3)
|
email = input.readString(3)
|
||||||
if (phones.size > 0) {
|
if (phones.size > 0) {
|
||||||
val tag = input.readTag()
|
val tag = input.readTag(4, WireType.LENGTH_DELIMITED)
|
||||||
val listSize = input.readInt32NoTag()
|
val listSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
for (i in 1..listSize) {
|
||||||
phones[i - 1].mergeFrom(input)
|
phones[i - 1].mergeFrom(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
someBytes = input.readBytes(5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AddressBook private constructor (people: Array <Person> = arrayOf()) {
|
class AddressBook private constructor (people: MutableList <Person> = mutableListOf()) {
|
||||||
var people : Array <Person>
|
var people : MutableList <Person>
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|
||||||
@@ -170,39 +231,62 @@ class AddressBook private constructor (people: Array <Person> = arrayOf()) {
|
|||||||
this.people = people
|
this.people = people
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeTo (output: CodedOutputStream) {
|
fun writeTo (output: CodedOutputStream): Unit {
|
||||||
writeToNoTag(output)
|
writeToNoTag(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeToNoTag (output: CodedOutputStream) {
|
fun writeToNoTag (output: CodedOutputStream): Unit {
|
||||||
if (people.size > 0) {
|
if (people.size > 0) {
|
||||||
|
output.writeTag(1, WireType.LENGTH_DELIMITED)
|
||||||
|
output.writeInt32NoTag(people.size)
|
||||||
output.writeInt32NoTag(people.size)
|
output.writeInt32NoTag(people.size)
|
||||||
for (item in people) {
|
for (item in people) {
|
||||||
|
output.writeTag(1, WireType.LENGTH_DELIMITED)
|
||||||
item.writeToNoTag(output)
|
item.writeToNoTag(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BuilderAddressBook constructor (people: Array <Person> = arrayOf()) {
|
class BuilderAddressBook constructor (people: MutableList <Person> = mutableListOf()) {
|
||||||
var people : Array <Person>
|
var people : MutableList <Person>
|
||||||
|
private set
|
||||||
|
fun setPeople(value: MutableList <Person> ): BuilderAddressBook {
|
||||||
|
people = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun setPerson(index: Int, value: Person): BuilderAddressBook {
|
||||||
|
people[index] = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun addPerson(value: Person): BuilderAddressBook {
|
||||||
|
people.add(value)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun addAllPerson(value: Iterable<Person>): BuilderAddressBook {
|
||||||
|
for (item in value) {
|
||||||
|
people.add(item)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
this.people = people
|
this.people = people
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom (input: CodedInputStream) {
|
fun readFrom (input: CodedInputStream): BuilderAddressBook {
|
||||||
readFromNoTag(input)
|
return readFromNoTag(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFromNoTag (input: CodedInputStream) {
|
fun readFromNoTag (input: CodedInputStream): BuilderAddressBook {
|
||||||
if (people.size > 0) {
|
if (people.size > 0) {
|
||||||
val tag = input.readTag()
|
val tag = input.readTag(1, WireType.LENGTH_DELIMITED)
|
||||||
val listSize = input.readInt32NoTag()
|
val listSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
for (i in 1..listSize) {
|
||||||
people[i - 1].mergeFrom(input)
|
people[i - 1].mergeFrom(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(): AddressBook {
|
fun build(): AddressBook {
|
||||||
@@ -212,7 +296,7 @@ class AddressBook private constructor (people: Array <Person> = arrayOf()) {
|
|||||||
|
|
||||||
fun mergeFrom (input: CodedInputStream) {
|
fun mergeFrom (input: CodedInputStream) {
|
||||||
if (people.size > 0) {
|
if (people.size > 0) {
|
||||||
val tag = input.readTag()
|
val tag = input.readTag(1, WireType.LENGTH_DELIMITED)
|
||||||
val listSize = input.readInt32NoTag()
|
val listSize = input.readInt32NoTag()
|
||||||
for (i in 1..listSize) {
|
for (i in 1..listSize) {
|
||||||
people[i - 1].mergeFrom(input)
|
people[i - 1].mergeFrom(input)
|
||||||
|
|||||||
@@ -5,18 +5,40 @@ import java.io.ByteArrayOutputStream
|
|||||||
* Created by user on 7/8/16.
|
* Created by user on 7/8/16.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import PersonMessage
|
|
||||||
|
|
||||||
fun testMessageSerialization() {
|
fun testMessageSerialization() {
|
||||||
|
// Messages work only with CodedStream classes, provided by ProtoKot-runtime library.
|
||||||
|
// One can create CodedStream passing any instance of corresponding Stream from Java's library.
|
||||||
val s = ByteArrayOutputStream()
|
val s = ByteArrayOutputStream()
|
||||||
val outs = CodedOutputStream(s)
|
val outs = CodedOutputStream(s)
|
||||||
val msg =
|
|
||||||
|
// All messages are immutable. Use Builders for creating new messages
|
||||||
|
val msg = Person.BuilderPerson()
|
||||||
|
.setEmail("wtf@dasda.com") // all setters return this builder, so you could chain modifiers in LINQ-style
|
||||||
|
.setId(42)
|
||||||
|
.setName("John Doe")
|
||||||
|
.setPhones(arrayOf( // repeated fields stored as Array<>, so use arrayOf() for creating repeated fields
|
||||||
|
Person.PhoneNumber.BuilderPhoneNumber()
|
||||||
|
.setNumber("342143-23423-42")
|
||||||
|
.setType(Person.PhoneType.HOME)
|
||||||
|
.build()
|
||||||
|
))
|
||||||
|
.build() // don't forget to call build() to produce message
|
||||||
msg.writeTo(outs)
|
msg.writeTo(outs)
|
||||||
|
|
||||||
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
// Now let's use output stream as input to read our message from it!
|
||||||
val readMsg = Person("", 0, "", arrayOf())
|
var ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
|
|
||||||
|
// Create default instance of message
|
||||||
|
var readMsg = Person.BuilderPerson().build()
|
||||||
|
// Read in that message data from input stream.
|
||||||
readMsg.mergeFrom(ins)
|
readMsg.mergeFrom(ins)
|
||||||
|
|
||||||
|
// Note, that currently mergeFrom is the only way to mutate instance of message.
|
||||||
|
// Don't rely on it, probably mergeFrom will be refactored lately to guarantee full immutability of mesages.
|
||||||
|
|
||||||
|
// Better way to read a message:
|
||||||
|
ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
|
readMsg = Person.BuilderPerson().readFrom(ins).build()
|
||||||
assert(msg == readMsg)
|
assert(msg == readMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user