Skip to content

Commit

Permalink
Go optional scalars (#7104)
Browse files Browse the repository at this point in the history
* [go] always write required types

* support optional scalars in go

* generate optional_scalars and monster_test

* restore original behavior for non-optional scalars

* add tests
  • Loading branch information
chriscraws authored Feb 16, 2022
1 parent 57e338f commit 06f4af1
Show file tree
Hide file tree
Showing 6 changed files with 1,140 additions and 19 deletions.
64 changes: 50 additions & 14 deletions src/idl_gen_go.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,16 @@ class GoGenerator : public BaseGenerator {
GenReceiver(struct_def, code_ptr);
code += " " + MakeCamel(field.name);
code += "() " + TypeName(field) + " ";
code += OffsetPrefix(field) + "\t\treturn ";
code += OffsetPrefix(field);
if (field.IsScalarOptional()) {
code += "\t\tv := ";
} else {
code += "\t\treturn ";
}
code += CastToEnum(field.value.type, getter + "(o + rcv._tab.Pos)");
if (field.IsScalarOptional()) {
code += "\n\t\treturn &v";
}
code += "\n\t}\n";
code += "\treturn " + GenConstant(field) + "\n";
code += "}\n\n";
Expand Down Expand Up @@ -571,21 +579,31 @@ class GoGenerator : public BaseGenerator {
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
code += "flatbuffers.UOffsetT";
} else {
code += TypeName(field);
code += GenTypeGet(field.value.type);
}
code += ") {\n\t";
code += "builder.Prepend";
code += GenMethod(field);
if (field.IsScalarOptional()) {
code += "(";
} else {
code += "Slot(" + NumToString(offset) + ", ";
}
code += ") {\n";
code += "\tbuilder.Prepend";
code += GenMethod(field) + "Slot(";
code += NumToString(offset) + ", ";
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
code += "flatbuffers.UOffsetT";
code += "(";
code += GoIdentity(field.name) + ")";
} else {
code += CastToBaseType(field.value.type, GoIdentity(field.name));
}
code += ", " + GenConstant(field);
code += ")\n}\n";
if (field.IsScalarOptional()) {
code += ")\n";
code += "\tbuilder.Slot(" + NumToString(offset);
} else {
code += ", " + GenConstant(field);
}
code += ")\n";
code += "}\n";
}

// Set the value of one of the members of a table's vector.
Expand Down Expand Up @@ -669,7 +687,7 @@ class GoGenerator : public BaseGenerator {
std::string setter = "rcv._tab.Mutate" + type;
GenReceiver(struct_def, code_ptr);
code += " Mutate" + MakeCamel(field.name);
code += "(n " + TypeName(field) + ") bool {\n\treturn " + setter;
code += "(n " + GenTypeGet(field.value.type) + ") bool {\n\treturn " + setter;
code += "(rcv._tab.Pos+flatbuffers.UOffsetT(";
code += NumToString(field.value.offset) + "), ";
code += CastToBaseType(field.value.type, "n") + ")\n}\n\n";
Expand All @@ -683,7 +701,7 @@ class GoGenerator : public BaseGenerator {
std::string setter = "rcv._tab.Mutate" + type + "Slot";
GenReceiver(struct_def, code_ptr);
code += " Mutate" + MakeCamel(field.name);
code += "(n " + TypeName(field) + ") bool {\n\treturn ";
code += "(n " + GenTypeGet(field.value.type) + ") bool {\n\treturn ";
code += setter + "(" + NumToString(field.value.offset) + ", ";
code += CastToBaseType(field.value.type, "n") + ")\n";
code += "}\n\n";
Expand Down Expand Up @@ -801,8 +819,11 @@ class GoGenerator : public BaseGenerator {
field.value.type.enum_def != nullptr &&
field.value.type.enum_def->is_union)
continue;
code += "\t" + MakeCamel(field.name) + " " +
NativeType(field.value.type) + "\n";
code += "\t" + MakeCamel(field.name) + " ";
if (field.IsScalarOptional()) {
code += "*";
}
code += NativeType(field.value.type) + "\n";
}
code += "}\n\n";

Expand Down Expand Up @@ -953,10 +974,18 @@ class GoGenerator : public BaseGenerator {

std::string offset = MakeCamel(field.name, false) + "Offset";
if (IsScalar(field.value.type.base_type)) {
std::string prefix;
if (field.IsScalarOptional()) {
code += "\tif t." + MakeCamel(field.name) + " != nil {\n\t";
prefix = "*";
}
if (field.value.type.enum_def == nullptr ||
!field.value.type.enum_def->is_union) {
code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) +
"(builder, t." + MakeCamel(field.name) + ")\n";
"(builder, " + prefix + "t." + MakeCamel(field.name) + ")\n";
}
if (field.IsScalarOptional()) {
code += "\t}\n";
}
} else {
if (field.value.type.base_type == BASE_TYPE_STRUCT &&
Expand Down Expand Up @@ -1192,7 +1221,11 @@ class GoGenerator : public BaseGenerator {
}

std::string TypeName(const FieldDef &field) {
return GenTypeGet(field.value.type);
std::string prefix;
if (field.IsScalarOptional()) {
prefix = "*";
}
return prefix + GenTypeGet(field.value.type);
}

// If type is an enum, returns value with a cast to the enum type, otherwise
Expand All @@ -1216,6 +1249,9 @@ class GoGenerator : public BaseGenerator {
}

std::string GenConstant(const FieldDef &field) {
if (field.IsScalarOptional()) {
return "nil";
}
switch (field.value.type.base_type) {
case BASE_TYPE_BOOL:
return field.value.constant == "0" ? "false" : "true";
Expand Down
3 changes: 2 additions & 1 deletion src/idl_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2479,7 +2479,8 @@ bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions &opts) {
static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster |
IDLOptions::kKotlin | IDLOptions::kCpp | IDLOptions::kJava |
IDLOptions::kCSharp | IDLOptions::kTs | IDLOptions::kBinary;
IDLOptions::kCSharp | IDLOptions::kTs | IDLOptions::kBinary |
IDLOptions::kGo;
unsigned long langs = opts.lang_to_generate;
return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs);
}
Expand Down
6 changes: 4 additions & 2 deletions tests/GoTest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ test_dir="$(pwd)"
go_path=${test_dir}/go_gen
go_src=${go_path}/src

# Emit Go code for the example schema in the test dir:
../flatc -g --gen-object-api -I include_test monster_test.fbs
# Emit Go code for the example schemas in the test dir:
../flatc -g --gen-object-api -I include_test monster_test.fbs optional_scalars.fbs

# Go requires a particular layout of files in order to link multiple packages.
# Copy flatbuffer Go files to their own package directories to compile the
Expand All @@ -29,6 +29,7 @@ mkdir -p ${go_src}/MyGame/Example
mkdir -p ${go_src}/MyGame/Example2
mkdir -p ${go_src}/github.com/google/flatbuffers/go
mkdir -p ${go_src}/flatbuffers_test
mkdir -p ${go_src}/optional_scalars

cp -a MyGame/*.go ./go_gen/src/MyGame/
cp -a MyGame/Example/*.go ./go_gen/src/MyGame/Example/
Expand All @@ -38,6 +39,7 @@ cp -a MyGame/Example2/*.go ./go_gen/src/MyGame/Example2/
rm ./go_gen/src/MyGame/Example/*_grpc.go
cp -a ../go/* ./go_gen/src/github.com/google/flatbuffers/go
cp -a ./go_test.go ./go_gen/src/flatbuffers_test/
cp -a optional_scalars/*.go ./go_gen/src/optional_scalars

# Run tests with necessary flags.
# Developers may wish to see more detail by appending the verbosity flag
Expand Down
Loading

0 comments on commit 06f4af1

Please sign in to comment.