Protobuf: refactored FieldGenerator interface heavily. Now it offers much more clearier interface for names getting (separating simple names from full-qualified names)

This commit is contained in:
dsavvinov
2016-07-20 15:33:11 +03:00
parent 5d58ddd8bb
commit bee4c839d2
12 changed files with 322 additions and 233 deletions
@@ -23,9 +23,14 @@ $(BINDIR):
mkdir -p $(BINDIR) mkdir -p $(BINDIR)
clean: clean:
rm -rf $(BINDIR) $(EXE) rm -rf $(BINDIR)
generate: generate:
./protoc --kotlin_out=$$HOME/Downloads/carkot/proto/compiler/src ./test/addressbook.proto ./protoc --kotlin_out=$$HOME/Downloads/carkot/proto/compiler/src ./test/addressbook.proto
./protoc --kotlin_out=$$HOME/Downloads/carkot/proto/compiler/src ./test/nested-msg.proto ./protoc --kotlin_out=$$HOME/Downloads/carkot/proto/compiler/src ./test/nested-msg.proto
.PHONY: clean all generate
debug:
gdb --args ./protoc --kotlin_out=$$HOME/Downloads/carkot/proto/compiler/src ./test/addressbook.proto
gdb --args ./protoc --kotlin_out=$$HOME/Downloads/carkot/proto/compiler/src ./test/nested-msg.proto
.PHONY: clean all generate debug
Binary file not shown.
@@ -0,0 +1,19 @@
//
// Created by user on 7/20/16.
//
#include "UnreachableStateException.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace kotlin {
UnreachableStateException::UnreachableStateException(std::string const & what)
: std::logic_error(what)
{ }
} // namespace kotlin
} // namespace compiler
} // namespace protobuf
} // namespace google
@@ -0,0 +1,28 @@
//
// Created by user on 7/20/16.
//
#ifndef GOOGLE_UNREACHABLESTATEEXCEPTION_H
#define GOOGLE_UNREACHABLESTATEEXCEPTION_H
#include <exception>
#include <stdexcept>
namespace google {
namespace protobuf {
namespace compiler {
namespace kotlin {
class UnreachableStateException : public std::logic_error {
public:
UnreachableStateException(std::string const & what);
};
} // namespace kotlin
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif //GOOGLE_UNREACHABLESTATEEXCEPTION_H
@@ -80,8 +80,6 @@ ClassGenerator::ClassGenerator(Descriptor const *descriptor, NameResolver * name
: descriptor(descriptor) : descriptor(descriptor)
, nameResolver(nameResolver) , nameResolver(nameResolver)
{ {
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) {
FieldDescriptor const * fieldDescriptor = descriptor->field(i); FieldDescriptor const * fieldDescriptor = descriptor->field(i);
@@ -91,14 +89,14 @@ ClassGenerator::ClassGenerator(Descriptor const *descriptor, NameResolver * name
int nested_types_count = descriptor->nested_type_count(); int nested_types_count = descriptor->nested_type_count();
for (int i = 0; i < nested_types_count; ++i) { for (int i = 0; i < nested_types_count; ++i) {
Descriptor const * nestedClassDescriptor = descriptor->nested_type(i); Descriptor const * nestedClassDescriptor = descriptor->nested_type(i);
nameResolver->addClass(nestedClassDescriptor->name(), nameResolver->getClassName(simpleName)); nameResolver->addClass(nestedClassDescriptor->name(), getFullType());
classesDeclarations.push_back(new ClassGenerator(nestedClassDescriptor, nameResolver)); classesDeclarations.push_back(new ClassGenerator(nestedClassDescriptor, nameResolver));
} }
int enums_declarations_count = descriptor->enum_type_count(); int enums_declarations_count = descriptor->enum_type_count();
for (int i = 0; i < enums_declarations_count; ++i) { for (int i = 0; i < enums_declarations_count; ++i) {
EnumDescriptor const * nestedEnumDescriptor = descriptor->enum_type(i); EnumDescriptor const * nestedEnumDescriptor = descriptor->enum_type(i);
nameResolver->addClass(nestedEnumDescriptor->name(), nameResolver->getClassName(simpleName)); nameResolver->addClass(nestedEnumDescriptor->name(), getFullType());
enumsDeclaraions.push_back(new EnumGenerator(nestedEnumDescriptor)); enumsDeclaraions.push_back(new EnumGenerator(nestedEnumDescriptor));
} }
@@ -109,7 +107,7 @@ ClassGenerator::ClassGenerator(Descriptor const *descriptor, NameResolver * name
*/ */
std::sort(properties.begin(), properties.end(), std::sort(properties.begin(), properties.end(),
[](FieldGenerator const * first, FieldGenerator const * second) { [](FieldGenerator const * first, FieldGenerator const * second) {
return first->fieldNumber < second->fieldNumber; return first->getFieldNumber() < second->getFieldNumber();
}); });
} }
@@ -137,7 +135,7 @@ void ClassGenerator::generateMergeMethods(io::Printer *printer) const {
// mergeWith(other: Message) // mergeWith(other: Message)
printer->Print("\n"); printer->Print("\n");
vars["className"] = simpleName; vars["className"] = getFullType();
printer->Print(vars, "fun mergeWith (other: $className$) {\n"); printer->Print(vars, "fun mergeWith (other: $className$) {\n");
printer->Indent(); printer->Indent();
@@ -145,12 +143,12 @@ void ClassGenerator::generateMergeMethods(io::Printer *printer) const {
vars["fieldName"] = properties[i]->simpleName; vars["fieldName"] = properties[i]->simpleName;
// concatenate repeated fields // concatenate repeated fields
if (properties[i]->modifier == FieldDescriptor::LABEL_REPEATED) { if (properties[i]->getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
printer->Print(vars, "$fieldName$.addAll(other.$fieldName$)\n"); printer->Print(vars, "$fieldName$.addAll(other.$fieldName$)\n");
} }
// Bytes type is handled separately // Bytes type is handled separately
else if (properties[i]->protoType == FieldDescriptor::TYPE_BYTES) { else if (properties[i]->getProtoType() == FieldDescriptor::TYPE_BYTES) {
vars["initValue"] = properties[i]->getInitValue(); vars["initValue"] = properties[i]->getInitValue();
printer->Print(vars, "$fieldName$.plus(other.$fieldName$)\n"); printer->Print(vars, "$fieldName$.plus(other.$fieldName$)\n");
} }
@@ -170,7 +168,7 @@ void ClassGenerator::generateMergeMethods(io::Printer *printer) const {
printer->Print(vars, "fun mergeFrom (input: CodedInputStream) {\n"); printer->Print(vars, "fun mergeFrom (input: CodedInputStream) {\n");
printer->Indent(); printer->Indent();
vars["builderName"] = nameResolver->getBuilderName(simpleName); vars["builderName"] = getBuilderFullType();
printer->Print(vars, "val builder = $builderName$()\n"); printer->Print(vars, "val builder = $builderName$()\n");
printer->Print("mergeWith(builder.parseFrom(input).build())"); printer->Print("mergeWith(builder.parseFrom(input).build())");
@@ -184,7 +182,7 @@ void ClassGenerator::generateSerializers(io::Printer *printer, bool isRead) cons
vars["funName"]= isRead ? "readFrom" : "writeTo"; vars["funName"]= isRead ? "readFrom" : "writeTo";
vars["stream"] = isRead ? "CodedInputStream" : "CodedOutputStream"; vars["stream"] = isRead ? "CodedInputStream" : "CodedOutputStream";
vars["arg"] = isRead ? "input" : "output"; vars["arg"] = isRead ? "input" : "output";
vars["returnType"] = isRead ? nameResolver->getBuilderName(simpleName) : "Unit"; vars["returnType"] = isRead ? getBuilderFullType() : "Unit";
vars["maybeReturn"] = isRead ? "return this\n" : ""; vars["maybeReturn"] = isRead ? "return this\n" : "";
// generate function header // generate function header
@@ -209,14 +207,14 @@ void ClassGenerator::generateHeader(io::Printer * printer, bool isBuilder) const
// build list of arguments like 'field1: Type1, field2: Type2, ... ' // build list of arguments like 'field1: Type1, field2: Type2, ... '
string argumentList = ""; string argumentList = "";
for (int i = 0; i < properties.size(); ++i) { for (int i = 0; i < properties.size(); ++i) {
argumentList += properties[i]->simpleName + ": " + properties[i]->fullType + " = " + properties[i]->getInitValue(); argumentList += properties[i]->simpleName + ": " + properties[i]->getFullType() + " = " + properties[i]->getInitValue();
if (i + 1 != properties.size()) { if (i + 1 != properties.size()) {
argumentList += ", "; argumentList += ", ";
} }
} }
map<string, string> vars; map<string, string> vars;
vars["name"] = isBuilder? "Builder" + simpleName : simpleName; vars["name"] = isBuilder? getBuidlerSimpleType() : getSimpleType();
vars["argumentList"] = argumentList; vars["argumentList"] = argumentList;
vars["maybePrivate"] = isBuilder? "" : " private"; vars["maybePrivate"] = isBuilder? "" : " private";
printer->Print(vars, printer->Print(vars,
@@ -227,7 +225,7 @@ void ClassGenerator::generateHeader(io::Printer * printer, bool isBuilder) const
void ClassGenerator::generateBuildMethod(io::Printer * printer) const { void ClassGenerator::generateBuildMethod(io::Printer * printer) const {
map <string, string> vars; map <string, string> vars;
vars["returnType"] = simpleName; vars["returnType"] = getFullType();
printer->Print(vars, printer->Print(vars,
"fun build(): $returnType$ {\n"); "fun build(): $returnType$ {\n");
printer->Indent(); printer->Indent();
@@ -266,7 +264,7 @@ void ClassGenerator::generateInitSection(io::Printer * printer) const {
void ClassGenerator::generateParseMethods(io::Printer *printer) const { void ClassGenerator::generateParseMethods(io::Printer *printer) const {
// parseFieldFrom(input: CodedInputStream): Boolean // parseFieldFrom(input: CodedInputStream): Boolean
map <string, string> vars; map <string, string> vars;
vars["builderName"] = nameResolver->getBuilderName(simpleName); vars["builderName"] = getBuilderFullType();
printer->Print("fun parseFieldFrom(input: CodedInputStream): Boolean {\n"); printer->Print("fun parseFieldFrom(input: CodedInputStream): Boolean {\n");
printer->Indent(); printer->Indent();
@@ -287,21 +285,21 @@ void ClassGenerator::generateParseMethods(io::Printer *printer) const {
printer->Indent(); printer->Indent();
for (int i = 0; i < properties.size(); ++i) { for (int i = 0; i < properties.size(); ++i) {
vars["fieldNumber"] = std::to_string(properties[i]->fieldNumber); vars["fieldNumber"] = std::to_string(properties[i]->getFieldNumber());
vars["kotlinFunSuffix"] = properties[i]->getKotlinFunctionSuffix(); vars["kotlinFunSuffix"] = properties[i]->getKotlinFunctionSuffix();
printer->Print(vars, "$fieldNumber$ -> "); printer->Print(vars, "$fieldNumber$ -> ");
// code for serialization arrays and messages consists of more than one line and needs enclosing brackets // code for serialization arrays and messages consists of more than one line and needs enclosing brackets
if (properties[i]->modifier == FieldDescriptor::LABEL_REPEATED if (properties[i]->getProtoLabel() == FieldDescriptor::LABEL_REPEATED
|| properties[i]->protoType == FieldDescriptor::TYPE_MESSAGE) { || properties[i]->getProtoType() == FieldDescriptor::TYPE_MESSAGE) {
printer->Print("{\n"); printer->Print("{\n");
printer->Indent(); printer->Indent();
} }
properties[i]->generateSerializationCode(printer, /* isRead = */ true, /* noTag = */ true); properties[i]->generateSerializationCode(printer, /* isRead = */ true, /* noTag = */ true);
if (properties[i]->modifier == FieldDescriptor::LABEL_REPEATED if (properties[i]->getProtoLabel() == FieldDescriptor::LABEL_REPEATED
|| properties[i]->protoType == FieldDescriptor::TYPE_MESSAGE) { || properties[i]->getProtoType() == FieldDescriptor::TYPE_MESSAGE) {
printer->Outdent(); printer->Outdent();
printer->Print("}\n"); printer->Print("}\n");
} }
@@ -339,36 +337,20 @@ void ClassGenerator::generateGetSizeMethod(io::Printer *printer) const {
printer->Print("}\n"); printer->Print("}\n");
} }
string ClassGenerator::getSimpleType() const {
return descriptor->name();
//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 {
string result = "";
switch (type) {
case CLASS:
result = "class";
break;
case INTERFACE:
result = "interface";
break;
}
return result;
} }
ClassModifier::ClassModifier(ClassModifier::Type type) string ClassGenerator::getFullType() const {
: type(type) return nameResolver->getClassName(getSimpleType());
{ } }
ClassModifier::ClassModifier() { string ClassGenerator::getBuilderFullType() const {
type = CLASS; return nameResolver->getBuilderName(getSimpleType());
}
string ClassGenerator::getBuidlerSimpleType() const {
return "Builder" + getSimpleType();
} }
@@ -20,24 +20,13 @@ namespace kotlin {
class FieldGenerator; // declared in "kotlin_file_generator.h" class FieldGenerator; // declared in "kotlin_file_generator.h"
class NameResolver; // declared in "kotlin_name_resolver.h" class NameResolver; // declared in "kotlin_name_resolver.h"
// wrapper for enum CLASS/INTERFACE with convenience method of getting name
class ClassModifier {
public:
enum Type {
CLASS,
INTERFACE
};
ClassModifier();
ClassModifier(Type type);
Type type;
string const getName() const;
};
class ClassGenerator { class ClassGenerator {
public: public:
string simpleName; string getSimpleType() const;
string fullName; string getFullType() const;
string getBuidlerSimpleType() const;
string getBuilderFullType() const;
vector <FieldGenerator *> properties; vector <FieldGenerator *> properties;
vector <ClassGenerator *> classesDeclarations; vector <ClassGenerator *> classesDeclarations;
vector <EnumGenerator *> enumsDeclaraions; vector <EnumGenerator *> enumsDeclaraions;
@@ -7,6 +7,7 @@
#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 "kotlin_name_resolver.h"
#include "UnreachableStateException.h"
#include <iostream> #include <iostream>
namespace google { namespace google {
@@ -15,13 +16,22 @@ namespace compiler {
namespace kotlin { namespace kotlin {
string FieldGenerator::getInitValue() const { string FieldGenerator::getInitValue() const {
return name_resolving::protobufTypeToInitValue(this); if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
return "mutableListOf()";
}
if (getProtoType() == FieldDescriptor::TYPE_MESSAGE) {
return getBuilderFullType() + "().build()";
}
if (getProtoType() == FieldDescriptor::TYPE_ENUM) {
return getEnumFromIntConverter() + "(0)";
}
return name_resolving::protobufTypeToInitValue(getProtoType());
} }
void FieldGenerator::generateCode(io::Printer *printer, bool isBuilder) const { void FieldGenerator::generateCode(io::Printer *printer, bool isBuilder) const {
map<string, string> vars; map<string, string> vars;
vars["name"] = simpleName; vars["name"] = simpleName;
vars["field"] = name_resolving::protobufToKotlinField(descriptor); vars["field"] = getFullType();
printer->Print(vars, "var $name$ : $field$\n"); printer->Print(vars, "var $name$ : $field$\n");
// make setter private // make setter private
@@ -35,29 +45,25 @@ void FieldGenerator::generateCode(io::Printer *printer, bool isBuilder) const {
} }
// generate additional methods for repeated fields // generate additional methods for repeated fields
if (modifier == FieldDescriptor::LABEL_REPEATED) { if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
generateRepeatedMethods(printer, isBuilder); generateRepeatedMethods(printer, isBuilder);
} }
} }
FieldGenerator::FieldGenerator(FieldDescriptor const * descriptor, ClassGenerator const * enclosingClass, NameResolver * nameResolver) FieldGenerator::FieldGenerator(FieldDescriptor const * descriptor, ClassGenerator const * enclosingClass, NameResolver * nameResolver)
: descriptor(descriptor) : descriptor(descriptor)
, modifier(descriptor->label())
, enclosingClass(enclosingClass) , enclosingClass(enclosingClass)
, simpleName(descriptor->name())
, underlyingType(name_resolving::protobufToKotlinType(descriptor))
, fullType(name_resolving::protobufToKotlinField(descriptor))
, protoType(descriptor->type())
, fieldNumber(descriptor->number())
, nameResolver(nameResolver) , nameResolver(nameResolver)
, simpleName(descriptor->name())
, protoLabel(descriptor->label())
{ } { }
// TODO: long, complicated and messy method. Refactor it ASAP // TODO: long, complicated and messy method. Refactor it ASAP
void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead, bool noTag) const { void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead, bool noTag) const {
map <string, string> vars; map <string, string> vars;
vars["type"] = name_resolving::protobufTypeToKotlinFunctionSuffix(descriptor->type()) + (noTag ? "NoTag" : ""); vars["type"] = getKotlinFunctionSuffix() + (noTag ? "NoTag" : "");
vars["fieldNumber"] = std::to_string(fieldNumber); vars["fieldNumber"] = std::to_string(getFieldNumber());
vars["maybeFieldNumber"] = noTag ? "" : std::to_string(fieldNumber); vars["maybeFieldNumber"] = noTag ? "" : std::to_string(getFieldNumber());
vars["fieldName"] = simpleName; vars["fieldName"] = simpleName;
vars["arg"] = isRead ? "input" : "output"; vars["arg"] = isRead ? "input" : "output";
vars["maybeComma"] = ", "; vars["maybeComma"] = ", ";
@@ -70,7 +76,7 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
* - Write length as int32 (note that tag shouldn't be added) * - Write length as int32 (note that tag shouldn't be added)
* - Write all repeated elements via recursive call (again, without tags) * - Write all repeated elements via recursive call (again, without tags)
*/ */
if (modifier == FieldDescriptor::LABEL_REPEATED) { if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
// tag // tag
if (isRead) { if (isRead) {
if (!noTag) { if (!noTag) {
@@ -90,7 +96,7 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
removed as soon as target code will support inheritance and interfaces. removed as soon as target code will support inheritance and interfaces.
(then writing CodedOutputStream.writeMessage will be possible). (then writing CodedOutputStream.writeMessage will be possible).
*/ */
FieldGenerator singleFieldGen = FieldGenerator(descriptor, enclosingClass, nameResolver); FieldGenerator singleFieldGen = getUnderlyingTypeGenerator();
/* 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.
@@ -99,11 +105,11 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
to ArrayOutOfIndex errors. to ArrayOutOfIndex errors.
*/ */
// TODO: stub here, resolve name properly! // TODO: stub here, resolve name properly!
vars["fieldType"] = underlyingType + ".Builder" + underlyingType; vars["builderType"] = getUnderlyingTypeGenerator().getFullType();
vars["initValue"] = underlyingType + ".Builder" + underlyingType + "()"; vars["initValue"] = getUnderlyingTypeGenerator().getInitValue();
printer->Print(vars, "val tmp: $fieldType$ = $initValue$\n"); printer->Print(vars, "val tmp: $builderType$ = $initValue$\n");
singleFieldGen.simpleName = "tmp"; singleFieldGen.simpleName = "tmp";
singleFieldGen.modifier = FieldDescriptor::LABEL_OPTIONAL; singleFieldGen.protoLabel = FieldDescriptor::LABEL_OPTIONAL;
// Note that primitive types are packed by default in proto3, i.e. they are should be written without tag // 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 && bool isPrimitive = descriptor->type() != FieldDescriptor::TYPE_BYTES &&
@@ -112,9 +118,9 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
descriptor->type() != FieldDescriptor::TYPE_ENUM; descriptor->type() != FieldDescriptor::TYPE_ENUM;
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ isPrimitive); singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ isPrimitive);
singleFieldGen.generateSizeEstimationCode(printer, "readSize"); // add size of current element to total size singleFieldGen.generateSizeEstimationCode(printer, /* varName = */ "readSize"); // add size of current element to total size
printer->Print(vars, "$fieldName$.add(tmp.build())\n"); printer->Print(vars, "$fieldName$.add(tmp)\n");
printer->Outdent(); printer->Outdent();
printer->Print("}\n"); printer->Print("}\n");
@@ -138,7 +144,7 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
// hack: see above // hack: see above
FieldGenerator singleFieldGen = FieldGenerator(descriptor, enclosingClass, nameResolver); FieldGenerator singleFieldGen = FieldGenerator(descriptor, enclosingClass, nameResolver);
singleFieldGen.simpleName = "item"; singleFieldGen.simpleName = "item";
singleFieldGen.modifier = FieldDescriptor::LABEL_OPTIONAL; singleFieldGen.protoLabel = FieldDescriptor::LABEL_OPTIONAL;
// TODO: maybe refactor this in name_resolving or separate method at least // 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 // Note that primitive types are packed by default in proto3, i.e. they are should be written without tag
@@ -167,7 +173,7 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
Example: output.writeEnum(42, enumField.ord) Example: output.writeEnum(42, enumField.ord)
*/ */
if (descriptor->type() == FieldDescriptor::TYPE_ENUM) { if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
vars["converter"] = underlyingType + ".fromIntTo" + underlyingType; vars["converter"] = getEnumFromIntConverter();
if (isRead) { if (isRead) {
printer->Print(vars, "$fieldName$ = $converter$(input.read$type$($maybeFieldNumber$))\n"); printer->Print(vars, "$fieldName$ = $converter$(input.read$type$($maybeFieldNumber$))\n");
} }
@@ -185,7 +191,7 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
*/ */
if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) { if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
if (isRead) { if (isRead) {
vars["fieldNumber"] = std::to_string(fieldNumber); vars["fieldNumber"] = std::to_string(getFieldNumber());
vars["dollar"] = "$"; vars["dollar"] = "$";
// read tag // read tag
@@ -205,7 +211,7 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
"\") }\n"); "\") }\n");
} }
else { else {
vars["fieldNumber"] = std::to_string(fieldNumber); vars["fieldNumber"] = std::to_string(getFieldNumber());
// write tag // write tag
printer->Print(vars, "output.writeTag($fieldNumber$, WireType.LENGTH_DELIMITED)\n"); printer->Print(vars, "output.writeTag($fieldNumber$, WireType.LENGTH_DELIMITED)\n");
@@ -233,8 +239,8 @@ void FieldGenerator::generateSetter(io::Printer *printer) const {
map <string, string> vars; map <string, string> vars;
vars["camelCaseName"] = name_resolving::makeFirstLetterUpper(simpleName); vars["camelCaseName"] = name_resolving::makeFirstLetterUpper(simpleName);
vars["fieldName"] = simpleName; vars["fieldName"] = simpleName;
vars["builderName"] = nameResolver->getBuilderName(enclosingClass->simpleName); vars["builderName"] = enclosingClass->getBuilderFullType();
vars["type"] = fullType; vars["type"] = getFullType();
printer->Print(vars, printer->Print(vars,
"fun set$camelCaseName$(value: $type$): $builderName$ {\n"); "fun set$camelCaseName$(value: $type$): $builderName$ {\n");
printer->Indent(); printer->Indent();
@@ -247,10 +253,10 @@ void FieldGenerator::generateSetter(io::Printer *printer) const {
void FieldGenerator::generateRepeatedMethods(io::Printer * printer, bool isBuilder) const { void FieldGenerator::generateRepeatedMethods(io::Printer * printer, bool isBuilder) const {
map <string, string> vars; map <string, string> vars;
vars["elementType"] = underlyingType; vars["elementType"] = getUnderlyingTypeGenerator().getSimpleType();
vars["arg"] = "value"; vars["arg"] = "value";
vars["fieldName"] = simpleName; vars["fieldName"] = simpleName;
vars["builderName"] = nameResolver->getBuilderName(underlyingType); // TODO: call to non-existent field in map. vars["builderName"] = enclosingClass->getBuilderFullType(); // TODO: call to non-existent field in map.
// generate indexed setter for builders // generate indexed setter for builders
if (isBuilder) { if (isBuilder) {
@@ -292,21 +298,14 @@ string FieldGenerator::getKotlinFunctionSuffix() const {
return name_resolving::protobufTypeToKotlinFunctionSuffix(descriptor->type()); return name_resolving::protobufTypeToKotlinFunctionSuffix(descriptor->type());
} }
string FieldGenerator::getUnderlyingTypeInitValue() const {
if (protoType == FieldDescriptor::TYPE_MESSAGE) {
return "Builder" + underlyingType + "().build()";
}
return name_resolving::protobufTypeToInitValue(this);
}
void FieldGenerator::generateSizeEstimationCode(io::Printer *printer, string varName, bool noTag) const { void FieldGenerator::generateSizeEstimationCode(io::Printer *printer, string varName, bool noTag) const {
map<string, string> vars; map<string, string> vars;
vars["varName"] = varName; vars["varName"] = varName;
vars["fieldName"] = simpleName; vars["fieldName"] = simpleName;
vars["fieldNumber"] = std::to_string(fieldNumber); vars["fieldNumber"] = std::to_string(getFieldNumber());
// First of all, generate code for repeated fields // First of all, generate code for repeated fields
if (modifier == FieldDescriptor::LABEL_REPEATED) { if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
// We will need total byte size of array, because that size is itself a part of the message and // We will need total byte size of array, because that size is itself a part of the message and
// adds to total message size. // adds to total message size.
// For the sake of hygiene, temporary variables are created in anonymous scope // For the sake of hygiene, temporary variables are created in anonymous scope
@@ -322,7 +321,7 @@ void FieldGenerator::generateSizeEstimationCode(io::Printer *printer, string var
// hack: reuse generateSizeEstimationCode in the same manner as in generateSerializationCode // hack: reuse generateSizeEstimationCode in the same manner as in generateSerializationCode
FieldGenerator singleFieldGen = FieldGenerator(descriptor, enclosingClass, nameResolver); FieldGenerator singleFieldGen = FieldGenerator(descriptor, enclosingClass, nameResolver);
singleFieldGen.modifier = FieldDescriptor::LABEL_OPTIONAL; singleFieldGen.protoLabel = FieldDescriptor::LABEL_OPTIONAL;
singleFieldGen.simpleName = "item"; singleFieldGen.simpleName = "item";
singleFieldGen.generateSizeEstimationCode(printer, "arraySize"); singleFieldGen.generateSizeEstimationCode(printer, "arraySize");
@@ -348,7 +347,7 @@ void FieldGenerator::generateSizeEstimationCode(io::Printer *printer, string var
// Then, call getSize recursively for nested messages // Then, call getSize recursively for nested messages
// TODO: currently suboptimal repeatative calls getSize() are being made. We can optimize it later via caching calls to getSize() // TODO: currently suboptimal repeatative calls getSize() are being made. We can optimize it later via caching calls to getSize()
if (protoType == FieldDescriptor::TYPE_MESSAGE) { if (getProtoType() == FieldDescriptor::TYPE_MESSAGE) {
// don't forget about tag and length annotation // don't forget about tag and length annotation
printer->Print(vars, "$varName$ += $fieldName$.getSize()" printer->Print(vars, "$varName$ += $fieldName$.getSize()"
" + " " + "
@@ -360,18 +359,82 @@ void FieldGenerator::generateSizeEstimationCode(io::Printer *printer, string var
} }
// Next, process enums as they should be casted to ints manually // Next, process enums as they should be casted to ints manually
if (protoType == FieldDescriptor::TYPE_ENUM) { if (getProtoType() == FieldDescriptor::TYPE_ENUM) {
vars["enumName"] = fullType;
printer->Print(vars, "$varName$ += WireFormat.getEnumSize($fieldNumber$, $fieldName$.ord)\n"); printer->Print(vars, "$varName$ += WireFormat.getEnumSize($fieldNumber$, $fieldName$.ord)\n");
return; return;
} }
// Finally, get size of all primitive types trivially via call to WireFormat in runtime // Finally, get size of all primitive types trivially via call to WireFormat in runtime
vars["kotlinSuffix"] = name_resolving::protobufTypeToKotlinFunctionSuffix(descriptor->type()); vars["kotlinSuffix"] = getKotlinFunctionSuffix();
printer->Print(vars, "$varName$ += WireFormat.get$kotlinSuffix$Size($fieldNumber$, $fieldName$)\n"); printer->Print(vars, "$varName$ += WireFormat.get$kotlinSuffix$Size($fieldNumber$, $fieldName$)\n");
return; return;
} }
FieldDescriptor::Label FieldGenerator::getProtoLabel() const {
return protoLabel;
}
FieldDescriptor::Type FieldGenerator::getProtoType() const {
return descriptor->type();
}
int FieldGenerator::getFieldNumber() const {
return descriptor->number();
}
string FieldGenerator::getSimpleType() const {
if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
return "MutableList <" + getUnderlyingTypeGenerator().getSimpleType() + ">";
}
if (getProtoType() == FieldDescriptor::TYPE_MESSAGE) {
return descriptor->message_type()->name();
}
if (getProtoType() == FieldDescriptor::TYPE_ENUM) {
return descriptor->enum_type()->name();
}
return name_resolving::protobufToKotlinType(descriptor->type());
}
string FieldGenerator::getFullType() const {
if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
return "MutableList <" + getUnderlyingTypeGenerator().getFullType() + ">";
}
if (getProtoType() == FieldDescriptor::TYPE_MESSAGE ||
getProtoType() == FieldDescriptor::TYPE_ENUM) {
return nameResolver->getClassName(getSimpleType());
}
return name_resolving::protobufToKotlinType(getProtoType());
}
string FieldGenerator::getBuilderFullType() const {
if (getProtoType() != FieldDescriptor::TYPE_MESSAGE) {
throw UnreachableStateException("Error: trying to get builder name for non-message field " + simpleName);
}
return nameResolver->getBuilderName(getSimpleType());
}
string FieldGenerator::getBuilderSimpleType() const {
if (getProtoType() != FieldDescriptor::TYPE_MESSAGE) {
throw UnreachableStateException("Error: trying to get builder name for non-message field " + simpleName);
}
return "Builder" + getSimpleType();
}
string FieldGenerator::getEnumFromIntConverter() const {
return getFullType() + ".fromIntTo" + getSimpleType();
}
FieldGenerator FieldGenerator::getUnderlyingTypeGenerator() const {
if (getProtoLabel() == FieldDescriptor::LABEL_REPEATED) {
FieldGenerator singleFieldGen = FieldGenerator(descriptor, enclosingClass, nameResolver);
singleFieldGen.protoLabel = FieldDescriptor::LABEL_OPTIONAL;
return singleFieldGen;
}
return *this;
}
} // namespace kotlin } // namespace kotlin
} // namespace compiler } // namespace compiler
} // namespace protobuf } // namespace protobuf
@@ -27,32 +27,58 @@ private:
void generateSetter(io::Printer * printer) const; void generateSetter(io::Printer * printer) const;
void generateRepeatedMethods(io::Printer * printer, bool isBuilder) const; void generateRepeatedMethods(io::Printer * printer, bool isBuilder) const;
public: public:
FieldDescriptor::Label modifier;
ClassGenerator const * enclosingClass; // class, in which that field is defined ClassGenerator const * enclosingClass; // class, in which that field is defined
string simpleName;
string underlyingType; // unwrapped type.
/**
* Full type of field.
* fullType = Array<underlyingType> for REPEATED fields
* fullType = underlyingType? for OPTIONAL fields
* fullType = underlyingType for all other cases
*/
string fullType;
string builderName;
string fullName;
string getInitValue() const;
string getUnderlyingTypeInitValue() const;
FieldDescriptor::Type protoType;
int fieldNumber;
NameResolver * nameResolver; NameResolver * nameResolver;
string simpleName;
FieldDescriptor::Label protoLabel; // TODO: hack here - this field is used for some dark magic that allows us to drop generics from the generated code
FieldDescriptor::Label getProtoLabel() const;
FieldDescriptor::Type getProtoType() const;
/* Return declared tag number */
int getFieldNumber() const;
/* Returns instance of FieldGenerator, that generated underlying type for repeated fields.
* For non-repeated fields, returns `this` */
FieldGenerator getUnderlyingTypeGenerator() const;
/* For repeated fields, returns simple name of single element.
* For all other cases, returns simple name of field, which is the same as getType()
*/
/* For repeated fields, return simple name of single element, wrapped into corresponding Kotlin array type
* Example: Array<NestedMessage>
* For other types, return simple name (without full-qualification for non-primitive types) of field's type
*/
string getSimpleType() const;
string getBuilderSimpleType() const;
/* Returns full=qualified name of builder if field type is user-defined message */
string getBuilderFullType() const;
/* Returns the same as getType(), but with full-qualification for non-primitive types if necessary.
* Example: Array<EnclosingMessage.NestedMessage>
*/
string getFullType() const;
/* Returns initial value of this field's type.
* Note that full qualification for non-primitive types will always used here.
*/
string getInitValue() const;
/* Return string, that is suitable as suffix for corresponding IO methods in ProtoKot runtime.
* Example: int64-field -> Int64 (readInt64() and writeInt64() methods exist in ProtoKot runtime)
*/
string getKotlinFunctionSuffix() const;
/* Return function name in enum namespace that converts from enum to Int */
string getEnumFromIntConverter() const;
void generateCode(io::Printer * printer, bool isBuilder) const; void generateCode(io::Printer * printer, bool isBuilder) const;
void generateSerializationCode(io::Printer * printer, bool isRead = false, bool noTag = false) const; void generateSerializationCode(io::Printer * printer, bool isRead = false, bool noTag = false) const;
void generateSizeEstimationCode(io::Printer * printer, string varName, bool noTag = false) const; void generateSizeEstimationCode(io::Printer * printer, string varName, bool noTag = false) const;
FieldGenerator(FieldDescriptor const * descriptor, ClassGenerator const * enclosingClass, NameResolver * nameResolver); FieldGenerator(FieldDescriptor const * descriptor, ClassGenerator const * enclosingClass, NameResolver * nameResolver);
string getKotlinFunctionSuffix() const;
}; };
} // namespace kotlin } // namespace kotlin
@@ -5,7 +5,7 @@
#include "kotlin_name_resolver.h" #include "kotlin_name_resolver.h"
#include "kotlin_field_generator.h" #include "kotlin_field_generator.h"
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
#include "UnreachableStateException.h"
#include <string> #include <string>
namespace google { namespace google {
@@ -33,8 +33,7 @@ string getKotlinOutputByProtoName(string protoName) {
return justName + ".kt"; return justName + ".kt";
} }
string protobufToKotlinType(FieldDescriptor const * descriptor) { string protobufToKotlinType(FieldDescriptor::Type type) {
FieldDescriptor::Type type = descriptor->type();
switch(type) { switch(type) {
case FieldDescriptor::TYPE_BOOL: case FieldDescriptor::TYPE_BOOL:
return "Boolean"; return "Boolean";
@@ -43,7 +42,8 @@ string protobufToKotlinType(FieldDescriptor const * descriptor) {
case FieldDescriptor::TYPE_DOUBLE: case FieldDescriptor::TYPE_DOUBLE:
return "Double"; return "Double";
case FieldDescriptor::TYPE_ENUM: case FieldDescriptor::TYPE_ENUM:
return string(descriptor->enum_type()->name()); throw UnreachableStateException
("Error: mapping protobuf enum types to kotlin types should be resolved by field generator, not by protobufToKotlinType function");
case FieldDescriptor::TYPE_FIXED32: case FieldDescriptor::TYPE_FIXED32:
// we map uint32 into Int, storing top bit in sign bit // we map uint32 into Int, storing top bit in sign bit
return "Int"; return "Int";
@@ -57,7 +57,8 @@ string protobufToKotlinType(FieldDescriptor const * descriptor) {
case FieldDescriptor::TYPE_INT64: case FieldDescriptor::TYPE_INT64:
return "Long"; return "Long";
case FieldDescriptor::TYPE_MESSAGE: case FieldDescriptor::TYPE_MESSAGE:
return string(descriptor->message_type()->name()); throw UnreachableStateException
("Error: mapping protobuf message types to kotlin types should be resolved by field generator, not by protobufToKotlinType function");
case FieldDescriptor::TYPE_SFIXED32: case FieldDescriptor::TYPE_SFIXED32:
return "Int"; return "Int";
case FieldDescriptor::TYPE_SFIXED64: case FieldDescriptor::TYPE_SFIXED64:
@@ -67,7 +68,7 @@ string protobufToKotlinType(FieldDescriptor const * descriptor) {
case FieldDescriptor::TYPE_SINT64: case FieldDescriptor::TYPE_SINT64:
return "Long"; return "Long";
case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_STRING:
return "kotlin.String"; return "String";
case FieldDescriptor::TYPE_UINT32: case FieldDescriptor::TYPE_UINT32:
return "Int"; // see notes for TYPE_FIXED32 return "Int"; // see notes for TYPE_FIXED32
case FieldDescriptor::TYPE_UINT64: case FieldDescriptor::TYPE_UINT64:
@@ -75,30 +76,9 @@ string protobufToKotlinType(FieldDescriptor const * descriptor) {
} }
} }
string protobufToKotlinField(FieldDescriptor const * descriptor) {
FieldDescriptor::Label modifier = descriptor->label();
string preamble = "",
postamble = "";
switch (modifier) {
case FieldDescriptor::LABEL_REQUIRED:
break;
case FieldDescriptor::LABEL_OPTIONAL:
break;
case FieldDescriptor::LABEL_REPEATED:
preamble = "MutableList <";
postamble = "> ";
break;
}
return preamble + protobufToKotlinType(descriptor) + postamble;
}
// TODO: think about nested arrays // TODO: think about nested arrays
string protobufTypeToInitValue(FieldGenerator const * fieldGen) { string protobufTypeToInitValue(FieldDescriptor::Type type) {
if (fieldGen->modifier == FieldDescriptor::LABEL_REPEATED) {
return "mutableListOf()";
}
FieldDescriptor::Type type = fieldGen->protoType;
switch(type) { switch(type) {
case FieldDescriptor::TYPE_BOOL: case FieldDescriptor::TYPE_BOOL:
return "false"; return "false";
@@ -106,9 +86,8 @@ string protobufTypeToInitValue(FieldGenerator const * fieldGen) {
return "ByteArray(0)"; return "ByteArray(0)";
case FieldDescriptor::TYPE_DOUBLE: case FieldDescriptor::TYPE_DOUBLE:
return "0.0"; return "0.0";
case FieldDescriptor::TYPE_ENUM: { case FieldDescriptor::TYPE_ENUM:
return fieldGen->nameResolver->getClassName(fieldGen->fullType) + ".fromIntTo" + fieldGen->fullType + "(0)"; // produce enum from 0, as demanded by Google throw UnreachableStateException("Error: getting init values of enums should be handled by FieldGenerator, not by protobufToInitValue");
}
case FieldDescriptor::TYPE_FIXED32: case FieldDescriptor::TYPE_FIXED32:
return "0"; return "0";
case FieldDescriptor::TYPE_FIXED64: case FieldDescriptor::TYPE_FIXED64:
@@ -120,7 +99,7 @@ string protobufTypeToInitValue(FieldGenerator const * fieldGen) {
case FieldDescriptor::TYPE_INT64: case FieldDescriptor::TYPE_INT64:
return "0L"; return "0L";
case FieldDescriptor::TYPE_MESSAGE: case FieldDescriptor::TYPE_MESSAGE:
return fieldGen->nameResolver->getBuilderName(fieldGen->fullType) + "().build()"; throw UnreachableStateException("Error: getting init values of enums should be handled by FieldGenerator, not by protobufToInitValue");
case FieldDescriptor::TYPE_SFIXED32: case FieldDescriptor::TYPE_SFIXED32:
return "0"; return "0";
case FieldDescriptor::TYPE_SFIXED64: case FieldDescriptor::TYPE_SFIXED64:
@@ -37,11 +37,9 @@ std::string getFileNameWithoutExtension(std::string fullName);
std::string getKotlinOutputByProtoName(std::string protoName); std::string getKotlinOutputByProtoName(std::string protoName);
std::string protobufTypeToInitValue(FieldGenerator const * fieldGenerator); std::string protobufTypeToInitValue(FieldDescriptor::Type type);
std::string protobufToKotlinField(FieldDescriptor const * descriptor); std::string protobufToKotlinType(FieldDescriptor::Type type);
std::string protobufToKotlinType(FieldDescriptor const * descriptor);
/** /**
* Converts one of protobuf wire types to corresponding Kotlin type with proper * Converts one of protobuf wire types to corresponding Kotlin type with proper
+43 -43
View File
@@ -1,14 +1,14 @@
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: String = "", id: Int = 0, email: String = "", phones: MutableList <Person.PhoneNumber> = mutableListOf(), someBytes: ByteArray = ByteArray(0)) {
var name : kotlin.String var name : String
private set private set
var id : Int var id : Int
private set private set
var email : kotlin.String var email : String
private set private set
var phones : MutableList <PhoneNumber> var phones : MutableList <Person.PhoneNumber>
private set private set
var someBytes : ByteArray var someBytes : ByteArray
@@ -38,11 +38,11 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
} }
} }
} }
class PhoneNumber private constructor (number: kotlin.String = "", type: PhoneType = Person.PhoneType.fromIntToPhoneType(0)) { class PhoneNumber private constructor (number: String = "", type: Person.PhoneType = Person.PhoneType.fromIntToPhoneType(0)) {
var number : kotlin.String var number : String
private set private set
var type : PhoneType var type : Person.PhoneType
private set private set
@@ -56,17 +56,17 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
output.writeEnum (2, type.ord) output.writeEnum (2, type.ord)
} }
class BuilderPhoneNumber constructor (number: kotlin.String = "", type: PhoneType = Person.PhoneType.fromIntToPhoneType(0)) { class BuilderPhoneNumber constructor (number: String = "", type: Person.PhoneType = Person.PhoneType.fromIntToPhoneType(0)) {
var number : kotlin.String var number : String
private set private set
fun setNumber(value: kotlin.String): Person.PhoneNumber.BuilderPhoneNumber { fun setNumber(value: String): Person.PhoneNumber.BuilderPhoneNumber {
number = value number = value
return this return this
} }
var type : PhoneType var type : Person.PhoneType
private set private set
fun setType(value: PhoneType): Person.PhoneNumber.BuilderPhoneNumber { fun setType(value: Person.PhoneType): Person.PhoneNumber.BuilderPhoneNumber {
type = value type = value
return this return this
} }
@@ -79,12 +79,12 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
fun readFrom (input: CodedInputStream): Person.PhoneNumber.BuilderPhoneNumber { fun readFrom (input: CodedInputStream): Person.PhoneNumber.BuilderPhoneNumber {
number = input.readString(1) number = input.readString(1)
type = PhoneType.fromIntToPhoneType(input.readEnum(2)) type = Person.PhoneType.fromIntToPhoneType(input.readEnum(2))
return this return this
} }
fun build(): PhoneNumber { fun build(): Person.PhoneNumber {
return PhoneNumber(number, type) return Person.PhoneNumber(number, type)
} }
fun parseFieldFrom(input: CodedInputStream): Boolean { fun parseFieldFrom(input: CodedInputStream): Boolean {
@@ -95,7 +95,7 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
val wireType = WireFormat.getTagWireType(tag) val wireType = WireFormat.getTagWireType(tag)
when(fieldNumber) { when(fieldNumber) {
1 -> number = input.readStringNoTag() 1 -> number = input.readStringNoTag()
2 -> type = PhoneType.fromIntToPhoneType(input.readEnumNoTag()) 2 -> type = Person.PhoneType.fromIntToPhoneType(input.readEnumNoTag())
} }
return true} return true}
fun parseFrom(input: CodedInputStream): Person.PhoneNumber.BuilderPhoneNumber { fun parseFrom(input: CodedInputStream): Person.PhoneNumber.BuilderPhoneNumber {
@@ -111,7 +111,7 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
} }
fun mergeWith (other: PhoneNumber) { fun mergeWith (other: Person.PhoneNumber) {
number = other.number number = other.number
type = other.type type = other.type
} }
@@ -152,10 +152,10 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
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: String = "", id: Int = 0, email: String = "", phones: MutableList <Person.PhoneNumber> = mutableListOf(), someBytes: ByteArray = ByteArray(0)) {
var name : kotlin.String var name : String
private set private set
fun setName(value: kotlin.String): Person.BuilderPerson { fun setName(value: String): Person.BuilderPerson {
name = value name = value
return this return this
} }
@@ -167,28 +167,28 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
return this return this
} }
var email : kotlin.String var email : String
private set private set
fun setEmail(value: kotlin.String): Person.BuilderPerson { fun setEmail(value: String): Person.BuilderPerson {
email = value email = value
return this return this
} }
var phones : MutableList <PhoneNumber> var phones : MutableList <Person.PhoneNumber>
private set private set
fun setPhones(value: MutableList <PhoneNumber> ): Person.BuilderPerson { fun setPhones(value: MutableList <Person.PhoneNumber>): Person.BuilderPerson {
phones = value phones = value
return this return this
} }
fun setPhoneNumber(index: Int, value: PhoneNumber): Person.PhoneNumber.BuilderPhoneNumber { fun setPhoneNumber(index: Int, value: PhoneNumber): Person.BuilderPerson {
phones[index] = value phones[index] = value
return this return this
} }
fun addPhoneNumber(value: PhoneNumber): Person.PhoneNumber.BuilderPhoneNumber { fun addPhoneNumber(value: PhoneNumber): Person.BuilderPerson {
phones.add(value) phones.add(value)
return this return this
} }
fun addAllPhoneNumber(value: Iterable<PhoneNumber>): Person.PhoneNumber.BuilderPhoneNumber { fun addAllPhoneNumber(value: Iterable<PhoneNumber>): Person.BuilderPerson {
for (item in value) { for (item in value) {
phones.add(item) phones.add(item)
} }
@@ -219,13 +219,13 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
val expectedSize = input.readInt32NoTag() val expectedSize = input.readInt32NoTag()
var readSize = 0 var readSize = 0
while(readSize != expectedSize) { while(readSize != expectedSize) {
val tmp: PhoneNumber.BuilderPhoneNumber = PhoneNumber.BuilderPhoneNumber() val tmp: Person.PhoneNumber = Person.PhoneNumber.BuilderPhoneNumber().build()
input.readTag(4, WireType.LENGTH_DELIMITED) input.readTag(4, WireType.LENGTH_DELIMITED)
val expectedSize = input.readInt32NoTag() val expectedSize = input.readInt32NoTag()
tmp.mergeFrom(input) tmp.mergeFrom(input)
if (expectedSize != tmp.getSize()) { throw InvalidProtocolBufferException ("Expected size ${expectedSize} got ${tmp.getSize()}") } 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()) readSize += tmp.getSize() + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(tmp.getSize())
phones.add(tmp.build()) phones.add(tmp)
} }
someBytes = input.readBytes(5) someBytes = input.readBytes(5)
return this return this
@@ -249,13 +249,13 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
val expectedSize = input.readInt32NoTag() val expectedSize = input.readInt32NoTag()
var readSize = 0 var readSize = 0
while(readSize != expectedSize) { while(readSize != expectedSize) {
val tmp: PhoneNumber.BuilderPhoneNumber = PhoneNumber.BuilderPhoneNumber() val tmp: Person.PhoneNumber = Person.PhoneNumber.BuilderPhoneNumber().build()
input.readTag(4, WireType.LENGTH_DELIMITED) input.readTag(4, WireType.LENGTH_DELIMITED)
val expectedSize = input.readInt32NoTag() val expectedSize = input.readInt32NoTag()
tmp.mergeFrom(input) tmp.mergeFrom(input)
if (expectedSize != tmp.getSize()) { throw InvalidProtocolBufferException ("Expected size ${expectedSize} got ${tmp.getSize()}") } 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()) readSize += tmp.getSize() + WireFormat.getTagSize(4, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(tmp.getSize())
phones.add(tmp.build()) phones.add(tmp)
} }
} }
5 -> someBytes = input.readBytesNoTag() 5 -> someBytes = input.readBytesNoTag()
@@ -312,8 +312,8 @@ class Person private constructor (name: kotlin.String = "", id: Int = 0, email:
} }
class AddressBook private constructor (people: MutableList <Person> = mutableListOf()) { class AddressBook private constructor (people: MutableList <Person> = mutableListOf()) {
var people : MutableList <Person> var people : MutableList <Person>
private set private set
@@ -341,22 +341,22 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
} }
} }
class BuilderAddressBook constructor (people: MutableList <Person> = mutableListOf()) { class BuilderAddressBook constructor (people: MutableList <Person> = mutableListOf()) {
var people : MutableList <Person> var people : MutableList <Person>
private set private set
fun setPeople(value: MutableList <Person> ): AddressBook.BuilderAddressBook { fun setPeople(value: MutableList <Person>): AddressBook.BuilderAddressBook {
people = value people = value
return this return this
} }
fun setPerson(index: Int, value: Person): Person.BuilderPerson { fun setPerson(index: Int, value: Person): AddressBook.BuilderAddressBook {
people[index] = value people[index] = value
return this return this
} }
fun addPerson(value: Person): Person.BuilderPerson { fun addPerson(value: Person): AddressBook.BuilderAddressBook {
people.add(value) people.add(value)
return this return this
} }
fun addAllPerson(value: Iterable<Person>): Person.BuilderPerson { fun addAllPerson(value: Iterable<Person>): AddressBook.BuilderAddressBook {
for (item in value) { for (item in value) {
people.add(item) people.add(item)
} }
@@ -373,13 +373,13 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
val expectedSize = input.readInt32NoTag() val expectedSize = input.readInt32NoTag()
var readSize = 0 var readSize = 0
while(readSize != expectedSize) { while(readSize != expectedSize) {
val tmp: Person.BuilderPerson = Person.BuilderPerson() val tmp: Person = Person.BuilderPerson().build()
input.readTag(1, WireType.LENGTH_DELIMITED) input.readTag(1, WireType.LENGTH_DELIMITED)
val expectedSize = input.readInt32NoTag() val expectedSize = input.readInt32NoTag()
tmp.mergeFrom(input) tmp.mergeFrom(input)
if (expectedSize != tmp.getSize()) { throw InvalidProtocolBufferException ("Expected size ${expectedSize} got ${tmp.getSize()}") } 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()) readSize += tmp.getSize() + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(tmp.getSize())
people.add(tmp.build()) people.add(tmp)
} }
return this return this
} }
@@ -399,13 +399,13 @@ class AddressBook private constructor (people: MutableList <Person> = mutableLi
val expectedSize = input.readInt32NoTag() val expectedSize = input.readInt32NoTag()
var readSize = 0 var readSize = 0
while(readSize != expectedSize) { while(readSize != expectedSize) {
val tmp: Person.BuilderPerson = Person.BuilderPerson() val tmp: Person = Person.BuilderPerson().build()
input.readTag(1, WireType.LENGTH_DELIMITED) input.readTag(1, WireType.LENGTH_DELIMITED)
val expectedSize = input.readInt32NoTag() val expectedSize = input.readInt32NoTag()
tmp.mergeFrom(input) tmp.mergeFrom(input)
if (expectedSize != tmp.getSize()) { throw InvalidProtocolBufferException ("Expected size ${expectedSize} got ${tmp.getSize()}") } 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()) readSize += tmp.getSize() + WireFormat.getTagSize(1, WireType.LENGTH_DELIMITED) + WireFormat.getVarint32Size(tmp.getSize())
people.add(tmp.build()) people.add(tmp)
} }
} }
} }
+29 -29
View File
@@ -1,29 +1,29 @@
class Level1 private constructor (field1: Level2 = Level1.Level2.BuilderLevel2().build()) { class Level1 private constructor (field1: Level1.Level2 = Level1.Level2.BuilderLevel2().build()) {
var field1 : Level2 var field1 : Level1.Level2
private set private set
init { init {
this.field1 = field1 this.field1 = field1
} }
class Level2 private constructor (field2: Level3 = Level1.Level2.Level3.BuilderLevel3().build()) { class Level2 private constructor (field2: Level1.Level2.Level3 = Level1.Level2.Level3.BuilderLevel3().build()) {
var field2 : Level3 var field2 : Level1.Level2.Level3
private set private set
init { init {
this.field2 = field2 this.field2 = field2
} }
class Level3 private constructor (field3: Level4 = Level1.Level2.Level3.Level4.BuilderLevel4().build()) { class Level3 private constructor (field3: Level1.Level2.Level3.Level4 = Level1.Level2.Level3.Level4.BuilderLevel4().build()) {
var field3 : Level4 var field3 : Level1.Level2.Level3.Level4
private set private set
init { init {
this.field3 = field3 this.field3 = field3
} }
class Level4 private constructor (field4: kotlin.String = "") { class Level4 private constructor (field4: String = "") {
var field4 : kotlin.String var field4 : String
private set private set
@@ -35,10 +35,10 @@ class Level1 private constructor (field1: Level2 = Level1.Level2.BuilderLevel2()
output.writeString (4, field4) output.writeString (4, field4)
} }
class BuilderLevel4 constructor (field4: kotlin.String = "") { class BuilderLevel4 constructor (field4: String = "") {
var field4 : kotlin.String var field4 : String
private set private set
fun setField4(value: kotlin.String): Level1.Level2.Level3.Level4.BuilderLevel4 { fun setField4(value: String): Level1.Level2.Level3.Level4.BuilderLevel4 {
field4 = value field4 = value
return this return this
} }
@@ -53,8 +53,8 @@ class Level1 private constructor (field1: Level2 = Level1.Level2.BuilderLevel2()
return this return this
} }
fun build(): Level4 { fun build(): Level1.Level2.Level3.Level4 {
return Level4(field4) return Level1.Level2.Level3.Level4(field4)
} }
fun parseFieldFrom(input: CodedInputStream): Boolean { fun parseFieldFrom(input: CodedInputStream): Boolean {
@@ -79,7 +79,7 @@ class Level1 private constructor (field1: Level2 = Level1.Level2.BuilderLevel2()
} }
fun mergeWith (other: Level4) { fun mergeWith (other: Level1.Level2.Level3.Level4) {
field4 = other.field4 field4 = other.field4
} }
@@ -100,10 +100,10 @@ class Level1 private constructor (field1: Level2 = Level1.Level2.BuilderLevel2()
field3.writeTo(output) field3.writeTo(output)
} }
class BuilderLevel3 constructor (field3: Level4 = Level1.Level2.Level3.Level4.BuilderLevel4().build()) { class BuilderLevel3 constructor (field3: Level1.Level2.Level3.Level4 = Level1.Level2.Level3.Level4.BuilderLevel4().build()) {
var field3 : Level4 var field3 : Level1.Level2.Level3.Level4
private set private set
fun setField3(value: Level4): Level1.Level2.Level3.BuilderLevel3 { fun setField3(value: Level1.Level2.Level3.Level4): Level1.Level2.Level3.BuilderLevel3 {
field3 = value field3 = value
return this return this
} }
@@ -121,8 +121,8 @@ class Level1 private constructor (field1: Level2 = Level1.Level2.BuilderLevel2()
return this return this
} }
fun build(): Level3 { fun build(): Level1.Level2.Level3 {
return Level3(field3) return Level1.Level2.Level3(field3)
} }
fun parseFieldFrom(input: CodedInputStream): Boolean { fun parseFieldFrom(input: CodedInputStream): Boolean {
@@ -152,7 +152,7 @@ class Level1 private constructor (field1: Level2 = Level1.Level2.BuilderLevel2()
} }
fun mergeWith (other: Level3) { fun mergeWith (other: Level1.Level2.Level3) {
field3 = other.field3 field3 = other.field3
} }
@@ -173,10 +173,10 @@ class Level1 private constructor (field1: Level2 = Level1.Level2.BuilderLevel2()
field2.writeTo(output) field2.writeTo(output)
} }
class BuilderLevel2 constructor (field2: Level3 = Level1.Level2.Level3.BuilderLevel3().build()) { class BuilderLevel2 constructor (field2: Level1.Level2.Level3 = Level1.Level2.Level3.BuilderLevel3().build()) {
var field2 : Level3 var field2 : Level1.Level2.Level3
private set private set
fun setField2(value: Level3): Level1.Level2.BuilderLevel2 { fun setField2(value: Level1.Level2.Level3): Level1.Level2.BuilderLevel2 {
field2 = value field2 = value
return this return this
} }
@@ -194,8 +194,8 @@ class Level1 private constructor (field1: Level2 = Level1.Level2.BuilderLevel2()
return this return this
} }
fun build(): Level2 { fun build(): Level1.Level2 {
return Level2(field2) return Level1.Level2(field2)
} }
fun parseFieldFrom(input: CodedInputStream): Boolean { fun parseFieldFrom(input: CodedInputStream): Boolean {
@@ -225,7 +225,7 @@ class Level1 private constructor (field1: Level2 = Level1.Level2.BuilderLevel2()
} }
fun mergeWith (other: Level2) { fun mergeWith (other: Level1.Level2) {
field2 = other.field2 field2 = other.field2
} }
@@ -246,10 +246,10 @@ class Level1 private constructor (field1: Level2 = Level1.Level2.BuilderLevel2()
field1.writeTo(output) field1.writeTo(output)
} }
class BuilderLevel1 constructor (field1: Level2 = Level1.Level2.BuilderLevel2().build()) { class BuilderLevel1 constructor (field1: Level1.Level2 = Level1.Level2.BuilderLevel2().build()) {
var field1 : Level2 var field1 : Level1.Level2
private set private set
fun setField1(value: Level2): Level1.BuilderLevel1 { fun setField1(value: Level1.Level2): Level1.BuilderLevel1 {
field1 = value field1 = value
return this return this
} }