You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by je...@apache.org on 2015/02/03 23:41:25 UTC

thrift git commit: THRIFT-2189 add union support for go generator Client: Go Patch: Anton Lindström and Jens Geyer

Repository: thrift
Updated Branches:
  refs/heads/master 2663ec43a -> b3654df14


THRIFT-2189 add union support for go generator
Client: Go
Patch: Anton Lindström <li...@gmail.com> and Jens Geyer

This closes #369

This makes it possible to check if a field  is set and skips adding new ones.
Fields in unions are pointers by setting them as `t_field::T_OPTIONAL`.

To be sure that exactly one and only one field is set in a union, we count the
number of fields set and return an error if not exactly one field is set.

This is a breaking change and will require fields in unions to be passed in as
pointers.


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/b3654df1
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/b3654df1
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/b3654df1

Branch: refs/heads/master
Commit: b3654df14cd4b391943eeab8124735a005fa7454
Parents: 2663ec4
Author: Jens Geyer <je...@apache.org>
Authored: Tue Feb 3 22:54:26 2015 +0100
Committer: Jens Geyer <je...@apache.org>
Committed: Tue Feb 3 23:40:02 2015 +0100

----------------------------------------------------------------------
 compiler/cpp/src/generate/t_go_generator.cc | 69 ++++++++++++++++++++++--
 1 file changed, 66 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/b3654df1/compiler/cpp/src/generate/t_go_generator.cc
----------------------------------------------------------------------
diff --git a/compiler/cpp/src/generate/t_go_generator.cc b/compiler/cpp/src/generate/t_go_generator.cc
index c09b8a3..2bae622 100644
--- a/compiler/cpp/src/generate/t_go_generator.cc
+++ b/compiler/cpp/src/generate/t_go_generator.cc
@@ -132,6 +132,10 @@ public:
                               t_struct* tstruct,
                               const string& tstruct_name,
                               bool is_result = false);
+  void generate_countsetfields_helper(std::ofstream& out,
+                              t_struct* tstruct,
+                              const string& tstruct_name,
+                              bool is_result = false);
   void generate_go_struct_reader(std::ofstream& out,
                                  t_struct* tstruct,
                                  const string& tstruct_name,
@@ -139,7 +143,8 @@ public:
   void generate_go_struct_writer(std::ofstream& out,
                                  t_struct* tstruct,
                                  const string& tstruct_name,
-                                 bool is_result = false);
+                                 bool is_result = false,
+                                 bool uses_countsetfields = false);
   void generate_go_function_helpers(t_function* tfunction);
   void get_publicized_name_and_def_value(t_field* tfield,
                                          string* OUT_pub_name,
@@ -1092,10 +1097,15 @@ void t_go_generator::generate_go_struct_definition(ofstream& out,
   // don't have thrift_spec.
   indent_up();
 
+  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::T_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()) {
@@ -1166,6 +1176,7 @@ void t_go_generator::generate_go_struct_definition(ofstream& out,
       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 << "() "
@@ -1175,9 +1186,14 @@ void t_go_generator::generate_go_struct_definition(ofstream& out,
     }
   }
 
+
+  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_reader(out, tstruct, tstruct_name, is_result);
-  generate_go_struct_writer(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;
@@ -1235,6 +1251,46 @@ void t_go_generator::generate_isset_helpers(ofstream& out,
 }
 
 /**
+ * Generates the CountSetFields helper method for a struct
+ */
+void t_go_generator::generate_countsetfields_helper(ofstream& out,
+                                            t_struct* tstruct,
+                                            const string& tstruct_name,
+                                            bool is_result) {
+  (void)is_result;
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  const string escaped_tstruct_name(escape_string(tstruct->get_name()));
+
+  out << indent() << "func (p *" << tstruct_name << ") CountSetFields" << tstruct_name
+      << "() int {"
+      << endl;
+  indent_up();
+  out << indent() << "count := 0" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
+      continue;
+
+    if (!is_pointer_field(*f_iter))
+      continue;
+
+    const string field_name(
+        publicize(variable_name_to_go_name(escape_string((*f_iter)->get_name()))));
+
+    out << indent() << "if (p.IsSet" << field_name << "()) {" << endl;
+    indent_up();
+    out << indent() << "count++" << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+  }
+
+  out << indent() << "return count" << endl << endl;
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+
+/**
  * Generates the read method for a struct
  */
 void t_go_generator::generate_go_struct_reader(ofstream& out,
@@ -1388,13 +1444,20 @@ void t_go_generator::generate_go_struct_reader(ofstream& out,
 void t_go_generator::generate_go_struct_writer(ofstream& out,
                                                t_struct* tstruct,
                                                const string& tstruct_name,
-                                               bool is_result) {
+                                               bool is_result,
+                                               bool uses_countsetfields) {
   (void)is_result;
   string name(tstruct->get_name());
   const vector<t_field*>& fields = tstruct->get_sorted_members();
   vector<t_field*>::const_iterator f_iter;
   indent(out) << "func (p *" << tstruct_name << ") Write(oprot thrift.TProtocol) error {" << endl;
   indent_up();
+  if (tstruct->is_union() && uses_countsetfields) {
+    std::string tstruct_name(publicize(tstruct->get_name()));
+    out << indent() << "if c := p.CountSetFields" << tstruct_name << "(); c != 1 {" << endl
+        << indent() << "  return fmt.Errorf(\"%T write union: exactly one field must be set (%d set).\", p, c)" << endl
+        << indent() << "}" << endl;
+  }
   out << indent() << "if err := oprot.WriteStructBegin(\"" << name << "\"); err != nil {" << endl;
   out << indent() << "  return thrift.PrependError(fmt.Sprintf("
                      "\"%T write struct begin error: \", p), err) }" << endl;