in thrift/compiler/generate/t_go_generator.cc [1391:1606]
void t_go_generator::generate_go_struct_definition(
ofstream& out,
const t_struct* tstruct,
bool is_exception,
bool is_result,
bool is_args) {
const vector<t_field*>& members = tstruct->get_members();
const vector<t_field*>& sorted_members = tstruct->get_sorted_members();
vector<t_field*>::const_iterator m_iter;
std::string tstruct_name(
publicize(tstruct->get_name(), is_args || is_result));
generate_go_docstring(out, tstruct);
out << indent() << "type " << tstruct_name << " struct {" << endl;
/*
Here we generate the structure specification for the fastbinary codec.
These specifications have the following structure:
thrift_spec -> tuple of item_spec
item_spec -> nil | (tag, type_enum, name, spec_args, default)
tag -> integer
type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ...
name -> string_literal
default -> nil # Handled by __init__
spec_args -> nil # For simple types
| (type_enum, spec_args) # Value type for list/set
| (type_enum, spec_args, type_enum, spec_args)
# Key and value for map
| (class_name, spec_args_ptr) # For struct/exception
class_name -> identifier # Basically a pointer to the class
spec_args_ptr -> expression # just class_name.spec_args
TODO(dreiss): Consider making this work for structs with negative tags.
*/
// TODO(dreiss): Look into generating an empty tuple instead of nil
// for structures with no members.
// TODO(dreiss): Test encoding of structs where some inner structs
// don't have thrift_spec.
indent_up();
if (is_args) {
out << indent() << "thrift.IRequest" << endl;
}
if (is_result) {
out << indent() << "thrift.IResponse" << endl;
}
int num_setable = 0;
if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) {
int sorted_keys_pos = 0;
for (m_iter = sorted_members.begin(); m_iter != sorted_members.end();
++m_iter) {
// Set field to optional if field is union, this is so we can get a
// pointer to the field.
if (tstruct->is_union())
(*m_iter)->set_req(t_field::e_req::optional);
if (sorted_keys_pos != (*m_iter)->get_key()) {
int first_unused = std::max(1, sorted_keys_pos++);
while (sorted_keys_pos != (*m_iter)->get_key()) {
++sorted_keys_pos;
}
int last_unused = sorted_keys_pos - 1;
if (first_unused < last_unused) {
indent(out) << "// unused fields # " << first_unused << " to "
<< last_unused << endl;
} else if (first_unused == last_unused) {
indent(out) << "// unused field # " << first_unused << endl;
}
}
const t_type* fieldType = (*m_iter)->get_type();
string goType =
type_to_go_type_with_opt(fieldType, is_pointer_field(*m_iter));
string gotag;
// Check for user override of db and json tags using "go.tag"
if (const auto* val = (*m_iter)->find_annotation_or_null("go.tag")) {
gotag = *val;
} else {
gotag = "db:\"" + escape_string((*m_iter)->get_name()) + "\" ";
if ((*m_iter)->get_req() == t_field::e_req::optional) {
gotag +=
"json:\"" + escape_string((*m_iter)->get_name()) + ",omitempty\"";
} else {
gotag += "json:\"" + escape_string((*m_iter)->get_name()) + "\"";
}
}
indent(out) << publicize((*m_iter)->get_name()) << " " << goType
<< " `thrift:\"" << escape_string((*m_iter)->get_name())
<< "," << sorted_keys_pos;
if ((*m_iter)->get_req() == t_field::e_req::required) {
out << ",required";
} else if (((*m_iter)->get_req() == t_field::e_req::optional)) {
out << ",optional";
}
out << "\" " << gotag << "`" << endl;
sorted_keys_pos++;
}
} else {
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
// This fills in default values, as opposed to nulls
out << indent() << publicize((*m_iter)->get_name()) << " "
<< type_to_go_type((*m_iter)->get_type()) << endl;
}
}
indent_down();
out << indent() << "}" << endl << endl;
out << indent() << "func New" << tstruct_name << "() *" << tstruct_name
<< " {" << endl;
indent_up();
out << indent() << "return &";
generate_go_struct_initializer(out, tstruct, is_result || is_args);
indent_down();
out << indent() << "}" << endl << endl;
// Default values for optional fields
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
string publicized_name;
const t_const_value* def_value;
get_publicized_name_and_def_value(*m_iter, &publicized_name, &def_value);
const t_type* fieldType = (*m_iter)->get_type();
string goType = type_to_go_type_with_opt(fieldType, false);
string def_var_name = tstruct_name + "_" + publicized_name + "_DEFAULT";
if ((*m_iter)->get_req() == t_field::e_req::optional ||
is_pointer_field(*m_iter)) {
out << indent() << "var " << def_var_name << " " << goType;
if (def_value != nullptr) {
out << " = "
<< render_const_value(fieldType, def_value, (*m_iter)->get_name());
}
out << endl;
}
if (is_pointer_field(*m_iter)) {
string goOptType = type_to_go_type_with_opt(fieldType, true);
string maybepointer = goOptType != goType ? "*" : "";
out << indent() << "func (p *" << tstruct_name << ") Get"
<< publicized_name << "() " << goType << " {" << endl;
out << indent() << " if !p.IsSet" << publicized_name << "() {" << endl;
out << indent() << " return " << def_var_name << endl;
out << indent() << " }" << endl;
out << indent() << "return " << maybepointer << "p." << publicized_name
<< endl;
out << indent() << "}" << endl;
num_setable += 1;
} else {
out << endl;
out << indent() << "func (p *" << tstruct_name << ") Get"
<< publicized_name << "() " << goType << " {" << endl;
out << indent() << " return p." << publicized_name << endl;
out << indent() << "}" << endl;
}
}
if (tstruct->is_union() && num_setable > 0) {
generate_countsetfields_helper(out, tstruct, tstruct_name, is_result);
}
generate_isset_helpers(out, tstruct, tstruct_name, is_result);
generate_go_struct_builder(out, tstruct, tstruct_name, is_result);
generate_go_struct_setters(out, tstruct, tstruct_name, is_result);
generate_go_struct_reader(out, tstruct, tstruct_name, is_result);
generate_go_struct_writer(
out, tstruct, tstruct_name, is_result, num_setable > 0);
out << indent() << "func (p *" << tstruct_name << ") String() string {"
<< endl;
out << indent() << " if p == nil {" << endl;
out << indent() << " return \"<nil>\"" << endl;
out << indent() << " }" << endl << endl;
std::vector<std::string> format;
string values;
for (m_iter = sorted_members.begin(); m_iter != sorted_members.end();
++m_iter) {
if (is_pointer_field(*m_iter)) {
out << indent() << " var " << privatize((*m_iter)->get_name())
<< "Val string" << endl;
out << indent() << " if p." << publicize((*m_iter)->get_name())
<< " == nil {" << endl;
out << indent() << " " << privatize((*m_iter)->get_name())
<< "Val = \"<nil>\"" << endl;
out << indent() << " } else {" << endl;
if (type_need_reference((*m_iter)->get_type())) {
out << indent() << " " << privatize((*m_iter)->get_name())
<< "Val = fmt.Sprintf(\"%v\", *p."
<< publicize((*m_iter)->get_name()) << ")" << endl;
} else {
out << indent() << " " << privatize((*m_iter)->get_name())
<< "Val = fmt.Sprintf(\"%v\", p."
<< publicize((*m_iter)->get_name()) << ")" << endl;
}
out << indent() << " }" << endl;
} else {
out << indent() << " " << privatize((*m_iter)->get_name())
<< "Val := fmt.Sprintf(\"%v\", p." << publicize((*m_iter)->get_name())
<< ")" << endl;
}
format.push_back(publicize((*m_iter)->get_name()) + ":%s");
values = values + ", " + privatize((*m_iter)->get_name()) + "Val";
}
out << indent() << " return fmt.Sprintf(\"" << escape_string(tstruct_name)
<< "({" << boost::algorithm::join(format, " ") << "})\"" << values << ")"
<< endl;
out << indent() << "}" << endl << endl;
if (is_exception) {
out << indent() << "func (p *" << tstruct_name << ") Error() string {"
<< endl;
out << indent() << " return p.String()" << endl;
out << indent() << "}" << endl << endl;
}
}