hawq-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r...@apache.org
Subject [37/51] [abbrv] [partial] incubator-hawq git commit: HAWQ-735. Import thrift-0.9.3 into depends/thirdparty/thrift folder
Date Wed, 18 May 2016 02:50:50 GMT
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/d709f67d/depends/thirdparty/thrift/compiler/cpp/src/generate/t_go_generator.cc
----------------------------------------------------------------------
diff --git a/depends/thirdparty/thrift/compiler/cpp/src/generate/t_go_generator.cc b/depends/thirdparty/thrift/compiler/cpp/src/generate/t_go_generator.cc
new file mode 100644
index 0000000..f04bc48
--- /dev/null
+++ b/depends/thirdparty/thrift/compiler/cpp/src/generate/t_go_generator.cc
@@ -0,0 +1,3582 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * This file is programmatically sanitized for style:
+ * astyle --style=1tbs -f -p -H -j -U t_go_generator.cc
+ *
+ * The output of astyle should not be taken unquestioningly, but it is a good
+ * guide for ensuring uniformity and readability.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include <algorithm>
+#include <clocale>
+#include "t_generator.h"
+#include "platform.h"
+#include "version.h"
+
+using std::map;
+using std::ofstream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * A helper for automatically formatting the emitted Go code from the Thrift
+ * IDL per the Go style guide.
+ *
+ * Returns:
+ *  - true, if the formatting process succeeded.
+ *  - false, if the formatting process failed, which means the basic output was
+ *           still generated.
+ */
+bool format_go_output(const string& file_path);
+
+const string default_thrift_import = "git.apache.org/thrift.git/lib/go/thrift";
+static std::string package_flag;
+
+/**
+ * Go code generator.
+ */
+class t_go_generator : public t_generator {
+public:
+  t_go_generator(t_program* program,
+                 const std::map<std::string, std::string>& parsed_options,
+                 const std::string& option_string)
+    : t_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+    out_dir_base_ = "gen-go";
+    gen_thrift_import_ = default_thrift_import;
+
+    iter = parsed_options.find("package_prefix");
+
+    if (iter != parsed_options.end()) {
+      gen_package_prefix_ = (iter->second);
+    }
+
+    iter = parsed_options.find("thrift_import");
+
+    if (iter != parsed_options.end()) {
+      gen_thrift_import_ = (iter->second);
+    }
+
+    iter = parsed_options.find("package");
+
+    if (iter != parsed_options.end()) {
+      package_flag = (iter->second);
+    }
+
+    iter = parsed_options.find("read_write_private");
+    read_write_private_ = (iter != parsed_options.end());
+
+    iter = parsed_options.find("ignore_initialisms");
+    ignore_initialisms_ = (iter != parsed_options.end());
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_const(t_const* tconst);
+  void generate_struct(t_struct* tstruct);
+  void generate_xception(t_struct* txception);
+  void generate_service(t_service* tservice);
+
+  std::string render_const_value(t_type* type, t_const_value* value, const string& name);
+
+  /**
+   * Struct generation code
+   */
+
+  void generate_go_struct(t_struct* tstruct, bool is_exception);
+  void generate_go_struct_definition(std::ofstream& out,
+                                     t_struct* tstruct,
+                                     bool is_xception = false,
+                                     bool is_result = false,
+                                     bool is_args = false);
+  void generate_go_struct_initializer(std::ofstream& out,
+                                      t_struct* tstruct,
+                                      bool is_args_or_result = false);
+  void generate_isset_helpers(std::ofstream& out,
+                              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,
+                                 bool is_result = false);
+  void generate_go_struct_writer(std::ofstream& out,
+                                 t_struct* tstruct,
+                                 const string& tstruct_name,
+                                 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,
+                                         t_const_value** OUT_def_value) const;
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_interface(t_service* tservice);
+  void generate_service_client(t_service* tservice);
+  void generate_service_remote(t_service* tservice);
+  void generate_service_server(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field(std::ofstream& out,
+                                  t_field* tfield,
+                                  bool declare,
+                                  std::string prefix = "",
+                                  bool inclass = false,
+                                  bool coerceData = false,
+                                  bool inkey = false,
+                                  bool in_container = false,
+                                  bool use_true_type = false);
+
+  void generate_deserialize_struct(std::ofstream& out,
+                                   t_struct* tstruct,
+                                   bool is_pointer_field,
+                                   bool declare,
+                                   std::string prefix = "");
+
+  void generate_deserialize_container(std::ofstream& out,
+                                      t_type* ttype,
+                                      bool pointer_field,
+                                      bool declare,
+                                      std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ofstream& out,
+                                        t_set* tset,
+                                        bool declare,
+                                        std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ofstream& out,
+                                        t_map* tmap,
+                                        bool declare,
+                                        std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ofstream& out,
+                                         t_list* tlist,
+                                         bool declare,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(std::ofstream& out,
+                                t_field* tfield,
+                                std::string prefix = "",
+                                bool inkey = false);
+
+  void generate_serialize_struct(std::ofstream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ofstream& out,
+                                    t_type* ttype,
+                                    bool pointer_field,
+                                    std::string prefix = "");
+
+  void generate_serialize_map_element(std::ofstream& out,
+                                      t_map* tmap,
+                                      std::string kiter,
+                                      std::string viter);
+
+  void generate_serialize_set_element(std::ofstream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ofstream& out, t_list* tlist, std::string iter);
+
+  void generate_go_docstring(std::ofstream& out, t_struct* tstruct);
+
+  void generate_go_docstring(std::ofstream& out, t_function* tfunction);
+
+  void generate_go_docstring(std::ofstream& out,
+                             t_doc* tdoc,
+                             t_struct* tstruct,
+                             const char* subheader);
+
+  void generate_go_docstring(std::ofstream& out, t_doc* tdoc);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string go_autogen_comment();
+  std::string go_package();
+  std::string go_imports_begin();
+  std::string go_imports_end();
+  std::string render_includes();
+  std::string render_import_protection();
+  std::string render_fastbinary_includes();
+  std::string declare_argument(t_field* tfield);
+  std::string render_field_initial_value(t_field* tfield, const string& name, bool optional_field);
+  std::string type_name(t_type* ttype);
+  std::string function_signature(t_function* tfunction, std::string prefix = "");
+  std::string function_signature_if(t_function* tfunction,
+                                    std::string prefix = "",
+                                    bool addError = false);
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string type_to_go_type(t_type* ttype, bool is_container_value = false);
+  std::string type_to_go_type_with_opt(t_type* ttype,
+                                       bool optional_field,
+                                       bool is_container_value = false);
+  std::string type_to_go_key_type(t_type* ttype);
+  std::string type_to_spec_args(t_type* ttype);
+
+  static std::string get_real_go_module(const t_program* program) {
+
+    if (!package_flag.empty()) {
+      return package_flag;
+    }
+    std::string real_module = program->get_namespace("go");
+    if (!real_module.empty()) {
+      return real_module;
+    }
+
+    return lowercase(program->get_name());
+  }
+
+private:
+  std::string gen_package_prefix_;
+  std::string gen_thrift_import_;
+  bool read_write_private_;
+  bool ignore_initialisms_;
+
+  /**
+   * File streams
+   */
+
+  std::ofstream f_types_;
+  std::string f_types_name_;
+  std::ofstream f_consts_;
+  std::string f_consts_name_;
+  std::stringstream f_const_values_;
+  std::ofstream f_service_;
+
+  std::string package_name_;
+  std::string package_dir_;
+  std::string read_method_name_;
+  std::string write_method_name_;
+
+  std::set<std::string> commonInitialisms;
+
+  std::string camelcase(const std::string& value) const;
+  void fix_common_initialism(std::string& value, int i) const;
+  std::string publicize(const std::string& value, bool is_args_or_result = false) const;
+  std::string privatize(const std::string& value) const;
+  std::string new_prefix(const std::string& value) const;
+  static std::string variable_name_to_go_name(const std::string& value);
+  static bool is_pointer_field(t_field* tfield, bool in_container = false);
+  static bool omit_initialization(t_field* tfield);
+};
+
+// returns true if field initialization can be omitted since it has corresponding go type zero value
+// or default value is not set
+bool t_go_generator::omit_initialization(t_field* tfield) {
+  t_const_value* value = tfield->get_value();
+  if (!value) {
+    return true;
+  }
+  t_type* type = tfield->get_type()->get_true_type();
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "";
+
+    case t_base_type::TYPE_STRING:
+      if (((t_base_type*)type)->is_binary()) {
+        //[]byte are always inline
+        return false;
+      }
+      // strings are pointers if has no default
+      return value->get_string().empty();
+
+    case t_base_type::TYPE_BOOL:
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      return value->get_integer() == 0;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        return value->get_integer() == 0;
+      } else {
+        return value->get_double() == 0.;
+      }
+    }
+  }
+  return false;
+}
+
+// Returns true if the type need a reference if used as optional without default
+static bool type_need_reference(t_type* type) {
+  type = type->get_true_type();
+  if (type->is_map() || type->is_set() || type->is_list() || type->is_struct()
+      || type->is_xception() || (type->is_string() && ((t_base_type*)type)->is_binary())) {
+    return false;
+  }
+  return true;
+}
+
+// returns false if field could not use comparison to default value as !IsSet*
+bool t_go_generator::is_pointer_field(t_field* tfield, bool in_container_value) {
+  (void)in_container_value;
+  if (tfield->annotations_.count("cpp.ref") != 0) {
+    return true;
+  }
+  t_type* type = tfield->get_type()->get_true_type();
+  // Structs in containers are pointers
+  if (type->is_struct() || type->is_xception()) {
+    return true;
+  }
+  if (!(tfield->get_req() == t_field::T_OPTIONAL)) {
+    return false;
+  }
+
+  bool has_default = tfield->get_value();
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "";
+
+    case t_base_type::TYPE_STRING:
+      if (((t_base_type*)type)->is_binary()) {
+        //[]byte are always inline
+        return false;
+      }
+      // strings are pointers if has no default
+      return !has_default;
+
+    case t_base_type::TYPE_BOOL:
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+    case t_base_type::TYPE_DOUBLE:
+      return !has_default;
+    }
+  } else if (type->is_enum()) {
+    return !has_default;
+  } else if (type->is_struct() || type->is_xception()) {
+    return true;
+  } else if (type->is_map()) {
+    return has_default;
+  } else if (type->is_set()) {
+    return has_default;
+  } else if (type->is_list()) {
+    return has_default;
+  } else if (type->is_typedef()) {
+    return has_default;
+  }
+
+  throw "INVALID TYPE IN type_to_go_type: " + type->get_name();
+}
+
+std::string t_go_generator::camelcase(const std::string& value) const {
+  std::string value2(value);
+  std::setlocale(LC_ALL, "C"); // set locale to classic
+
+  // Fix common initialism in first word
+  fix_common_initialism(value2, 0);
+
+  // as long as we are changing things, let's change _ followed by lowercase to
+  // capital and fix common initialisms
+  for (std::string::size_type i = 1; i < value2.size() - 1; ++i) {
+    if (value2[i] == '_') {
+      if (islower(value2[i + 1])) {
+        value2.replace(i, 2, 1, toupper(value2[i + 1]));
+      }
+      fix_common_initialism(value2, i);
+    }
+  }
+
+  return value2;
+}
+
+// Checks to see if the word starting at i in value contains a common initialism
+// and if so replaces it with the upper case version of the word.
+void t_go_generator::fix_common_initialism(std::string& value, int i) const {
+  if (!ignore_initialisms_) {
+    size_t wordLen = value.find('_', i);
+    if (wordLen != std::string::npos) {
+      wordLen -= i;
+    }
+    std::string word = value.substr(i, wordLen);
+    std::transform(word.begin(), word.end(), word.begin(), ::toupper);
+    if (commonInitialisms.find(word) != commonInitialisms.end()) {
+      value.replace(i, word.length(), word);
+    }
+  }
+}
+
+std::string t_go_generator::publicize(const std::string& value, bool is_args_or_result) const {
+  if (value.size() <= 0) {
+    return value;
+  }
+
+  std::string value2(value), prefix;
+
+  string::size_type dot_pos = value.rfind('.');
+  if (dot_pos != string::npos) {
+    prefix = value.substr(0, dot_pos + 1) + prefix;
+    value2 = value.substr(dot_pos + 1);
+  }
+
+  if (!isupper(value2[0])) {
+    value2[0] = toupper(value2[0]);
+  }
+
+  value2 = camelcase(value2);
+
+  // final length before further checks, the string may become longer
+  size_t len_before = value2.length();
+
+  // IDL identifiers may start with "New" which interferes with the CTOR pattern
+  // Adding an extra underscore to all those identifiers solves this
+  if ((len_before >= 3) && (value2.substr(0, 3) == "New")) {
+    value2 += '_';
+  }
+
+  // IDL identifiers may end with "Args"/"Result" which interferes with the implicit service
+  // function structs
+  // Adding another extra underscore to all those identifiers solves this
+  // Suppress this check for the actual helper struct names
+  if (!is_args_or_result) {
+    bool ends_with_args = (len_before >= 4) && (value2.substr(len_before - 4, 4) == "Args");
+    bool ends_with_rslt = (len_before >= 6) && (value2.substr(len_before - 6, 6) == "Result");
+    if (ends_with_args || ends_with_rslt) {
+      value2 += '_';
+    }
+  }
+
+  // Avoid naming collisions with other services
+  if (is_args_or_result) {
+    prefix += publicize(service_name_);
+  }
+
+  return prefix + value2;
+}
+
+std::string t_go_generator::new_prefix(const std::string& value) const {
+  if (value.size() <= 0) {
+    return value;
+  }
+
+  string::size_type dot_pos = value.rfind('.');
+  if (dot_pos != string::npos) {
+    return value.substr(0, dot_pos + 1) + "New" + publicize(value.substr(dot_pos + 1));
+  }
+  return "New" + publicize(value);
+}
+
+std::string t_go_generator::privatize(const std::string& value) const {
+  if (value.size() <= 0) {
+    return value;
+  }
+
+  std::string value2(value);
+
+  if (!islower(value2[0])) {
+    value2[0] = tolower(value2[0]);
+  }
+
+  value2 = camelcase(value2);
+
+  return value2;
+}
+
+std::string t_go_generator::variable_name_to_go_name(const std::string& value) {
+  if (value.size() <= 0) {
+    return value;
+  }
+
+  std::string value2(value);
+  std::transform(value2.begin(), value2.end(), value2.begin(), ::tolower);
+
+  switch (value[0]) {
+  case 'b':
+  case 'B':
+    if (value2 != "break") {
+      return value;
+    }
+
+    break;
+
+  case 'c':
+  case 'C':
+    if (value2 != "case" && value2 != "chan" && value2 != "const" && value2 != "continue") {
+      return value;
+    }
+
+    break;
+
+  case 'd':
+  case 'D':
+    if (value2 != "default" && value2 != "defer") {
+      return value;
+    }
+
+    break;
+
+  case 'e':
+  case 'E':
+    if (value2 != "else" && value2 != "error") {
+      return value;
+    }
+
+    break;
+
+  case 'f':
+  case 'F':
+    if (value2 != "fallthrough" && value2 != "for" && value2 != "func") {
+      return value;
+    }
+
+    break;
+
+  case 'g':
+  case 'G':
+    if (value2 != "go" && value2 != "goto") {
+      return value;
+    }
+
+    break;
+
+  case 'i':
+  case 'I':
+    if (value2 != "if" && value2 != "import" && value2 != "interface") {
+      return value;
+    }
+
+    break;
+
+  case 'm':
+  case 'M':
+    if (value2 != "map") {
+      return value;
+    }
+
+    break;
+
+  case 'p':
+  case 'P':
+    if (value2 != "package") {
+      return value;
+    }
+
+    break;
+
+  case 'r':
+  case 'R':
+    if (value2 != "range" && value2 != "return") {
+      return value;
+    }
+
+    break;
+
+  case 's':
+  case 'S':
+    if (value2 != "select" && value2 != "struct" && value2 != "switch") {
+      return value;
+    }
+
+    break;
+
+  case 't':
+  case 'T':
+    if (value2 != "type") {
+      return value;
+    }
+
+    break;
+
+  case 'v':
+  case 'V':
+    if (value2 != "var") {
+      return value;
+    }
+
+    break;
+
+  default:
+    return value;
+  }
+
+  return value2 + "_a1";
+}
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_go_generator::init_generator() {
+  // Make output directory
+  string module = get_real_go_module(program_);
+  string target = module;
+  package_dir_ = get_out_dir();
+
+  // This set is taken from https://github.com/golang/lint/blob/master/lint.go#L692
+  commonInitialisms.insert("API");
+  commonInitialisms.insert("ASCII");
+  commonInitialisms.insert("CPU");
+  commonInitialisms.insert("CSS");
+  commonInitialisms.insert("DNS");
+  commonInitialisms.insert("EOF");
+  commonInitialisms.insert("GUID");
+  commonInitialisms.insert("HTML");
+  commonInitialisms.insert("HTTP");
+  commonInitialisms.insert("HTTPS");
+  commonInitialisms.insert("ID");
+  commonInitialisms.insert("IP");
+  commonInitialisms.insert("JSON");
+  commonInitialisms.insert("LHS");
+  commonInitialisms.insert("QPS");
+  commonInitialisms.insert("RAM");
+  commonInitialisms.insert("RHS");
+  commonInitialisms.insert("RPC");
+  commonInitialisms.insert("SLA");
+  commonInitialisms.insert("SMTP");
+  commonInitialisms.insert("SSH");
+  commonInitialisms.insert("TCP");
+  commonInitialisms.insert("TLS");
+  commonInitialisms.insert("TTL");
+  commonInitialisms.insert("UDP");
+  commonInitialisms.insert("UI");
+  commonInitialisms.insert("UID");
+  commonInitialisms.insert("UUID");
+  commonInitialisms.insert("URI");
+  commonInitialisms.insert("URL");
+  commonInitialisms.insert("UTF8");
+  commonInitialisms.insert("VM");
+  commonInitialisms.insert("XML");
+  commonInitialisms.insert("XSRF");
+  commonInitialisms.insert("XSS");
+
+  // names of read and write methods
+  if (read_write_private_) {
+    read_method_name_ = "read";
+    write_method_name_ = "write";
+  } else {
+    read_method_name_ = "Read";
+    write_method_name_ = "Write";
+  }
+
+  while (true) {
+    // TODO: Do better error checking here.
+    MKDIR(package_dir_.c_str());
+
+    if (module.empty()) {
+      break;
+    }
+
+    string::size_type pos = module.find('.');
+
+    if (pos == string::npos) {
+      package_dir_ += "/";
+      package_dir_ += module;
+      package_name_ = module;
+      module.clear();
+    } else {
+      package_dir_ += "/";
+      package_dir_ += module.substr(0, pos);
+      module.erase(0, pos + 1);
+    }
+  }
+
+  string::size_type loc;
+
+  while ((loc = target.find(".")) != string::npos) {
+    target.replace(loc, 1, 1, '/');
+  }
+
+  // Make output files
+  f_types_name_ = package_dir_ + "/" + "ttypes.go";
+  f_types_.open(f_types_name_.c_str());
+
+  f_consts_name_ = package_dir_ + "/" + "constants.go";
+  f_consts_.open(f_consts_name_.c_str());
+
+  vector<t_service*> services = program_->get_services();
+  vector<t_service*>::iterator sv_iter;
+
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    string service_dir = package_dir_ + "/" + underscore((*sv_iter)->get_name()) + "-remote";
+    MKDIR(service_dir.c_str());
+  }
+
+  // Print header
+  f_types_ << go_autogen_comment() << go_package() << render_includes()
+           << render_import_protection();
+
+  f_consts_ << go_autogen_comment() << go_package() << render_includes();
+
+  f_const_values_ << endl << "func init() {" << endl;
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_go_generator::render_includes() {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+  string unused_prot = "";
+
+  for (size_t i = 0; i < includes.size(); ++i) {
+    string go_module = get_real_go_module(includes[i]);
+    size_t found = 0;
+    for (size_t j = 0; j < go_module.size(); j++) {
+      // Import statement uses slashes ('/') in namespace
+      if (go_module[j] == '.') {
+        go_module[j] = '/';
+        found = j + 1;
+      }
+    }
+
+    result += "\t\"" + gen_package_prefix_ + go_module + "\"\n";
+    unused_prot += "var _ = " + go_module.substr(found) + ".GoUnusedProtection__\n";
+  }
+
+  if (includes.size() > 0) {
+    result += "\n";
+  }
+
+  return go_imports_begin() + result + go_imports_end() + unused_prot;
+}
+
+string t_go_generator::render_import_protection() {
+  return string("var GoUnusedProtection__ int;\n\n");
+}
+
+/**
+ * Renders all the imports necessary to use the accelerated TBinaryProtocol
+ */
+string t_go_generator::render_fastbinary_includes() {
+  return "";
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_go_generator::go_autogen_comment() {
+  return
+        std::string() +
+        "// Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
+        "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n\n";
+}
+
+/**
+ * Prints standard thrift package
+ */
+string t_go_generator::go_package() {
+  return string("package ") + package_name_ + "\n\n";
+}
+
+/**
+ * Render the beginning of the import statement
+ */
+string t_go_generator::go_imports_begin() {
+  return string(
+      "import (\n"
+      "\t\"bytes\"\n"
+      "\t\"fmt\"\n"
+      "\t\"" + gen_thrift_import_ + "\"\n");
+}
+
+/**
+ * End the import statement, include undscore-assignments
+ *
+ * These "_ =" prevent the go compiler complaining about used imports.
+ * This will have to do in lieu of more intelligent import statement construction
+ */
+string t_go_generator::go_imports_end() {
+  return string(
+      ")\n\n"
+      "// (needed to ensure safety because of naive import list construction.)\n"
+      "var _ = thrift.ZERO\n"
+      "var _ = fmt.Printf\n"
+      "var _ = bytes.Equal\n\n");
+}
+
+/**
+ * Closes the type files
+ */
+void t_go_generator::close_generator() {
+  f_const_values_ << "}" << endl << endl;
+  f_consts_ << f_const_values_.str();
+
+  // Close types and constants files
+  f_consts_.close();
+  f_types_.close();
+  format_go_output(f_types_name_);
+  format_go_output(f_consts_name_);
+}
+
+/**
+ * Generates a typedef.
+ *
+ * @param ttypedef The type definition
+ */
+void t_go_generator::generate_typedef(t_typedef* ttypedef) {
+  generate_go_docstring(f_types_, ttypedef);
+  string new_type_name(publicize(ttypedef->get_symbolic()));
+  string base_type(type_to_go_type(ttypedef->get_type()));
+
+  if (base_type == new_type_name) {
+    return;
+  }
+
+  f_types_ << "type " << new_type_name << " " << base_type << endl << endl;
+  // Generate a convenience function that converts an instance of a type
+  // (which may be a constant) into a pointer to an instance of a type.
+  f_types_ << "func " << new_type_name << "Ptr(v " << new_type_name << ") *" << new_type_name
+           << " { return &v }" << endl << endl;
+}
+
+/**
+ * Generates code for an enumerated type. Done using a class to scope
+ * the values.
+ *
+ * @param tenum The enumeration
+ */
+void t_go_generator::generate_enum(t_enum* tenum) {
+  std::ostringstream to_string_mapping, from_string_mapping;
+  std::string tenum_name(publicize(tenum->get_name()));
+  generate_go_docstring(f_types_, tenum);
+  f_types_ << "type " << tenum_name << " int64" << endl << "const (" << endl;
+
+  to_string_mapping << indent() << "func (p " << tenum_name << ") String() string {" << endl;
+  to_string_mapping << indent() << "  switch p {" << endl;
+
+  from_string_mapping << indent() << "func " << tenum_name << "FromString(s string) (" << tenum_name
+                      << ", error) {" << endl;
+  from_string_mapping << indent() << "  switch s {" << endl;
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  int value = -1;
+
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    value = (*c_iter)->get_value();
+
+    string iter_std_name(escape_string((*c_iter)->get_name()));
+    string iter_name((*c_iter)->get_name());
+    f_types_ << indent() << "  " << tenum_name << "_" << iter_name << ' ' << tenum_name << " = "
+             << value << endl;
+    // Dictionaries to/from string names of enums
+    to_string_mapping << indent() << "  case " << tenum_name << "_" << iter_name << ": return \""
+                      << iter_std_name << "\"" << endl;
+
+    if (iter_std_name != escape_string(iter_name)) {
+      from_string_mapping << indent() << "  case \"" << iter_std_name << "\", \""
+                          << escape_string(iter_name) << "\": return " << tenum_name << "_"
+                          << iter_name << ", nil " << endl;
+    } else {
+      from_string_mapping << indent() << "  case \"" << iter_std_name << "\": return " << tenum_name
+                          << "_" << iter_name << ", nil " << endl;
+    }
+  }
+
+  to_string_mapping << indent() << "  }" << endl;
+  to_string_mapping << indent() << "  return \"<UNSET>\"" << endl;
+  to_string_mapping << indent() << "}" << endl;
+  from_string_mapping << indent() << "  }" << endl;
+  from_string_mapping << indent() << "  return " << tenum_name << "(0),"
+                      << " fmt.Errorf(\"not a valid " << tenum_name << " string\")" << endl;
+  from_string_mapping << indent() << "}" << endl;
+
+  f_types_ << ")" << endl << endl << to_string_mapping.str() << endl << from_string_mapping.str()
+           << endl << endl;
+
+  // Generate a convenience function that converts an instance of an enum
+  // (which may be a constant) into a pointer to an instance of that enum
+  // type.
+  f_types_ << "func " << tenum_name << "Ptr(v " << tenum_name << ") *" << tenum_name
+           << " { return &v }" << endl << endl;
+
+  // Generate MarshalText
+  f_types_ << "func (p " << tenum_name << ") MarshalText() ([]byte, error) {" << endl;
+  f_types_ << "return []byte(p.String()), nil" << endl;
+  f_types_ << "}" << endl << endl;
+
+  // Generate UnmarshalText
+  f_types_ << "func (p *" << tenum_name << ") UnmarshalText(text []byte) error {" << endl;
+  f_types_ << "q, err := " << tenum_name << "FromString(string(text))" << endl;
+  f_types_ << "if (err != nil) {" << endl << "return err" << endl << "}" << endl;
+  f_types_ << "*p = q" << endl;
+  f_types_ << "return nil" << endl;
+  f_types_ << "}" << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_go_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = publicize(tconst->get_name());
+  t_const_value* value = tconst->get_value();
+
+  if (type->is_base_type() || type->is_enum()) {
+    indent(f_consts_) << "const " << name << " = " << render_const_value(type, value, name) << endl;
+  } else {
+    f_const_values_ << indent() << name << " = " << render_const_value(type, value, name) << endl
+                    << endl;
+
+    f_consts_ << indent() << "var " << name << " " << type_to_go_type(type) << endl;
+  }
+}
+
+/**
+ * Prints the value of a constant with the given type. Note that type checking
+ * is NOT performed in this function as it is always run beforehand using the
+ * validate_types method in main.cc
+ */
+string t_go_generator::render_const_value(t_type* type, t_const_value* value, const string& name) {
+  type = get_true_type(type);
+  std::ostringstream out;
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      if (((t_base_type*)type)->is_binary()) {
+        out << "[]byte(\"" << get_escaped_string(value) << "\")";
+      } else {
+        out << '"' << get_escaped_string(value) << '"';
+      }
+
+      break;
+
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "true" : "false");
+      break;
+
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      out << value->get_integer();
+      break;
+
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        out << value->get_integer();
+      } else {
+        out << value->get_double();
+      }
+
+      break;
+
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    indent(out) << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << "&" << publicize(type_name(type)) << "{";
+    indent_up();
+    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = NULL;
+
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+          field_type = (*f_iter)->get_type();
+        }
+      }
+
+      if (field_type == NULL) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+
+      out << endl << indent() << publicize(v_iter->first->get_string()) << ": "
+          << render_const_value(field_type, v_iter->second, name) << "," << endl;
+    }
+
+    indent_down();
+    out << "}";
+
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    out << "map[" << type_to_go_type(ktype) << "]" << type_to_go_type(vtype, true) << "{" << endl;
+    indent_up();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent() << render_const_value(ktype, v_iter->first, name) << ": "
+          << render_const_value(vtype, v_iter->second, name) << "," << endl;
+    }
+
+    indent_down();
+    out << indent() << "}";
+  } else if (type->is_list()) {
+    t_type* etype = ((t_list*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    out << "[]" << type_to_go_type(etype) << "{" << endl;
+    indent_up();
+    vector<t_const_value*>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent() << render_const_value(etype, *v_iter, name) << ", ";
+    }
+
+    indent_down();
+    out << indent() << "}";
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    out << "map[" << type_to_go_key_type(etype) << "]bool{" << endl;
+    indent_up();
+    vector<t_const_value*>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent() << render_const_value(etype, *v_iter, name) << ": true," << endl;
+    }
+
+    indent_down();
+    out << indent() << "}";
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+
+  return out.str();
+}
+
+/**
+ * Generates a go struct
+ */
+void t_go_generator::generate_struct(t_struct* tstruct) {
+  generate_go_struct(tstruct, false);
+}
+
+/**
+ * Generates a struct definition for a thrift exception. Basically the same
+ * as a struct but extends the Exception class.
+ *
+ * @param txception The struct definition
+ */
+void t_go_generator::generate_xception(t_struct* txception) {
+  generate_go_struct(txception, true);
+}
+
+/**
+ * Generates a go struct
+ */
+void t_go_generator::generate_go_struct(t_struct* tstruct, bool is_exception) {
+  generate_go_struct_definition(f_types_, tstruct, is_exception);
+}
+
+void t_go_generator::get_publicized_name_and_def_value(t_field* tfield,
+                                                       string* OUT_pub_name,
+                                                       t_const_value** OUT_def_value) const {
+  const string base_field_name = tfield->get_name();
+  const string escaped_field_name = escape_string(base_field_name);
+  *OUT_pub_name = publicize(escaped_field_name);
+  *OUT_def_value = tfield->get_value();
+}
+
+void t_go_generator::generate_go_struct_initializer(ofstream& out,
+                                                    t_struct* tstruct,
+                                                    bool is_args_or_result) {
+  out << publicize(type_name(tstruct), is_args_or_result) << "{";
+  const vector<t_field*>& members = tstruct->get_members();
+  for (vector<t_field*>::const_iterator m_iter = members.begin(); m_iter != members.end();
+       ++m_iter) {
+    bool pointer_field = is_pointer_field(*m_iter);
+    string publicized_name;
+    t_const_value* def_value;
+    get_publicized_name_and_def_value(*m_iter, &publicized_name, &def_value);
+    if (!pointer_field && def_value != NULL && !omit_initialization(*m_iter)) {
+      out << endl << indent() << publicized_name << ": "
+          << render_field_initial_value(*m_iter, (*m_iter)->get_name(), pointer_field) << ","
+          << endl;
+    }
+  }
+
+  out << "}" << endl;
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_go_generator::generate_go_struct_definition(ofstream& out,
+                                                   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();
+
+  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()) {
+          ++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;
+        }
+      }
+
+      t_type* fieldType = (*m_iter)->get_type();
+      string goType = type_to_go_type_with_opt(fieldType, is_pointer_field(*m_iter));
+      string gotag;
+      if ((*m_iter)->get_req() == t_field::T_OPTIONAL) {
+        gotag = "json:\"" + escape_string((*m_iter)->get_name()) + ",omitempty\"";
+      } else {
+        gotag = "json:\"" + escape_string((*m_iter)->get_name()) + "\"";
+      }
+      std::map<string, string>::iterator it = (*m_iter)->annotations_.find("go.tag");
+      if (it != (*m_iter)->annotations_.end()) {
+        gotag = it->second;
+      }
+      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::T_REQUIRED) {
+        out << ",required";
+      }
+
+      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;
+  out << indent() << "  return &";
+  generate_go_struct_initializer(out, tstruct, is_result || is_args);
+  out << indent() << "}" << endl << endl;
+  // Default values for optional fields
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    string publicized_name;
+    t_const_value* def_value;
+    get_publicized_name_and_def_value(*m_iter, &publicized_name, &def_value);
+    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::T_OPTIONAL || is_pointer_field(*m_iter)) {
+      out << indent() << "var " << def_var_name << " " << goType;
+      if (def_value != NULL) {
+        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_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;
+  out << indent() << "  return fmt.Sprintf(\"" << escape_string(tstruct_name) << "(%+v)\", *p)"
+      << 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;
+  }
+}
+
+/**
+ * Generates the IsSet helper methods for a struct
+ */
+void t_go_generator::generate_isset_helpers(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()));
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    const string field_name(publicize(escape_string((*f_iter)->get_name())));
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL || is_pointer_field(*f_iter)) {
+      out << indent() << "func (p *" << tstruct_name << ") IsSet" << field_name << "() bool {"
+          << endl;
+      indent_up();
+      t_type* ttype = (*f_iter)->get_type()->get_true_type();
+      bool is_byteslice = ttype->is_base_type() && ((t_base_type*)ttype)->is_binary();
+      bool compare_to_nil_only = ttype->is_set() || ttype->is_list() || ttype->is_map()
+                                 || (is_byteslice && !(*f_iter)->get_value());
+      if (is_pointer_field(*f_iter) || compare_to_nil_only) {
+        out << indent() << "return p." << field_name << " != nil" << endl;
+      } else {
+        string def_var_name = tstruct_name + "_" + field_name + "_DEFAULT";
+        if (is_byteslice) {
+          out << indent() << "return !bytes.Equal(p." << field_name << ", " << def_var_name << ")"
+              << endl;
+        } else {
+          out << indent() << "return p." << field_name << " != " << def_var_name << endl;
+        }
+      }
+      indent_down();
+      out << indent() << "}" << endl << endl;
+    }
+  }
+}
+
+/**
+ * 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(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,
+                                               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;
+  string escaped_tstruct_name(escape_string(tstruct->get_name()));
+  out << indent() << "func (p *" << tstruct_name << ") " << read_method_name_ << "(iprot thrift.TProtocol) error {"
+      << endl;
+  indent_up();
+  out << indent() << "if _, err := iprot.ReadStructBegin(); err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)"
+      << endl;
+  out << indent() << "}" << endl << endl;
+
+  // Required variables does not have IsSet functions, so we need tmp vars to check them.
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      const string field_name(publicize(escape_string((*f_iter)->get_name())));
+      indent(out) << "var isset" << field_name << " bool = false;" << endl;
+    }
+  }
+  out << endl;
+
+  // Loop over reading in fields
+  indent(out) << "for {" << endl;
+  indent_up();
+  // Read beginning field marker
+  out << indent() << "_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()" << endl;
+  out << indent() << "if err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(fmt.Sprintf("
+                     "\"%T field %d read error: \", p, fieldId), err)" << endl;
+  out << indent() << "}" << endl;
+  // Check for field STOP marker and break
+  out << indent() << "if fieldTypeId == thrift.STOP { break; }" << endl;
+
+  string thriftFieldTypeId;
+  // Generate deserialization code for known cases
+  int32_t field_id = -1;
+
+  // Switch statement on the field we are reading, false if no fields present
+  bool have_switch = !fields.empty();
+  if (have_switch) {
+    indent(out) << "switch fieldId {" << endl;
+  }
+
+  // All the fields we know
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    field_id = (*f_iter)->get_key();
+
+    // if negative id, ensure we generate a valid method name
+    string field_method_prefix("readField");
+
+    if (field_id < 0) {
+      field_method_prefix += "_";
+      field_id *= -1;
+    }
+
+    out << indent() << "case " << field_id << ":" << endl;
+    indent_up();
+    thriftFieldTypeId = type_to_enum((*f_iter)->get_type());
+
+    if (thriftFieldTypeId == "thrift.BINARY") {
+      thriftFieldTypeId = "thrift.STRING";
+    }
+
+    out << indent() << "if err := p." << field_method_prefix << field_id << "(iprot); err != nil {"
+        << endl;
+    out << indent() << "  return err" << endl;
+    out << indent() << "}" << endl;
+
+    // Mark required field as read
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      const string field_name(publicize(escape_string((*f_iter)->get_name())));
+      out << indent() << "isset" << field_name << " = true" << endl;
+    }
+
+    indent_down();
+  }
+
+  // Begin switch default case
+  if (have_switch) {
+    out << indent() << "default:" << endl;
+    indent_up();
+  }
+
+  // Skip unknown fields in either case
+  out << indent() << "if err := iprot.Skip(fieldTypeId); err != nil {" << endl;
+  out << indent() << "  return err" << endl;
+  out << indent() << "}" << endl;
+
+  // End switch default case
+  if (have_switch) {
+    indent_down();
+    out << indent() << "}" << endl;
+  }
+
+  // Read field end marker
+  out << indent() << "if err := iprot.ReadFieldEnd(); err != nil {" << endl;
+  out << indent() << "  return err" << endl;
+  out << indent() << "}" << endl;
+  indent_down();
+  out << indent() << "}" << endl;
+  out << indent() << "if err := iprot.ReadStructEnd(); err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(fmt.Sprintf("
+                     "\"%T read struct end error: \", p), err)" << endl;
+  out << indent() << "}" << endl;
+
+  // Return error if any required fields are missing.
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      const string field_name(publicize(escape_string((*f_iter)->get_name())));
+      out << indent() << "if !isset" << field_name << "{" << endl;
+      out << indent() << "  return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, "
+                         "fmt.Errorf(\"Required field " << field_name << " is not set\"));" << endl;
+      out << indent() << "}" << endl;
+    }
+  }
+
+  out << indent() << "return nil" << endl;
+  indent_down();
+  out << indent() << "}" << endl << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    string field_type_name(publicize((*f_iter)->get_type()->get_name()));
+    string field_name(publicize((*f_iter)->get_name()));
+    string field_method_prefix("readField");
+    int32_t field_id = (*f_iter)->get_key();
+
+    if (field_id < 0) {
+      field_method_prefix += "_";
+      field_id *= -1;
+    }
+
+    out << indent() << "func (p *" << tstruct_name << ")  " << field_method_prefix << field_id
+        << "(iprot thrift.TProtocol) error {" << endl;
+    indent_up();
+    generate_deserialize_field(out, *f_iter, false, "p.");
+    indent_down();
+    out << indent() << "  return nil" << endl;
+    out << indent() << "}" << endl << endl;
+  }
+}
+
+void t_go_generator::generate_go_struct_writer(ofstream& out,
+                                               t_struct* tstruct,
+                                               const string& tstruct_name,
+                                               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_method_name_ << "(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;
+
+  string field_name;
+  string escape_field_name;
+  // t_const_value* field_default_value;
+  t_field::e_req field_required;
+  int32_t field_id = -1;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    string field_method_prefix("writeField");
+    field_name = (*f_iter)->get_name();
+    escape_field_name = escape_string(field_name);
+    field_id = (*f_iter)->get_key();
+
+    if (field_id < 0) {
+      field_method_prefix += "_";
+      field_id *= -1;
+    }
+
+    out << indent() << "if err := p." << field_method_prefix << field_id
+        << "(oprot); err != nil { return err }" << endl;
+  }
+
+  // Write the struct map
+  out << indent() << "if err := oprot.WriteFieldStop(); err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(\"write field stop error: \", err) }" << endl;
+  out << indent() << "if err := oprot.WriteStructEnd(); err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(\"write struct stop error: \", err) }" << endl;
+  out << indent() << "return nil" << endl;
+  indent_down();
+  out << indent() << "}" << endl << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    string field_method_prefix("writeField");
+    field_id = (*f_iter)->get_key();
+    field_name = (*f_iter)->get_name();
+    escape_field_name = escape_string(field_name);
+    // field_default_value = (*f_iter)->get_value();
+    field_required = (*f_iter)->get_req();
+
+    if (field_id < 0) {
+      field_method_prefix += "_";
+      field_id *= -1;
+    }
+
+    out << indent() << "func (p *" << tstruct_name << ") " << field_method_prefix << field_id
+        << "(oprot thrift.TProtocol) (err error) {" << endl;
+    indent_up();
+
+    if (field_required == t_field::T_OPTIONAL) {
+      out << indent() << "if p.IsSet" << publicize(field_name) << "() {" << endl;
+      indent_up();
+    }
+
+    out << indent() << "if err := oprot.WriteFieldBegin(\"" << escape_field_name << "\", "
+        << type_to_enum((*f_iter)->get_type()) << ", " << field_id << "); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T write field begin error "
+        << field_id << ":" << escape_field_name << ": \", p), err) }" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "p.");
+
+    // Write field closer
+    out << indent() << "if err := oprot.WriteFieldEnd(); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T write field end error "
+        << field_id << ":" << escape_field_name << ": \", p), err) }" << endl;
+
+    if (field_required == t_field::T_OPTIONAL) {
+      indent_down();
+      out << indent() << "}" << endl;
+    }
+
+    indent_down();
+    out << indent() << "  return err" << endl;
+    out << indent() << "}" << endl << endl;
+  }
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_go_generator::generate_service(t_service* tservice) {
+  string test_suffix("_test");
+  string filename = lowercase(service_name_);
+  string f_service_name;
+
+  size_t fname_len = filename.length();
+  size_t suffix_len = test_suffix.length();
+
+  if ((fname_len >= suffix_len)
+      && (filename.compare(fname_len - suffix_len, suffix_len, test_suffix) == 0)) {
+    f_service_name = package_dir_ + "/" + filename + "_.go";
+  } else {
+    f_service_name = package_dir_ + "/" + filename + ".go";
+  }
+  f_service_.open(f_service_name.c_str());
+  f_service_ << go_autogen_comment() << go_package() << render_includes();
+
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+  generate_service_remote(tservice);
+  // Close service file
+  f_service_ << endl;
+  f_service_.close();
+  format_go_output(f_service_name);
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_go_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  f_service_ << "// HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_go_struct_definition(f_service_, ts, false, false, true);
+    generate_go_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_go_generator::generate_go_function_helpers(t_function* tfunction) {
+  if (!tfunction->is_oneway()) {
+    t_struct result(program_, tfunction->get_name() + "_result");
+    t_field success(tfunction->get_returntype(), "success", 0);
+    success.set_req(t_field::T_OPTIONAL);
+
+    if (!tfunction->get_returntype()->is_void()) {
+      result.append(&success);
+    }
+
+    t_struct* xs = tfunction->get_xceptions();
+    const vector<t_field*>& fields = xs->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      t_field* f = *f_iter;
+      f->set_req(t_field::T_OPTIONAL);
+      result.append(f);
+    }
+
+    generate_go_struct_definition(f_service_, &result, false, true);
+  }
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_go_generator::generate_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_if = "";
+  string serviceName(publicize(tservice->get_name()));
+  string interfaceName = serviceName;
+
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    size_t index = extends.rfind(".");
+
+    if (index != string::npos) {
+      extends_if = "\n" + indent() + "  " + extends.substr(0, index + 1)
+                   + publicize(extends.substr(index + 1)) + "\n";
+    } else {
+      extends_if = "\n" + indent() + publicize(extends) + "\n";
+    }
+  }
+
+  f_service_ << indent() << "type " << interfaceName << " interface {" << extends_if;
+  indent_up();
+  generate_go_docstring(f_service_, tservice);
+  vector<t_function*> functions = tservice->get_functions();
+
+  if (!functions.empty()) {
+    f_service_ << endl;
+    vector<t_function*>::iterator f_iter;
+
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      generate_go_docstring(f_service_, (*f_iter));
+      f_service_ << indent() << function_signature_if(*f_iter, "", true) << endl;
+    }
+  }
+
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_go_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_field = "";
+  string extends_client = "";
+  string extends_client_new = "";
+  string serviceName(publicize(tservice->get_name()));
+
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    size_t index = extends.rfind(".");
+
+    if (index != string::npos) {
+      extends_client = extends.substr(0, index + 1) + publicize(extends.substr(index + 1))
+                       + "Client";
+      extends_client_new = extends.substr(0, index + 1) + "New"
+                           + publicize(extends.substr(index + 1)) + "Client";
+    } else {
+      extends_client = publicize(extends) + "Client";
+      extends_client_new = "New" + extends_client;
+    }
+  }
+
+  extends_field = extends_client.substr(extends_client.find(".") + 1);
+
+  generate_go_docstring(f_service_, tservice);
+  f_service_ << indent() << "type " << serviceName << "Client struct {" << endl;
+  indent_up();
+
+  if (!extends_client.empty()) {
+    f_service_ << indent() << "*" << extends_client << endl;
+  } else {
+    f_service_ << indent() << "Transport thrift.TTransport" << endl;
+    f_service_ << indent() << "ProtocolFactory thrift.TProtocolFactory" << endl;
+    f_service_ << indent() << "InputProtocol thrift.TProtocol" << endl;
+    f_service_ << indent() << "OutputProtocol thrift.TProtocol" << endl;
+    f_service_ << indent() << "SeqId int32" << endl;
+    /*f_service_ << indent() << "reqs map[int32]Deferred" << endl*/;
+  }
+
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+  // Constructor function
+  f_service_ << indent() << "func New" << serviceName
+             << "ClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *" << serviceName
+             << "Client {" << endl;
+  indent_up();
+  f_service_ << indent() << "return &" << serviceName << "Client";
+
+  if (!extends.empty()) {
+    f_service_ << "{" << extends_field << ": " << extends_client_new << "Factory(t, f)}";
+  } else {
+    indent_up();
+    f_service_ << "{Transport: t," << endl;
+    f_service_ << indent() << "ProtocolFactory: f," << endl;
+    f_service_ << indent() << "InputProtocol: f.GetProtocol(t)," << endl;
+    f_service_ << indent() << "OutputProtocol: f.GetProtocol(t)," << endl;
+    f_service_ << indent() << "SeqId: 0," << endl;
+    /*f_service_ << indent() << "Reqs: make(map[int32]Deferred)" << endl*/;
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+  }
+
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+  // Constructor function
+  f_service_
+      << indent() << "func New" << serviceName
+      << "ClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *"
+      << serviceName << "Client {" << endl;
+  indent_up();
+  f_service_ << indent() << "return &" << serviceName << "Client";
+
+  if (!extends.empty()) {
+    f_service_ << "{" << extends_field << ": " << extends_client_new << "Protocol(t, iprot, oprot)}"
+               << endl;
+  } else {
+    indent_up();
+    f_service_ << "{Transport: t," << endl;
+    f_service_ << indent() << "ProtocolFactory: nil," << endl;
+    f_service_ << indent() << "InputProtocol: iprot," << endl;
+    f_service_ << indent() << "OutputProtocol: oprot," << endl;
+    f_service_ << indent() << "SeqId: 0," << endl;
+    /*f_service_ << indent() << "Reqs: make(map[int32]interface{})" << endl*/;
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+  }
+
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+  // Generate client method implementations
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    string funname = publicize((*f_iter)->get_name());
+    // Open function
+    generate_go_docstring(f_service_, (*f_iter));
+    f_service_ << indent() << "func (p *" << serviceName << "Client) "
+               << function_signature_if(*f_iter, "", true) << " {" << endl;
+    indent_up();
+    /*
+    f_service_ <<
+      indent() << "p.SeqId += 1" << endl;
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ <<
+        indent() << "d := defer.Deferred()" << endl <<
+        indent() << "p.Reqs[p.SeqId] = d" << endl;
+    }
+    */
+    f_service_ << indent() << "if err = p.send" << funname << "(";
+    bool first = true;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+
+      f_service_ << variable_name_to_go_name((*fld_iter)->get_name());
+    }
+
+    f_service_ << "); err != nil { return }" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent() << "return p.recv" << funname << "()" << endl;
+    } else {
+      f_service_ << indent() << "return" << endl;
+    }
+
+    indent_down();
+    f_service_ << indent() << "}" << endl << endl;
+    f_service_ << indent() << "func (p *" << serviceName << "Client) send"
+               << function_signature(*f_iter) << "(err error) {" << endl;
+    indent_up();
+    std::string argsname = publicize((*f_iter)->get_name() + "_args", true);
+    // Serialize the request header
+    f_service_ << indent() << "oprot := p.OutputProtocol" << endl;
+    f_service_ << indent() << "if oprot == nil {" << endl;
+    f_service_ << indent() << "  oprot = p.ProtocolFactory.GetProtocol(p.Transport)" << endl;
+    f_service_ << indent() << "  p.OutputProtocol = oprot" << endl;
+    f_service_ << indent() << "}" << endl;
+    f_service_ << indent() << "p.SeqId++" << endl;
+    f_service_ << indent() << "if err = oprot.WriteMessageBegin(\"" << (*f_iter)->get_name()
+               << "\", " << ((*f_iter)->is_oneway() ? "thrift.ONEWAY" : "thrift.CALL")
+               << ", p.SeqId); err != nil {" << endl;
+    indent_up();
+    f_service_ << indent() << "  return" << endl;
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+    f_service_ << indent() << "args := " << argsname << "{" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << indent() << publicize((*fld_iter)->get_name()) << " : "
+                 << variable_name_to_go_name((*fld_iter)->get_name()) << "," << endl;
+    }
+    f_service_ << indent() << "}" << endl;
+
+    // Write to the stream
+    f_service_ << indent() << "if err = args." << write_method_name_ << "(oprot); err != nil {" << endl;
+    indent_up();
+    f_service_ << indent() << "  return" << endl;
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+    f_service_ << indent() << "if err = oprot.WriteMessageEnd(); err != nil {" << endl;
+    indent_up();
+    f_service_ << indent() << "  return" << endl;
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+    f_service_ << indent() << "return oprot.Flush()" << endl;
+    indent_down();
+    f_service_ << indent() << "}" << endl << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = publicize((*f_iter)->get_name() + "_result", true);
+      // Open function
+      f_service_ << endl << indent() << "func (p *" << serviceName << "Client) recv"
+                 << publicize((*f_iter)->get_name()) << "() (";
+
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "value " << type_to_go_type((*f_iter)->get_returntype()) << ", ";
+      }
+
+      f_service_ << "err error) {" << endl;
+      indent_up();
+      // TODO(mcslee): Validate message reply here, seq ids etc.
+      string error(tmp("error"));
+      string error2(tmp("error"));
+      f_service_ << indent() << "iprot := p.InputProtocol" << endl;
+      f_service_ << indent() << "if iprot == nil {" << endl;
+      f_service_ << indent() << "  iprot = p.ProtocolFactory.GetProtocol(p.Transport)" << endl;
+      f_service_ << indent() << "  p.InputProtocol = iprot" << endl;
+      f_service_ << indent() << "}" << endl;
+      f_service_ << indent() << "method, mTypeId, seqId, err := iprot.ReadMessageBegin()" << endl;
+      f_service_ << indent() << "if err != nil {" << endl;
+      f_service_ << indent() << "  return" << endl;
+      f_service_ << indent() << "}" << endl;
+      f_service_ << indent() << "if method != \"" << (*f_iter)->get_name() << "\" {" << endl;
+      f_service_ << indent() << "  err = thrift.NewTApplicationException("
+                 << "thrift.WRONG_METHOD_NAME, \"" << (*f_iter)->get_name()
+                 << " failed: wrong method name\")" << endl;
+      f_service_ << indent() << "  return" << endl;
+      f_service_ << indent() << "}" << endl;
+      f_service_ << indent() << "if p.SeqId != seqId {" << endl;
+      f_service_ << indent() << "  err = thrift.NewTApplicationException("
+                 << "thrift.BAD_SEQUENCE_ID, \"" << (*f_iter)->get_name()
+                 << " failed: out of sequence response\")" << endl;
+      f_service_ << indent() << "  return" << endl;
+      f_service_ << indent() << "}" << endl;
+      f_service_ << indent() << "if mTypeId == thrift.EXCEPTION {" << endl;
+      f_service_ << indent() << "  " << error
+                 << " := thrift.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, "
+                    "\"Unknown Exception\")" << endl;
+      f_service_ << indent() << "  var " << error2 << " error" << endl;
+      f_service_ << indent() << "  " << error2 << ", err = " << error << "." << read_method_name_ << "(iprot)" << endl;
+      f_service_ << indent() << "  if err != nil {" << endl;
+      f_service_ << indent() << "    return" << endl;
+      f_service_ << indent() << "  }" << endl;
+      f_service_ << indent() << "  if err = iprot.ReadMessageEnd(); err != nil {" << endl;
+      f_service_ << indent() << "    return" << endl;
+      f_service_ << indent() << "  }" << endl;
+      f_service_ << indent() << "  err = " << error2 << endl;
+      f_service_ << indent() << "  return" << endl;
+      f_service_ << indent() << "}" << endl;
+      f_service_ << indent() << "if mTypeId != thrift.REPLY {" << endl;
+      f_service_ << indent() << "  err = thrift.NewTApplicationException("
+                 << "thrift.INVALID_MESSAGE_TYPE_EXCEPTION, \"" << (*f_iter)->get_name()
+                 << " failed: invalid message type\")" << endl;
+      f_service_ << indent() << "  return" << endl;
+      f_service_ << indent() << "}" << endl;
+      f_service_ << indent() << "result := " << resultname << "{}" << endl;
+      f_service_ << indent() << "if err = result." << read_method_name_ << "(iprot); err != nil {" << endl;
+      f_service_ << indent() << "  return" << endl;
+      f_service_ << indent() << "}" << endl;
+      f_service_ << indent() << "if err = iprot.ReadMessageEnd(); err != nil {" << endl;
+      f_service_ << indent() << "  return" << endl;
+      f_service_ << indent() << "}" << endl;
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        const std::string pubname = publicize((*x_iter)->get_name());
+
+        f_service_ << indent() << "if result." << pubname << " != nil {" << endl;
+        f_service_ << indent() << "  err = result." << pubname << endl;
+        f_service_ << indent() << "  return " << endl;
+        f_service_ << indent() << "}";
+
+        if ((x_iter + 1) != xceptions.end()) {
+          f_service_ << " else ";
+        } else {
+          f_service_ << endl;
+        }
+      }
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << indent() << "value = result.GetSuccess()" << endl;
+      }
+
+      f_service_ << indent() << "return" << endl;
+      // Close function
+      indent_down();
+      f_service_ << indent() << "}" << endl << endl;
+    }
+  }
+
+  // indent_down();
+  f_service_ << endl;
+}
+
+/**
+ * Generates a command line tool for making remote requests
+ *
+ * @param tservice The service to generate a remote for.
+ */
+void t_go_generator::generate_service_remote(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  t_service* parent = tservice->get_extends();
+
+  // collect inherited functions
+  while (parent != NULL) {
+    vector<t_function*> p_functions = parent->get_functions();
+    functions.insert(functions.end(), p_functions.begin(), p_functions.end());
+    parent = parent->get_extends();
+  }
+
+  vector<t_function*>::iterator f_iter;
+  string f_remote_name = package_dir_ + "/" + underscore(service_name_) + "-remote/"
+                         + underscore(service_name_) + "-remote.go";
+  ofstream f_remote;
+  f_remote.open(f_remote_name.c_str());
+  string service_module = get_real_go_module(program_);
+  string::size_type loc;
+
+  while ((loc = service_module.find(".")) != string::npos) {
+    service_module.replace(loc, 1, 1, '/');
+  }
+  if (!gen_package_prefix_.empty()) {
+    service_module = gen_package_prefix_ + service_module;
+  }
+
+  f_remote << go_autogen_comment();
+  f_remote << indent() << "package main" << endl << endl;
+  f_remote << indent() << "import (" << endl;
+  f_remote << indent() << "        \"flag\"" << endl;
+  f_remote << indent() << "        \"fmt\"" << endl;
+  f_remote << indent() << "        \"math\"" << endl;
+  f_remote << indent() << "        \"net\"" << endl;
+  f_remote << indent() << "        \"net/url\"" << endl;
+  f_remote << indent() << "        \"os\"" << endl;
+  f_remote << indent() << "        \"strconv\"" << endl;
+  f_remote << indent() << "        \"strings\"" << endl;
+  f_remote << indent() << "        \"" + gen_thrift_import_ + "\"" << endl;
+  f_remote << indent() << "        \"" << service_module << "\"" << endl;
+  f_remote << indent() << ")" << endl;
+  f_remote << indent() << endl;
+  f_remote << indent() << "func Usage() {" << endl;
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Usage of \", os.Args[0], \" "
+                          "[-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:\")"
+           << endl;
+  f_remote << indent() << "  flag.PrintDefaults()" << endl;
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"\\nFunctions:\")" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_remote << "  fmt.Fprintln(os.Stderr, \"  " << (*f_iter)->get_returntype()->get_name() << " "
+             << (*f_iter)->get_name() << "(";
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const std::vector<t_field*>& args = arg_struct->get_members();
+    vector<t_field*>::const_iterator a_iter;
+    std::vector<t_field*>::size_type num_args = args.size();
+    bool first = true;
+
+    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
+      if (first) {
+        first = false;
+      } else {
+        f_remote << ", ";
+      }
+
+      f_remote << args[i]->get_type()->get_name() << " " << args[i]->get_name();
+    }
+
+    f_remote << ")\")" << endl;
+  }
+
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr)" << endl;
+  f_remote << indent() << "  os.Exit(0)" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << endl;
+  f_remote << indent() << "func main() {" << endl;
+  indent_up();
+  f_remote << indent() << "flag.Usage = Usage" << endl;
+  f_remote << indent() << "var host string" << endl;
+  f_remote << indent() << "var port int" << endl;
+  f_remote << indent() << "var protocol string" << endl;
+  f_remote << indent() << "var urlString string" << endl;
+  f_remote << indent() << "var framed bool" << endl;
+  f_remote << indent() << "var useHttp bool" << endl;
+  f_remote << indent() << "var parsedUrl url.URL" << endl;
+  f_remote << indent() << "var trans thrift.TTransport" << endl;
+  f_remote << indent() << "_ = strconv.Atoi" << endl;
+  f_remote << indent() << "_ = math.Abs" << endl;
+  f_remote << indent() << "flag.Usage = Usage" << endl;
+  f_remote << indent() << "flag.StringVar(&host, \"h\", \"localhost\", \"Specify host and port\")"
+           << endl;
+  f_remote << indent() << "flag.IntVar(&port, \"p\", 9090, \"Specify port\")" << endl;
+  f_remote << indent() << "flag.StringVar(&protocol, \"P\", \"binary\", \""
+                          "Specify the protocol (binary, compact, simplejson, json)\")" << endl;
+  f_remote << indent() << "flag.StringVar(&urlString, \"u\", \"\", \"Specify the url\")" << endl;
+  f_remote << indent() << "flag.BoolVar(&framed, \"framed\", false, \"Use framed transport\")"
+           << endl;
+  f_remote << indent() << "flag.BoolVar(&useHttp, \"http\", false, \"Use http\")" << endl;
+  f_remote << indent() << "flag.Parse()" << endl;
+  f_remote << indent() << endl;
+  f_remote << indent() << "if len(urlString) > 0 {" << endl;
+  f_remote << indent() << "  parsedUrl, err := url.Parse(urlString)" << endl;
+  f_remote << indent() << "  if err != nil {" << endl;
+  f_remote << indent() << "    fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << endl;
+  f_remote << indent() << "    flag.Usage()" << endl;
+  f_remote << indent() << "  }" << endl;
+  f_remote << indent() << "  host = parsedUrl.Host" << endl;
+  f_remote << indent() << "  useHttp = len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == \"http\""
+           << endl;
+  f_remote << indent() << "} else if useHttp {" << endl;
+  f_remote << indent() << "  _, err := url.Parse(fmt.Sprint(\"http://\", host, \":\", port))"
+           << endl;
+  f_remote << indent() << "  if err != nil {" << endl;
+  f_remote << indent() << "    fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << endl;
+  f_remote << indent() << "    flag.Usage()" << endl;
+  f_remote << indent() << "  }" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << endl;
+  f_remote << indent() << "cmd := flag.Arg(0)" << endl;
+  f_remote << indent() << "var err error" << endl;
+  f_remote << indent() << "if useHttp {" << endl;
+  f_remote << indent() << "  trans, err = thrift.NewTHttpClient(parsedUrl.String())" << endl;
+  f_remote << indent() << "} else {" << endl;
+  f_remote << indent() << "  portStr := fmt.Sprint(port)" << endl;
+  f_remote << indent() << "  if strings.Contains(host, \":\") {" << endl;
+  f_remote << indent() << "         host, portStr, err = net.SplitHostPort(host)" << endl;
+  f_remote << indent() << "         if err != nil {" << endl;
+  f_remote << indent() << "                 fmt.Fprintln(os.Stderr, \"error with host:\", err)"
+           << endl;
+  f_remote << indent() << "                 os.Exit(1)" << endl;
+  f_remote << indent() << "         }" << endl;
+  f_remote << indent() << "  }" << endl;
+  f_remote << indent() << "  trans, err = thrift.NewTSocket(net.JoinHostPort(host, portStr))"
+           << endl;
+  f_remote << indent() << "  if err != nil {" << endl;
+  f_remote << indent() << "    fmt.Fprintln(os.Stderr, \"error resolving address:\", err)" << endl;
+  f_remote << indent() << "    os.Exit(1)" << endl;
+  f_remote << indent() << "  }" << endl;
+  f_remote << indent() << "  if framed {" << endl;
+  f_remote << indent() << "    trans = thrift.NewTFramedTransport(trans)" << endl;
+  f_remote << indent() << "  }" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << "if err != nil {" << endl;
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Error creating transport\", err)" << endl;
+  f_remote << indent() << "  os.Exit(1)" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << "defer trans.Close()" << endl;
+  f_remote << indent() << "var protocolFactory thrift.TProtocolFactory" << endl;
+  f_remote << indent() << "switch protocol {" << endl;
+  f_remote << indent() << "case \"compact\":" << endl;
+  f_remote << indent() << "  protocolFactory = thrift.NewTCompactProtocolFactory()" << endl;
+  f_remote << indent() << "  break" << endl;
+  f_remote << indent() << "case \"simplejson\":" << endl;
+  f_remote << indent() << "  protocolFactory = thrift.NewTSimpleJSONProtocolFactory()" << endl;
+  f_remote << indent() << "  break" << endl;
+  f_remote << indent() << "case \"json\":" << endl;
+  f_remote << indent() << "  protocolFactory = thrift.NewTJSONProtocolFactory()" << endl;
+  f_remote << indent() << "  break" << endl;
+  f_remote << indent() << "case \"binary\", \"\":" << endl;
+  f_remote << indent() << "  protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()" << endl;
+  f_remote << indent() << "  break" << endl;
+  f_remote << indent() << "default:" << endl;
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Invalid protocol specified: \", protocol)"
+           << endl;
+  f_remote << indent() << "  Usage()" << endl;
+  f_remote << indent() << "  os.Exit(1)" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << "client := " << package_name_ << ".New" << publicize(service_name_)
+           << "ClientFactory(trans, protocolFactory)" << endl;
+  f_remote << indent() << "if err := trans.Open(); err != nil {" << endl;
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Error opening socket to \", "
+                          "host, \":\", port, \" \", err)" << endl;
+  f_remote << indent() << "  os.Exit(1)" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << endl;
+  f_remote << indent() << "switch cmd {" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const std::vector<t_field*>& args = arg_struct->get_members();
+    vector<t_field*>::const_iterator a_iter;
+    std::vector<t_field*>::size_type num_args = args.size();
+    string funcName((*f_iter)->get_name());
+    string pubName(publicize(funcName));
+    string argumentsName(publicize(funcName + "_args", true));
+    f_remote << indent() << "case \"" << escape_string(funcName) << "\":" << endl;
+    indent_up();
+    f_remote << indent() << "if flag.NArg() - 1 != " << num_args << " {" << endl;
+    f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"" << escape_string(pubName) << " requires "
+             << num_args << " args\")" << endl;
+    f_remote << indent() << "  flag.Usage()" << endl;
+    f_remote << indent() << "}" << endl;
+
+    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
+      int flagArg = i + 1;
+      t_type* the_type(args[i]->get_type());
+      t_type* the_type2(get_true_type(the_type));
+
+      if (the_type2->is_enum()) {
+        f_remote << indent() << "tmp" << i << ", err := (strconv.Atoi(flag.Arg(" << flagArg << ")))"
+                 << endl;
+        f_remote << indent() << "if err != nil {" << endl;
+        f_remote << indent() << "  Usage()" << endl;
+        f_remote << indent() << " return" << endl;
+        f_remote << indent() << "}" << endl;
+        f_remote << indent() << "argvalue" << i << " := " << package_name_ << "."
+                 << publicize(the_type->get_name()) << "(tmp" << i << ")" << endl;
+      } else if (the_type2->is_base_type()) {
+        t_base_type::t_base e = ((t_base_type*)the_type2)->get_base();
+        string err(tmp("err"));
+
+        switch (e) {
+        case t_base_type::TYPE_VOID:
+          break;
+
+        case t_base_type::TYPE_STRING:
+          if (((t_base_type*)the_type2)->is_binary()) {
+            f_remote << indent() << "argvalue" << i << " := []byte(flag.Arg(" << flagArg << "))"
+                     << endl;
+          } else {
+            f_remote << indent() << "argvalue" << i << " := flag.Arg(" << flagArg << ")" << endl;
+          }
+          break;
+
+        case t_base_type::TYPE_BOOL:
+          f_remote << indent() << "argvalue" << i << " := flag.Arg(" << flagArg << ") == \"true\""
+                   << endl;
+          break;
+
+        case t_base_type::TYPE_BYTE:
+          f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg("
+                   << flagArg << ")))" << endl;
+          f_remote << indent() << "if " << err << " != nil {" << endl;
+          f_remote << indent() << "  Usage()" << endl;
+          f_remote << indent() << "  return" << endl;
+          f_remote << indent() << "}" << endl;
+          f_remote << indent() << "argvalue" << i << " := byte(tmp" << i << ")" << endl;
+          break;
+
+        case t_base_type::TYPE_I16:
+          f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg("
+                   << flagArg << ")))" << endl;
+          f_remote << indent() << "if " << err << " != nil {" << endl;
+          f_remote << indent() << "  Usage()" << endl;
+          f_remote << indent() << "  return" << endl;
+          f_remote << indent() << "}" << endl;
+          f_remote << indent() << "argvalue" << i << " := byte(tmp" << i << ")" << endl;
+          break;
+
+        case t_base_type::TYPE_I32:
+          f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg("
+                   << flagArg << ")))" << endl;
+          f_remote << indent() << "if " << err << " != nil {" << endl;
+          f_remote << indent() << "  Usage()" << endl;
+          f_remote << indent() << "  return" << endl;
+          f_remote << indent() << "}" << endl;
+          f_remote << indent() << "argvalue" << i << " := int32(tmp" << i << ")" << endl;
+          break;
+
+        case t_base_type::TYPE_I64:
+          f_remote << indent() << "argvalue" << i << ", " << err
+                   << " := (strconv.ParseInt(flag.Arg(" << flagArg << "), 10, 64))" << endl;
+          f_remote << indent() << "if " << err << " != nil {" << endl;
+          f_remote << indent() << "  Usage()" << endl;
+          f_remote << indent() << "  return" << endl;
+          f_remote << indent() << "}" << endl;
+          break;
+
+        case t_base_type::TYPE_DOUBLE:
+          f_remote << indent() << "argvalue" << i << ", " << err
+                   << " := (strconv.ParseFloat(flag.Arg(" << flagArg << "), 64))" << endl;
+          f_remote << indent() << "if " << err << " != nil {" << endl;
+          f_remote << indent() << "  Usage()" << endl;
+          f_remote << indent() << "  return" << endl;
+          f_remote << indent() << "}" << endl;
+          break;
+
+        default:
+          throw("Invalid base type in generate_service_remote");
+        }
+
+        // f_remote << publicize(args[i]->get_name()) << "(strconv.Atoi(flag.Arg(" << flagArg <<
+        // ")))";
+      } else if (the_type2->is_struct()) {
+        string arg(tmp("arg"));
+        string mbTrans(tmp("mbTrans"));
+        string err1(tmp("err"));
+        string factory(tmp("factory"));
+        string jsProt(tmp("jsProt"));
+        string err2(tmp("err"));
+        std::string tstruct_name(publicize(the_type->get_name()));
+        f_remote << indent() << arg << " := flag.Arg(" << flagArg << ")" << endl;
+        f_remote << indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))"
+                 << endl;
+        f_remote << indent() << "d

<TRUNCATED>


Mime
View raw message