[ 
https://issues.apache.org/jira/browse/THRIFT-3773?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15518788#comment-15518788
 ] 

ASF GitHub Bot commented on THRIFT-3773:
----------------------------------------

Github user ChristopherRogers commented on a diff in the pull request:

    https://github.com/apache/thrift/pull/1084#discussion_r80355989
  
    --- Diff: compiler/cpp/src/generate/t_swift_3_generator.cc ---
    @@ -0,0 +1,2458 @@
    +/*
    + * 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.
    + */
    +
    +#include <string>
    +#include <fstream>
    +#include <iostream>
    +#include <vector>
    +#include <set>
    +
    +#include <stdlib.h>
    +#include <sys/stat.h>
    +#include <sstream>
    +#include "t_oop_generator.h"
    +#include "platform.h"
    +
    +using std::map;
    +using std::ostream;
    +using std::ofstream;
    +using std::ostringstream;
    +using std::set;
    +using std::string;
    +using std::stringstream;
    +using std::vector;
    +
    +static const string endl = "\n"; // avoid ostream << std::endl flushes
    +
    +/**
    + * Swift 3 code generator.
    + *
    + * Designed from the Swift/Cocoa code generator(s)
    + */
    +class t_swift_3_generator : public t_oop_generator {
    +public:
    +  t_swift_3_generator(t_program* program,
    +                    const map<string, string>& parsed_options,
    +                    const string& option_string)
    +    : t_oop_generator(program) {
    +    (void)option_string;
    +    map<string, string>::const_iterator iter;
    +
    +    log_unexpected_ = false;
    +    async_clients_ = false;
    +    debug_descriptions_ = false;
    +    no_strict_ = false;
    +
    +    for( iter = parsed_options.begin(); iter != parsed_options.end(); 
++iter) {
    +      if( iter->first.compare("log_unexpected") == 0) {
    +        log_unexpected_ = true;
    +      } else if( iter->first.compare("async_clients") == 0) {
    +        async_clients_ = true;
    +      } else if( iter->first.compare("no_strict") == 0) {
    +        no_strict_ = true;
    +      } else if( iter->first.compare("debug_descriptions") == 0) {
    +        debug_descriptions_ = true;
    +      } else {
    +        throw "unknown option swift:" + iter->first;
    +      }
    +    }
    +
    +    out_dir_base_ = "gen-swift";
    +  }
    +
    +  /**
    +   * Init and close methods
    +   */
    +
    +  void init_generator();
    +  void close_generator();
    +
    +  void generate_consts(vector<t_const*> consts);
    +
    +  /**
    +   * Program-level generation functions
    +   */
    +
    +  void generate_typedef(t_typedef* ttypedef);
    +  void generate_enum(t_enum* tenum);
    +  void generate_struct(t_struct* tstruct);
    +  void generate_xception(t_struct* txception);
    +  void generate_service(t_service* tservice);
    +
    +  void print_const_value(ostream& out,
    +                         string name,
    +                         t_type* type,
    +                         t_const_value* value,
    +                         bool defval = false,
    +                         bool is_property = false);
    +  void render_const_value(ostream& out,
    +                          t_type* type,
    +                          t_const_value* value);
    +
    +  void generate_swift_struct(ofstream& out,
    +                             t_struct* tstruct,
    +                             bool is_private,
    +                             bool is_result);
    +  void generate_swift_struct_init(ofstream& out,
    +                                  t_struct* tstruct,
    +                                  bool all,
    +                                  bool is_private);
    +
    +  void generate_swift_struct_implementation(ofstream& out,
    +                                            t_struct* tstruct,
    +                                            bool is_result,
    +                                            bool is_private);
    +  void generate_swift_struct_hashable_extension(ofstream& out,
    +                                                t_struct* tstruct,
    +                                                bool is_private);
    +  void generate_swift_struct_equatable_extension(ofstream& out,
    +                                                 t_struct* tstruct,
    +                                                 bool is_private);
    +  void generate_swift_struct_thrift_extension(ofstream& out,
    +                                              t_struct* tstruct,
    +                                              bool is_result,
    +                                              bool is_private);
    +  void generate_swift_struct_reader(ofstream& out, t_struct* tstruct, bool 
is_private);
    +  void generate_swift_union_reader(ofstream& out, t_struct* tstruct);
    +
    +  void generate_swift_struct_writer(ofstream& out,t_struct* tstruct, bool 
is_private);
    +  void generate_swift_struct_result_writer(ofstream& out, t_struct* 
tstruct);
    +  void generate_swift_struct_printable_extension(ofstream& out, t_struct* 
tstruct);
    +
    +  string function_result_helper_struct_type(t_service *tservice, 
t_function* tfunction);
    +  string function_args_helper_struct_type(t_service* tservice, t_function* 
tfunction);
    +  void generate_function_helpers(t_service *tservice, t_function* 
tfunction);
    +
    +  /**
    +   * Service-level generation functions
    +   */
    +
    +  void generate_swift_service_protocol(ofstream& out, t_service* tservice);
    +  void generate_swift_service_protocol_async(ofstream& out, t_service* 
tservice);
    +
    +  void generate_swift_service_client(ofstream& out, t_service* tservice);
    +  void generate_swift_service_client_async(ofstream& out, t_service* 
tservice);
    +
    +  void 
generate_swift_service_client_send_function_implementation(ofstream& out,
    +                                                                  
t_service* tservice,
    +                                                                  
t_function* tfunction,
    +                                                                  bool 
needs_protocol);
    +  void generate_swift_service_client_send_function_invocation(ofstream& 
out, t_function* tfunction);
    +  void 
generate_swift_service_client_send_async_function_invocation(ofstream& out,
    +                                                                    
t_function* tfunction);
    +  void 
generate_swift_service_client_recv_function_implementation(ofstream& out,
    +                                                                  
t_service* tservice,
    +                                                                  
t_function* tfunction,
    +                                                                  bool 
needs_protocol);
    +  void generate_swift_service_client_implementation(ofstream& out, 
t_service* tservice);
    +  void generate_swift_service_client_async_implementation(ofstream& out, 
t_service* tservice);
    +
    +  void generate_swift_service_server(ofstream& out, t_service* tservice);
    +  void generate_swift_service_server_implementation(ofstream& out, 
t_service* tservice);
    +  void generate_swift_service_helpers(t_service* tservice);
    +  /**
    +   * Helper rendering functions
    +   */
    +
    +  string swift_imports();
    +  string swift_thrift_imports();
    +  string type_name(t_type* ttype, bool is_optional=false, bool 
is_forced=false);
    +  string base_type_name(t_base_type* tbase);
    +  string declare_property(t_field* tfield, bool is_private);
    +  string function_signature(t_function* tfunction);
    +  string async_function_signature(t_function* tfunction);
    +  string argument_list(t_struct* tstruct, string protocol_name, bool 
is_internal, bool default_val);
    +  string type_to_enum(t_type* ttype, bool qualified=false);
    +  string maybe_escape_identifier(const string& identifier);
    +  string enum_case_name(t_enum_value* tenum_case, bool declaration);
    +  string enum_const_name(string enum_identifier);
    +  void populate_reserved_words();
    +  void generate_docstring(ofstream& out, string& doc);
    +
    +private:
    +
    +  void block_open(ostream& out) {
    +    out << " {" << endl;
    +    indent_up();
    +  }
    +
    +  void block_close(ostream& out, bool end_line=true) {
    +    indent_down();
    +    indent(out) << "}";
    +    if (end_line) out << endl;
    +  }
    +
    +
    +  bool field_is_optional(t_field* tfield) {
    +    return tfield->get_req() == t_field::T_OPTIONAL;
    +  }
    +
    +  bool struct_has_required_fields(t_struct* tstruct) {
    +    const vector<t_field*>& members = tstruct->get_members();
    +    vector<t_field*>::const_iterator m_iter;
    +    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    +      if (!field_is_optional(*m_iter)) {
    +        return true;
    +      }
    +    }
    +    return false;
    +  }
    +
    +  bool struct_has_optional_fields(t_struct* tstruct) {
    +    const vector<t_field*>& members = tstruct->get_members();
    +    vector<t_field*>::const_iterator m_iter;
    +    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    +      if (field_is_optional(*m_iter)) {
    +        return true;
    +      }
    +    }
    +    return false;
    +  }
    +
    +  string constants_declarations_;
    +
    +  /**
    +   * File streams
    +   */
    +
    +  ofstream f_decl_;
    +  ofstream f_impl_;
    +
    +  bool log_unexpected_;
    +  bool async_clients_;
    +  bool debug_descriptions_;
    +  bool no_strict_;
    +
    +  set<string> swift_reserved_words_;
    +};
    +
    +/**
    + * Prepares for file generation by opening up the necessary file output
    + * streams.
    + */
    +void t_swift_3_generator::init_generator() {
    +  // Make output directory
    +  MKDIR(get_out_dir().c_str());
    +
    +  populate_reserved_words();
    +
    +  // we have a .swift declarations file...
    +  string f_decl_name = capitalize(program_name_) + ".swift";
    +  string f_decl_fullname = get_out_dir() + f_decl_name;
    +  f_decl_.open(f_decl_fullname.c_str());
    +
    +  f_decl_ << autogen_comment() << endl;
    +
    +  f_decl_ << swift_imports() << swift_thrift_imports() << endl;
    +
    +  // ...and a .swift implementation extensions file
    +  string f_impl_name = capitalize(program_name_) + "+Exts.swift";
    +  string f_impl_fullname = get_out_dir() + f_impl_name;
    +  f_impl_.open(f_impl_fullname.c_str());
    +
    +  f_impl_ << autogen_comment() << endl;
    +
    +  f_impl_ << swift_imports() << swift_thrift_imports() << 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
    + */
    +void t_swift_3_generator::print_const_value(ostream& out,
    +                                            string name,
    +                                            t_type* type,
    +                                            t_const_value* value,
    +                                            bool defval,
    +                                            bool is_property) {
    +  // type = get_true_type(type);
    +
    +  // if (type->is_base_type()) {
    +  //   string v2 = render_const_value(out, type, value);
    +  //   indent(out);
    +  //   if (defval)
    +  //     out << type_name(type) << " ";
    +  //   out << name << " = " << v2 << ";" << endl << endl;
    +  // } else if (type->is_enum()) {
    +  //   indent(out);
    +  //   if (defval)
    +  //     out << type_name(type) << " ";
    +  //   out << name << " = " << render_const_value(out, type, value) << ";" 
<< endl << endl;
    +  // } else if (type->is_struct() || type->is_xception()) {
    +  //   indent(out);
    +  //   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;
    +  //   if (defval)
    +  //     out << type_name(type) << " ";
    +  //   out << name << " = [" << type_name(type, true) << " new];"
    +  //       << endl;
    +  //   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();
    +  //     }
    +  //     string val = render_const_value(out, field_type, v_iter->second);
    +  //     std::string cap_name = capitalize(v_iter->first->get_string());
    +  //     indent(out) << "[" << name << " set" << cap_name << ":" << val << 
"];" << endl;
    +  //   }
    +  // } else if (type->is_map()) {
    +  //   ostringstream mapout;
    +  //   indent(mapout);
    +  //   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();
    +  //   map<t_const_value*, t_const_value*>::const_iterator v_iter;
    +  //   if (defval)
    +  //     mapout << type_name(type) << " ";
    +  //   mapout << name << " = @{";
    +  //   for (v_iter = val.begin(); v_iter != val.end();) {
    +  //     mapout << render_const_value(out, ktype, v_iter->first, true) << 
": "
    +  //         << render_const_value(out, vtype, v_iter->second, true);
    +  //     if (++v_iter != val.end()) {
    +  //       mapout << ", ";
    +  //     }
    +  //   }
    +  //   mapout << "}";
    +  //   out << mapout.str();
    +  // } else if (type->is_list()) {
    +  //   ostringstream listout;
    +  //   indent(listout);
    +  //   t_type* etype = ((t_list*)type)->get_elem_type();
    +  //   const vector<t_const_value*>& val = value->get_list();
    +  //   vector<t_const_value*>::const_iterator v_iter;
    +  //   if (defval)
    +  //     listout << type_name(type) << " ";
    +  //   listout << name << " = @[";
    +  //   for (v_iter = val.begin(); v_iter != val.end();) {
    +  //     listout << render_const_value(out, etype, *v_iter, true);
    +  //     if (++v_iter != val.end()) {
    +  //       listout << ", ";
    +  //     }
    +  //   }
    +  //   listout << "]";
    +  //   out << listout.str();
    +  // } else if (type->is_set()) {
    +  //   ostringstream setout;
    +  //   indent(setout);
    +  //   t_type* etype = ((t_set*)type)->get_elem_type();
    +  //   const vector<t_const_value*>& val = value->get_list();
    +  //   vector<t_const_value*>::const_iterator v_iter;
    +  //   if (defval)
    +  //     setout << type_name(type) << " ";
    +  //   setout << name << " = [NSSet setWithArray:@[";
    +  //   for (v_iter = val.begin(); v_iter != val.end();) {
    +  //     setout << render_const_value(out, etype, *v_iter, true);
    +  //     if (++v_iter != val.end()) {
    +  //       setout << ", ";
    +  //     }
    +  //   }
    +  //   setout << "]]";
    +  //   out << setout.str();
    +  // } else {
    +  //   throw "compiler error: no const of type " + type->get_name();
    +  // }
    +}
    +
    +/**
    + * Prints standard Cocoa imports
    + *
    + * @return List of imports for Cocoa libraries
    + */
    +string t_swift_3_generator::swift_imports() {
    +
    +  vector<string> includes_list;
    +  includes_list.push_back("Foundation");
    +
    +  ostringstream includes;
    +
    +  vector<string>::const_iterator i_iter;
    +  for (i_iter=includes_list.begin(); i_iter!=includes_list.end(); 
++i_iter) {
    +    includes << "import " << *i_iter << endl;
    +  }
    +
    +  includes << endl;
    +
    +  return includes.str();
    +}
    +
    +/**
    + * Prints Thrift runtime imports
    + *
    + * @return List of imports necessary for Thrift runtime
    + */
    +string t_swift_3_generator::swift_thrift_imports() {
    +
    +  vector<string> includes_list;
    +  includes_list.push_back("Thrift");
    +
    +  ostringstream includes;
    +
    +  vector<string>::const_iterator i_iter;
    +  for (i_iter=includes_list.begin(); i_iter!=includes_list.end(); 
++i_iter) {
    +    includes << "import " << *i_iter << endl;
    +  }
    +
    +  includes << endl;
    +
    +  return includes.str();
    +}
    +
    +/**
    + * Finish up generation.
    + */
    +void t_swift_3_generator::close_generator() {
    +  // stick our constants declarations at the end of the header file
    +  // since they refer to things we are defining.
    +  f_decl_ << constants_declarations_ << endl;
    +}
    +
    +/**
    + * Generates a typedef. This is just a simple 1-liner in Swift
    + *
    + * @param ttypedef The type definition
    + */
    +void t_swift_3_generator::generate_typedef(t_typedef* ttypedef) {
    +  f_decl_ << indent() << "public typealias " << ttypedef->get_symbolic()
    +          << " = " << type_name(ttypedef->get_type()) << endl;
    +  f_decl_ << endl;
    +}
    +
    +
    +/**
    + * Generates code for an enumerated type. In Swift, this is
    + * essentially the same as the thrift definition itself, using
    + * Swift syntax.  Conforms to TEnum which
    + * implementes read/write.
    + *
    + * @param tenum The enumeration
    + */
    +void t_swift_3_generator::generate_enum(t_enum* tenum) {
    +  f_decl_ << indent() << "public enum " << tenum->get_name() << " : Int32, 
TEnum";
    +  block_open(f_decl_);
    +
    +  vector<t_enum_value*> constants = tenum->get_constants();
    +  vector<t_enum_value*>::iterator c_iter;
    +
    +  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
    +    f_decl_ << indent() << "case " << enum_case_name((*c_iter), true)
    +            << " = " << (*c_iter)->get_value() << endl;
    +  }
    +
    +  f_decl_ << endl;
    +  f_decl_ << indent() << "public init()";
    +  block_open(f_decl_);
    +
    +  f_decl_ << indent() << "self = ." << enum_case_name(constants.front(), 
false) << endl;
    +  block_close(f_decl_);
    +
    +  block_close(f_decl_);
    +  f_decl_ << endl;
    +}
    +
    +string t_swift_3_generator::enum_case_name(t_enum_value* tenum_case, bool 
declaration) {
    +  string name = tenum_case->get_name();
    +  // force to lowercase for Swift style, maybe escape if its a keyword
    +  std::transform(name.begin(), name.end(), name.begin(), ::tolower);
    +  if (declaration) {
    +    name = maybe_escape_identifier(name);
    +  }
    +  return name;
    +}
    +
    +/**
    + * Renders a constant enum value by transforming the value portion to 
lowercase
    + * for Swift style.
    + */
    +string t_swift_3_generator::enum_const_name(string enum_identifier) {
    +  string::iterator it;
    +  for (it = enum_identifier.begin(); it < enum_identifier.end(); ++it) {
    +    if ((*it) == '.') {
    +      break;
    +    }
    +  }
    +  std::transform(it, enum_identifier.end(), it, ::tolower);
    +  return enum_identifier;
    +}
    +
    +/**
    + * Generates public constants for all Thrift constants.
    + *
    + * @param consts Constants to generate
    + */
    +void t_swift_3_generator::generate_consts(vector<t_const*> consts) {
    +
    +  ostringstream const_interface;
    +
    +  // Public constants for base types & strings
    +  vector<t_const*>::iterator c_iter;
    +  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
    +    t_type* type = (*c_iter)->get_type();
    +    const_interface << "public let " << capitalize((*c_iter)->get_name()) 
<< " : " << type_name(type) << " = ";
    +    render_const_value(const_interface, type, (*c_iter)->get_value());
    +    const_interface << endl << endl;
    +  }
    +
    +  // this gets spit into the header file in ::close_generator
    +  constants_declarations_ = const_interface.str();
    +
    +}
    +
    +/**
    + * Generates a struct definition for a thrift data type. This is a struct
    + * with public members. Optional types are used for optional properties to
    + * allow them to be tested for availability. Separate inits are included 
for
    + * required properties & all properties.
    + *
    + * Generates extensions to provide conformance to TStruct, TSerializable,
    + * Hashable & Equatable
    + *
    + * @param tstruct The struct definition
    + */
    +void t_swift_3_generator::generate_struct(t_struct* tstruct) {
    +  generate_swift_struct(f_decl_, tstruct, false, false);
    +  generate_swift_struct_implementation(f_impl_, tstruct, false, false);
    +}
    +
    +/**
    + * Exceptions are structs, but they conform to Error
    + *
    + * @param tstruct The struct definition
    + */
    +void t_swift_3_generator::generate_xception(t_struct* txception) {
    +  generate_swift_struct(f_decl_, txception, false, false);
    +  generate_swift_struct_implementation(f_impl_, txception, false, false);
    +}
    +
    +void t_swift_3_generator::generate_docstring(ofstream& out,
    +                                             string& doc) {
    +  if (doc != "") {
    +    std::vector<std::string> strings;
    +
    +    std::string::size_type pos = 0;
    +    std::string::size_type prev = 0;
    +    while ((pos = doc.find("\n", prev)) != std::string::npos)
    +    {
    +        strings.push_back(doc.substr(prev, pos - prev));
    +        prev = pos + 1;
    +    }
    +
    +    // To get the last substring (or only, if delimiter is not found)
    +    strings.push_back(doc.substr(prev));
    +
    +    vector<string>::const_iterator d_iter;
    +    for (d_iter = strings.begin(); d_iter != strings.end(); ++d_iter) {
    +      out << indent() << "/// " << (*d_iter) << endl;
    +    }
    +  }
    +}
    +
    +
    +
    +/**
    + * Generate the interface for a struct. Only properties and
    + * init methods are included.
    + *
    + * @param tstruct The struct definition
    + * @param is_private
    + *                Is the struct public or private
    + */
    +void t_swift_3_generator::generate_swift_struct(ofstream& out,
    +                                              t_struct* tstruct,
    +                                              bool is_private,
    +                                              bool is_result) {
    +
    +
    +  string doc = tstruct->get_doc();
    +  if (doc != "") {
    +    std::vector<std::string> strings;
    +
    +    std::string::size_type pos = 0;
    +    std::string::size_type prev = 0;
    +    while ((pos = doc.find("\n", prev)) != std::string::npos)
    +    {
    +        strings.push_back(doc.substr(prev, pos - prev));
    +        prev = pos + 1;
    +    }
    +
    +    // To get the last substring (or only, if delimiter is not found)
    +    strings.push_back(doc.substr(prev));
    +
    +    vector<string>::const_iterator d_iter;
    +    for (d_iter = strings.begin(); d_iter != strings.end(); ++d_iter) {
    +      out << "/// " << (*d_iter) << endl;
    +    }
    +  }
    +
    +  // properties
    +  const vector<t_field*>& members = tstruct->get_members();
    +  vector<t_field*>::const_iterator m_iter;
    +
    +
    +  if (tstruct->is_union()) {
    +    // special, unions
    +    out << indent() << "public enum " << tstruct->get_name();
    +    block_open(out);
    +    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    +      out << endl;
    +      // TODO: Defaults
    +      // add swift docstring if available
    +      string doc = (*m_iter)->get_doc();
    +      if (doc != "") {
    +        out << indent() << "/// " << doc;
    +      }
    +      out << indent() << "case "
    +          << maybe_escape_identifier((*m_iter)->get_name()) << "(val: "
    +          << type_name((*m_iter)->get_type(), false) << ")" << endl;
    +    }
    +  } else {
    +    // Normal structs
    +
    +    string visibility = is_private ? "fileprivate" : "public";
    +
    +    out << indent() << visibility << " final class " << 
tstruct->get_name();
    +
    +    if (tstruct->is_xception()) {
    +      out << " : Swift.Error"; // Error seems to be a common exception 
name in thrift
    +    }
    +
    +    block_open(out);
    +    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    +      out << endl;
    +      // TODO: Defaults
    +      // add swift docstring if available
    +      string doc = (*m_iter)->get_doc();
    +      if (doc != "") {
    +        out << indent() << "/// " << doc;
    +      }
    +      out << indent() << declare_property(*m_iter, is_private) << endl;
    +    }
    +
    +    out << endl;
    +
    +    // init TODO: Remove, no need for generic init
    +
    +    // indent(out) << visibility << " init() { }" << endl;
    +
    +    out << endl;
    +    if (!struct_has_required_fields(tstruct)) {
    +      indent(out) << visibility << " init() { }" << endl;
    +    }
    +    if (struct_has_required_fields(tstruct)) {
    +      generate_swift_struct_init(out, tstruct, false, is_private);
    +    }
    +    if (struct_has_optional_fields(tstruct)) {
    +      generate_swift_struct_init(out, tstruct, true, is_private);
    +    }
    +  }
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generate struct init for properties
    + *
    + * @param tstruct The structure definition
    + * @param all     Generate init with all or just required properties
    + * @param is_private
    + *                Is the initializer public or private
    + */
    +void t_swift_3_generator::generate_swift_struct_init(ofstream& out,
    +                                                   t_struct* tstruct,
    +                                                   bool all,
    +                                                   bool is_private) {
    +
    +  string visibility = is_private ? "fileprivate" : "public";
    +
    +  indent(out) << visibility << " init(";
    +
    +  const vector<t_field*>& members = tstruct->get_members();
    +  vector<t_field*>::const_iterator m_iter;
    +
    +  bool first=true;
    +  for (m_iter = members.begin(); m_iter != members.end();) {
    +    if (all || !field_is_optional(*m_iter)) {
    +      if (first) {
    +        first = false;
    +      }
    +      else {
    +        out << ", ";
    +      }
    +      out << (*m_iter)->get_name() << ": "
    +          << maybe_escape_identifier(type_name((*m_iter)->get_type(), 
field_is_optional(*m_iter)));
    +    }
    +    ++m_iter;
    +  }
    +  out << ")";
    +
    +  block_open(out);
    +
    +  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    +    if (all || (*m_iter)->get_req() == t_field::T_REQUIRED || 
(*m_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
    +      out << indent() << "self." << 
maybe_escape_identifier((*m_iter)->get_name()) << " = "
    +          << maybe_escape_identifier((*m_iter)->get_name()) << endl;
    +    }
    +  }
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generate the hashable protocol implmentation
    + *
    + * @param tstruct The structure definition
    + * @param is_private
    + *                Is the struct public or private
    + */
    +void 
t_swift_3_generator::generate_swift_struct_hashable_extension(ofstream& out,
    +                                                                 t_struct* 
tstruct,
    +                                                                 bool 
is_private) {
    +
    +  string visibility = is_private ? "fileprivate" : "public";
    +
    +  indent(out) << "extension " << tstruct->get_name() << " : Hashable";
    +
    +  block_open(out);
    +
    +  out << endl;
    +
    +  indent(out) << visibility << " var hashValue : Int";
    +
    +  block_open(out);
    +
    +  const vector<t_field*>& members = tstruct->get_members();
    +  vector<t_field*>::const_iterator m_iter;
    +
    +  if (!members.empty()) {
    +    indent(out) << "let prime = 31" << endl;
    +    indent(out) << "var result = 1" << endl;
    +    if (!tstruct->is_union()) {
    +      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    +        t_field* tfield = *m_iter;
    +        string accessor = field_is_optional(tfield) ? "?." : ".";
    +        string defaultor = field_is_optional(tfield) ? " ?? 0" : "";
    +        indent(out) << "result = prime &* result &+ (" << 
maybe_escape_identifier(tfield->get_name()) << accessor
    +                    <<  "hashValue" << defaultor << ")" << endl;
    +      }
    +    } else {
    +      indent(out) << "switch self {" << endl;
    +      for (m_iter = members.begin(); m_iter != members.end(); m_iter++) {
    +        t_field *tfield = *m_iter;
    +        indent(out) << "case ." << tfield->get_name() << "(let val): 
result = prime &* val.hashValue" << endl;
    +      }
    +      indent(out) << "}" << endl << endl;
    +    }
    +
    +
    +    indent(out) << "return result" << endl;
    +  }
    +  else {
    +    indent(out) << "return 31" << endl;
    +  }
    +
    +  block_close(out);
    +
    +  out << endl;
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generate the equatable protocol implementation
    + *
    + * @param tstruct The structure definition
    + * @param is_private
    + *                Is the struct public or private
    + */
    +void 
t_swift_3_generator::generate_swift_struct_equatable_extension(ofstream& out,
    +                                                                  
t_struct* tstruct,
    +                                                                  bool 
is_private) {
    +
    +  string visibility = is_private ? "fileprivate" : "public";
    +
    +  indent(out) << visibility << " func ==(lhs: " << type_name(tstruct) << 
", rhs: " << type_name(tstruct) << ") -> Bool";
    +
    +  block_open(out);
    +
    +  indent(out) << "return";
    +
    +  const vector<t_field*>& members = tstruct->get_members();
    +  vector<t_field*>::const_iterator m_iter;
    +
    +  if (members.size()) {
    +    if (!tstruct->is_union()) {
    +      out << endl;
    +      indent_up();
    +
    +      for (m_iter = members.begin(); m_iter != members.end();) {
    +        t_field* tfield = *m_iter;
    +        indent(out) << "(lhs." << 
maybe_escape_identifier(tfield->get_name())
    +                    << " == rhs." << 
maybe_escape_identifier(tfield->get_name()) << ")";
    +        if (++m_iter != members.end()) {
    +          out << " &&";
    +        }
    +        out << endl;
    +      }
    +
    +      indent_down();
    +    } else {
    +      block_open(out);
    +      indent(out) << "switch (lhs, rhs) {" << endl;
    +      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    +        t_field* tfield = *m_iter;
    +        indent(out) << "case (." << tfield->get_name() << "(let lval), ."
    +                    << tfield->get_name() << "(let rval)): return lval == 
rval"
    +                    << endl;
    +      }
    +      indent(out) << "default: return false" << endl;
    +      indent(out) << "}" << endl;
    +      indent_down();
    +      indent(out) << "}()" << endl;
    +    }
    +
    +  }
    +  else {
    +    out << " true" << endl;
    +  }
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generate struct implementation. Produces extensions that
    + * fulfill the requisite protocols to complete the value.
    + *
    + * @param tstruct The struct definition
    + * @param is_result
    + *                If this is a result it needs a different writer
    + * @param is_private
    + *                Is the struct public or private
    + */
    +void t_swift_3_generator::generate_swift_struct_implementation(ofstream& 
out,
    +                                                             t_struct* 
tstruct,
    +                                                             bool 
is_result,
    +                                                             bool 
is_private) {
    +
    +  generate_swift_struct_equatable_extension(out, tstruct, is_private);
    +
    +  if (!is_private && !is_result) {
    +    generate_swift_struct_printable_extension(out, tstruct);
    +  }
    +
    +  generate_swift_struct_hashable_extension(out, tstruct, is_private);
    +  generate_swift_struct_thrift_extension(out, tstruct, is_result, 
is_private);
    +
    +  out << endl << endl;
    +}
    +
    +
    +/**
    + * Generate the TStruct protocol implementation.
    + *
    + * @param tstruct The structure definition
    + * @param is_result
    + *                Is the struct a result value
    + * @param is_private
    + *                Is the struct public or private
    + */
    +void t_swift_3_generator::generate_swift_struct_thrift_extension(ofstream& 
out,
    +                                                               t_struct* 
tstruct,
    +                                                               bool 
is_result,
    +                                                               bool 
is_private) {
    +
    +  indent(out) << "extension " << tstruct->get_name() << " : TStruct";
    +
    +  block_open(out);
    +
    +  out << endl;
    +
    +  string access = (is_private) ? "fileprivate" : "public";
    +  // generate fieldID's dictionary
    +  out << indent() << access << " static var fieldIds: [String: Int32]";
    +  block_open(out);
    +  out << indent() << "return [";
    +  const vector<t_field*>& fields = tstruct->get_members();
    +  vector<t_field*>::const_iterator f_iter;
    +  bool wrote = false;
    +  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    +    wrote = true;
    +    out << "\"" << (*f_iter)->get_name() << "\": " << (*f_iter)->get_key() 
<< ", ";
    +  }
    +  if (!wrote) {
    +    // pad a colon
    +    out << ":";
    +  }
    +  out << "]" << endl;
    +  block_close(out);
    +  out << endl;
    +  out << indent() << access << " static var structName: String { return \""
    +      << tstruct->get_name() << "\" }" << endl << endl;
    +
    +
    +  if (tstruct->is_union()) {
    +    generate_swift_union_reader(out, tstruct);
    +  } else {
    +    generate_swift_struct_reader(out, tstruct, is_private);
    +  }
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +void t_swift_3_generator::generate_swift_union_reader(ofstream& out,
    +                                                     t_struct* tstruct) {
    +  indent(out) << "public static func read(from proto: TProtocol) throws -> 
"
    +              << tstruct->get_name();
    +  block_open(out);
    +  indent(out) << "_ = try proto.readStructBegin()" << endl;
    +
    +  indent(out) << "var ret: " << tstruct->get_name() << "?";
    +  out << endl;
    +  indent(out) << "fields: while true";
    +  block_open(out);
    +  out << endl;
    +  indent(out) << "let (_, fieldType, fieldID) = try 
proto.readFieldBegin()" << endl << endl;
    +  indent(out) << "switch (fieldID, fieldType)";
    +  block_open(out);
    +  indent(out) << "case (_, .stop):            break fields" << endl;
    +
    +  const vector<t_field*>& fields = tstruct->get_members();
    +  vector<t_field*>::const_iterator f_iter;
    +  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    +    indent(out) << "case (" << (*f_iter)->get_key() << ", " << 
type_to_enum((*f_iter)->get_type()) << "):";// << endl;
    +    string padding = "";
    +
    +    t_type* type = get_true_type((*f_iter)->get_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_STRING:
    +        case t_base_type::TYPE_DOUBLE:
    +          padding = "           ";
    +          break;
    +
    +        case t_base_type::TYPE_BOOL:
    +        case t_base_type::TYPE_I8:
    +          padding = "            ";
    +          break;
    +        case t_base_type::TYPE_I16:
    +        case t_base_type::TYPE_I32:
    +        case t_base_type::TYPE_I64:
    +          padding = "             ";
    +          break;
    +        default: break;
    +      }
    +    } else if (type->is_enum() || type->is_set() || type->is_map()) {
    +      padding = "             ";
    +    } else if (type->is_struct() || type->is_xception()) {
    +      padding = "           ";
    +    } else if (type->is_list()) {
    +      padding = "            ";
    +    }
    +
    +    // indent_up();
    +    indent(out) << padding << "ret = " << tstruct->get_name() << "."
    +                << (*f_iter)->get_name() << "(val: " << "try "
    +                << type_name((*f_iter)->get_type(), false, false)
    +                << ".read(from: proto))" << endl;
    +  }
    +
    +  indent(out) << "case let (_, unknownType):  try proto.skip(type: 
unknownType)" << endl;
    +
    +  block_close(out);
    +  indent(out) << "try proto.readFieldEnd()" << endl;
    +
    +  block_close(out);
    +  out << endl;
    +  indent(out) << "if let ret = ret";
    +  block_open(out);
    +  indent(out) << "return ret" << endl;
    +  block_close(out);
    +  out << endl;
    +  indent(out) << "throw TProtocolError(error: .unknown, message: \"Missing 
required value for type: "
    +              << tstruct->get_name() << "\")";
    +  block_close(out);
    +  out << endl;
    +
    +}
    +
    +/**
    + * Generates a function to read a struct from
    + * from a protocol. (TStruct compliance)
    + *
    + * @param tstruct The structure definition
    + * @param is_private
    + *                Is the struct public or private
    + */
    +void t_swift_3_generator::generate_swift_struct_reader(ofstream& out,
    +                                                     t_struct* tstruct,
    +                                                     bool is_private) {
    +
    +
    +  string visibility = is_private ? "fileprivate" : "public";
    +
    +  indent(out) << visibility << " static func read(from proto: TProtocol) 
throws -> "
    +              << tstruct->get_name();
    +
    +  block_open(out);
    +
    +  indent(out) << "_ = try proto.readStructBegin()" << endl;
    +
    +  const vector<t_field*>& fields = tstruct->get_members();
    +  vector<t_field*>::const_iterator f_iter;
    +
    +  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    +    bool optional = field_is_optional(*f_iter);
    +    indent(out) << "var " << 
maybe_escape_identifier((*f_iter)->get_name()) << ": "
    +                << type_name((*f_iter)->get_type(), optional, !optional) 
<< endl;
    +  }
    +
    +  out << endl;
    +
    +  // Loop over reading in fields
    +  indent(out) << "fields: while true";
    +
    +  block_open(out);
    +
    +  out << endl;
    +
    +  indent(out) << "let (_, fieldType, fieldID) = try 
proto.readFieldBegin()" << endl << endl;
    +  indent(out) << "switch (fieldID, fieldType)";
    +
    +  block_open(out);
    +
    +  indent(out) << "case (_, .stop):            break fields" << endl;
    +  // indent_up();
    +  // indent(out) << "break fields" << endl << endl;
    +  // indent_down();
    +
    +  // Generate deserialization code for known cases
    +  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    +    bool optional = field_is_optional(*f_iter);
    +    indent(out) << "case (" << (*f_iter)->get_key() << ", " << 
type_to_enum((*f_iter)->get_type()) << "):";// << endl;
    +    string padding = "";
    +
    +    t_type* type = get_true_type((*f_iter)->get_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_STRING:
    +        case t_base_type::TYPE_DOUBLE:
    +          padding = "           ";
    +          break;
    +
    +        case t_base_type::TYPE_BOOL:
    +        case t_base_type::TYPE_I8:
    +          padding = "            ";
    +          break;
    +        case t_base_type::TYPE_I16:
    +        case t_base_type::TYPE_I32:
    +        case t_base_type::TYPE_I64:
    +          padding = "             ";
    +          break;
    +        default: break;
    +      }
    +    } else if (type->is_enum() || type->is_set() || type->is_map()) {
    +      padding = "             ";
    +    } else if (type->is_struct() || type->is_xception()) {
    +      padding = "           ";
    +    } else if (type->is_list()) {
    +      padding = "            ";
    +    }
    +
    +    // indent_up();
    +    out << padding << maybe_escape_identifier((*f_iter)->get_name()) << " 
= try "
    +        << type_name((*f_iter)->get_type(), false, false) << ".read(from: 
proto)" << endl;
    +    // indent(out) << maybe_escape_identifier((*f_iter)->get_name()) << " 
= try proto.read() as "
    +    //             << type_name((*f_iter)->get_type()) << endl << endl;
    +    // indent_down();
    +
    +  }
    +
    +  indent(out) << "case let (_, unknownType):  try proto.skip(type: 
unknownType)" << endl;
    +
    +  block_close(out);
    +
    +  out << endl;
    +
    +  // Read field end marker
    +  indent(out) << "try proto.readFieldEnd()" << endl;
    +
    +  block_close(out);
    +
    +  out << endl;
    +
    +  indent(out) << "try proto.readStructEnd()" << endl;
    +
    +  if (struct_has_required_fields(tstruct)) {
    +    // performs various checks (e.g. check that all required fields are 
set)
    +    indent(out) << "// Required fields" << endl;
    +
    +    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    +      if (field_is_optional(*f_iter)) {
    +        continue;
    +      }
    +      indent(out) << "try proto.validateValue(" << (*f_iter)->get_name() 
<< ", "
    +                  << "named: \"" << (*f_iter)->get_name() << "\")" << endl;
    +    }
    +  }
    +
    +  out << endl;
    +
    +  indent(out) << "return " << tstruct->get_name() << "(";
    +  for (f_iter = fields.begin(); f_iter != fields.end();) {
    +    out << (*f_iter)->get_name() << ": " << 
maybe_escape_identifier((*f_iter)->get_name());
    +    if (++f_iter != fields.end()) {
    +      out << ", ";
    +    }
    +  }
    +  out << ")" << endl;
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generates a function to write a struct to
    + * a protocol. (TStruct compliance)
    + *
    + * @param tstruct The structure definition
    + * @param is_private
    + *                Is the struct public or private
    + */
    +// DEPRECATED: Handled in Library
    +// void t_swift_3_generator::generate_swift_struct_writer(ofstream& out,
    +//                                                      t_struct* tstruct,
    +//                                                      bool is_private) {
    +
    +//   string visibility = is_private ? "private" : "public";
    +
    +//   indent(out) << visibility << " func write(to proto: TProtocol) 
throws";
    +
    +//   block_open(out);
    +
    +//   out << endl;
    +
    +//   string name = tstruct->get_name();
    +//   const vector<t_field*>& fields = tstruct->get_members();
    +//   vector<t_field*>::const_iterator f_iter;
    +
    +//   indent(out) << "try proto.writeStructBegin(name: \"" << name << "\")" 
<< endl;
    +
    +//   out << endl;
    +
    +//   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    +//     t_field *tfield = *f_iter;
    +
    +//     bool optional = field_is_optional(tfield);
    +//     if (optional) {
    +//       indent(out) << "if let " << 
maybe_escape_identifier(tfield->get_name())
    +//                   << " = __value." << 
maybe_escape_identifier(tfield->get_name());
    +//       block_open(out);
    +//     }
    +
    +//     indent(out) << "try proto.writeFieldValue("
    +//                 << (optional ? "" : "__value.") << 
maybe_escape_identifier(tfield->get_name()) << ", "
    +//                 << "name: \"" << tfield->get_name() << "\", "
    +//                 << "type: " << type_to_enum(tfield->get_type()) << ", "
    +//                 << "id: " << tfield->get_key() << ")" << endl;
    +
    +//     if (optional) {
    +//       block_close(out);
    +//     }
    +
    +//     out << endl;
    +//   }
    +
    +//   indent(out) << "try __proto.writeFieldStop()" << endl << endl;
    +
    +//   indent(out) << "try __proto.writeStructEnd()" << endl;
    +
    +//   block_close(out);
    +
    +//   out << endl;
    +// }
    +
    +/**
    + * Generates a function to read a struct from
    + * from a protocol. (TStruct compliance)
    + *
    + * This is specifically a function result. Only
    + * the first available field is written.
    + *
    + * @param tstruct The structure definition
    + */
    +// DEPRECATED: Handled in library
    +// void t_swift_3_generator::generate_swift_struct_result_writer(ofstream& 
out, t_struct* tstruct) {
    +
    +//   indent(out) << "private static func writeValue(__value: " << 
tstruct->get_name() << ", toProtocol __proto: TProtocol) throws";
    +
    +//   block_open(out);
    +
    +//   out << endl;
    +
    +//   string name = tstruct->get_name();
    +//   const vector<t_field*>& fields = tstruct->get_members();
    +//   vector<t_field*>::const_iterator f_iter;
    +
    +//   indent(out) << "try __proto.writeStructBeginWithName(\"" << name << 
"\")" << endl;
    +
    +//   out << endl;
    +
    +//   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    +//     t_field *tfield = *f_iter;
    +
    +//     indent(out) << "if let result = __value." << (*f_iter)->get_name();
    +
    +//     block_open(out);
    +
    +//     indent(out) << "try __proto.writeFieldValue(result, "
    +//                 << "name: \"" << tfield->get_name() << "\", "
    +//                 << "type: " << type_to_enum(tfield->get_type()) << ", "
    +//                 << "id: " << tfield->get_key() << ")" << endl;
    +
    +//     block_close(out);
    +//   }
    +//   // Write the struct map
    +//   indent(out) << "try __proto.writeFieldStop()" << endl << endl;
    +
    +//   indent(out) << "try __proto.writeStructEnd()" << endl;
    +
    +//   block_close(out);
    +
    +//   out << endl;
    +// }
    +
    +/**
    + * Generates a description method for the given struct
    + *
    + * @param tstruct The struct definition
    + */
    +void 
t_swift_3_generator::generate_swift_struct_printable_extension(ofstream& out, 
t_struct* tstruct) {
    +
    +  // Allow use of debugDescription so the app can add description via a 
cateogory/extension
    +
    +  const vector<t_field*>& fields = tstruct->get_members();
    +  vector<t_field*>::const_iterator f_iter;
    +
    +  indent(out) << "extension " << tstruct->get_name() << " : "
    +              << (debug_descriptions_ ? "CustomDebugStringConvertible" : 
"CustomStringConvertible");
    +
    +  block_open(out);
    +
    +  out << endl;
    +
    +  indent(out) << "public var description : String";
    +
    +  block_open(out);
    +
    +  indent(out) << "var desc = \"" << tstruct->get_name();
    +
    +  if (!tstruct->is_union()) {
    +    out << "(\"" << endl;
    +    for (f_iter = fields.begin(); f_iter != fields.end();) {
    +      indent(out) << "desc += \"" << (*f_iter)->get_name()
    +                  << "=\\(self." << 
maybe_escape_identifier((*f_iter)->get_name()) << ")";
    +      if (++f_iter != fields.end()) {
    +        out << ", ";
    +      }
    +      out << "\"" << endl;
    +    }
    +  } else {
    +    out << ".\"" << endl;
    +    indent(out) << "switch self {" << endl;
    +    for (f_iter = fields.begin(); f_iter != fields.end();f_iter++) {
    +      indent(out) << "case ." << (*f_iter)->get_name() << "(let val): "
    +                  << "desc += \"" << (*f_iter)->get_name() << "(val: 
\\(val))\""
    +                  << endl;
    +    }
    +    indent(out) << "}" << endl;
    +
    +
    +  }
    +
    +  indent(out) << "return desc" << endl;
    +
    +  block_close(out);
    +
    +  out << endl;
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generates a thrift service.  In Swift this consists of a
    + * protocol definition and a client (with it's implementation
    + * separated into exts file).
    + *
    + * @param tservice The service definition
    + */
    +void t_swift_3_generator::generate_service(t_service* tservice) {
    +
    +  generate_swift_service_protocol(f_decl_, tservice);
    +  generate_swift_service_client(f_decl_, tservice);
    +  if (async_clients_) {
    +    generate_swift_service_protocol_async(f_decl_, tservice);
    +    generate_swift_service_client_async(f_decl_, tservice);
    +  }
    +  generate_swift_service_server(f_decl_, tservice);
    +
    +  generate_swift_service_helpers(tservice);
    +
    +  generate_swift_service_client_implementation(f_impl_, tservice);
    +  if (async_clients_) {
    +    generate_swift_service_client_async_implementation(f_impl_, tservice);
    +  }
    +  generate_swift_service_server_implementation(f_impl_, tservice);
    +}
    +
    +/**
    + * Generates structs for all the service return types
    + *
    + * @param tservice The service
    + */
    +void t_swift_3_generator::generate_swift_service_helpers(t_service* 
tservice) {
    +  vector<t_function*> functions = tservice->get_functions();
    +  vector<t_function*>::iterator f_iter;
    +  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    +
    +    t_struct* ts = (*f_iter)->get_arglist();
    +
    +    string qname = function_args_helper_struct_type(tservice, *f_iter);
    +
    +    t_struct qname_ts = t_struct(ts->get_program(), qname);
    +
    +    const vector<t_field*>& members = ts->get_members();
    +    vector<t_field*>::const_iterator m_iter;
    +    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    +      qname_ts.append(*m_iter);
    +    }
    +
    +    generate_swift_struct(f_impl_, &qname_ts, true, true);
    +    generate_swift_struct_implementation(f_impl_, &qname_ts, false, true);
    +    generate_function_helpers(tservice, *f_iter);
    +  }
    +}
    +
    +string t_swift_3_generator::function_result_helper_struct_type(t_service 
*tservice, t_function* tfunction) {
    +  if (tfunction->is_oneway()) {
    +    return tservice->get_name() + "_" + tfunction->get_name();
    +  } else {
    +    return tservice->get_name() + "_" + tfunction->get_name() + "_result";
    +  }
    +}
    +
    +string t_swift_3_generator::function_args_helper_struct_type(t_service 
*tservice, t_function* tfunction) {
    +  return tservice->get_name() + "_" + tfunction->get_name() + "_args";
    +}
    +
    +/**
    + * Generates a struct and helpers for a function.
    + *
    + * @param tfunction The function
    + */
    +void t_swift_3_generator::generate_function_helpers(t_service *tservice, 
t_function* tfunction) {
    +  if (tfunction->is_oneway()) {
    +    return;
    +  }
    +
    +  // create a result struct with a success field of the return type,
    +  // and a field for each type of exception thrown
    +  t_struct result(program_, function_result_helper_struct_type(tservice, 
tfunction));
    +  if (!tfunction->get_returntype()->is_void()) {
    +    t_field* success = new t_field(tfunction->get_returntype(), "success", 
0);
    +    success->set_req(t_field::T_OPTIONAL);
    +    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 *x = *f_iter;
    +    t_field *ox = new t_field(x->get_type(), x->get_name(), x->get_key());
    +    ox->set_req(t_field::T_OPTIONAL);
    +    result.append(ox);
    +  }
    +
    +  // generate the result struct
    +  generate_swift_struct(f_impl_, &result, true, true);
    +  generate_swift_struct_implementation(f_impl_, &result, true, true);
    +
    +  for (f_iter = result.get_members().begin(); f_iter != 
result.get_members().end(); ++f_iter) {
    +    delete *f_iter;
    +  }
    +}
    +
    +/**
    + * Generates a service protocol definition.
    + *
    + * @param tservice The service to generate a protocol definition for
    + */
    +void t_swift_3_generator::generate_swift_service_protocol(ofstream& out, 
t_service* tservice) {
    +
    +  indent(out) << "public protocol " << tservice->get_name();
    +  t_service* parent = tservice->get_extends();
    +  if (parent != NULL) {
    +    out << " : " << parent->get_name();
    +  }
    +  block_open(out);
    +
    +  vector<t_function*> functions = tservice->get_functions();
    +  vector<t_function*>::iterator f_iter;
    +
    +  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    +    out << endl;
    +
    +    indent(out) << function_signature(*f_iter) << "  // exceptions: ";
    +    t_struct* xs = (*f_iter)->get_xceptions();
    +    const 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) {
    +      out << type_name((*x_iter)->get_type()) + ", ";
    +    }
    +    out << endl;
    +  }
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generates an asynchronous service protocol definition.
    + *
    + * @param tservice The service to generate a protocol definition for
    + */
    +void t_swift_3_generator::generate_swift_service_protocol_async(ofstream& 
out, t_service* tservice) {
    +
    +  indent(out) << "public protocol " << tservice->get_name() << "Async";
    +
    +  block_open(out);
    +
    +  vector<t_function*> functions = tservice->get_functions();
    +  vector<t_function*>::iterator f_iter;
    +
    +  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    +    out << endl;
    +    indent(out) << async_function_signature(*f_iter) << endl;
    +    out << endl;
    +  }
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generates a service client interface definition.
    + *
    + * @param tservice The service to generate a client interface definition 
for
    + */
    +void t_swift_3_generator::generate_swift_service_client(ofstream& out,
    +                                                                t_service* 
tservice) {
    +
    +  indent(out) << "public class " << tservice->get_name() << "Client";// : "
    +
    +  // Inherit from ParentClient
    +  t_service* parent = tservice->get_extends();
    +
    +  out << " : " << ((parent == NULL) ? "TClient" : parent->get_name() + 
"Client");
    +
    +  out <<  " /* , " << tservice->get_name() << " */";
    +
    +
    +  block_open(out);
    +  out << endl;
    +
    +  // out << endl;
    +
    +  // indent(out) << "let inProtocol: TProtocol" << endl;
    +
    +  // indent(out) << "let outProtocol: TProtocol" << endl << endl;
    +
    +  // indent(out) << "public init(inoutProtocol: TProtocol)";
    +
    +  // block_open(out);
    +
    +  // indent(out) << "self.inProtocol = inoutProtocol" << endl;
    +
    +  // indent(out) << "self.outProtocol = inoutProtocol" << endl;
    +
    +  // block_close(out);
    +
    +  // out << endl;
    +
    +  // indent(out) << "public init(inProtocol: TProtocol, outProtocol: 
TProtocol)";
    +
    +  // block_open(out);
    +
    +  // indent(out) << "self.inProtocol = inProtocol" << endl;
    +
    +  // indent(out) << "self.outProtocol = outProtocol" << endl;
    +
    +  // block_close(out);
    +
    +  // out << endl;
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generates a service client interface definition.
    + *
    + * @param tservice The service to generate a client interface definition 
for
    + */
    +void t_swift_3_generator::generate_swift_service_client_async(ofstream& 
out,
    +                                                                      
t_service* tservice) {
    +
    +  indent(out) << "public class " << tservice->get_name() << 
"AsyncClient<Protocol: TProtocol, Factory: TAsyncTransportFactory>";// : "
    +
    +  // Inherit from ParentClient
    +  t_service* parent = tservice->get_extends();
    +
    +  out << " : " << ((parent == NULL) ? "T" :  parent->get_name()) + 
"AsyncClient<Protocol, Factory>";
    +  out <<  " /* , " << tservice->get_name() << " */";
    +
    +  block_open(out);
    +
    +  out << endl;
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generates a service server interface definition. In other words,
    + * the TProcess implementation for the service definition.
    + *
    + * @param tservice The service to generate a client interface definition 
for
    + */
    +void t_swift_3_generator::generate_swift_service_server(ofstream& out,
    +                                                                t_service* 
tservice) {
    +
    +  indent(out) << "public class " << tservice->get_name() << "Processor /* 
" << tservice->get_name() << " */";
    +
    +  block_open(out);
    +
    +  out << endl;
    +
    +  out << indent() << "typealias ProcessorHandlerDictionary = "
    +                  << "[String: (Int32, TProtocol, TProtocol, " << 
tservice->get_name() << ") throws -> Void]" << endl
    +      << endl
    +      << indent() << "public var service: " << tservice->get_name() << endl
    +      << endl
    +      << indent() << "public required init(service: " << 
tservice->get_name() << ")";
    +  block_open(out);
    +  indent(out) << "self.service = service" << endl;
    +  block_close(out);
    +
    +  out << endl;
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generates a function that will send the arguments
    + * for a service function via a protocol.
    + *
    + * @param tservice  The service to generate
    + * @param tfunction The function to generate
    + * @param needs_protocol
    + *                  Wether the first parameter must be a protocol or if
    + *                  the protocol is to be assumed
    + */
    +void 
t_swift_3_generator::generate_swift_service_client_send_function_implementation(ofstream&
 out,
    +                                                                           
        t_service *tservice,
    +                                                                           
        t_function* tfunction,
    +                                                                           
        bool needs_protocol) {
    +
    +  string funname = tfunction->get_name();
    +
    +  t_function send_function(g_type_bool,
    +                           "send_" + tfunction->get_name(),
    +                           tfunction->get_arglist());
    +
    +  string argsname = function_args_helper_struct_type(tservice, tfunction);
    +  t_struct* arg_struct = tfunction->get_arglist();
    +
    +  // Open function
    +  indent(out) << "private func " << send_function.get_name() << "(" << 
argument_list(tfunction->get_arglist(), needs_protocol ? "on outProtocol" : "", 
true, true) << ") throws";
    +  block_open(out);
    +
    +  // Serialize the request
    +  indent(out) << "try outProtocol.writeMessageBegin(name: \"" << funname 
<< "\", "
    +              << "type: " << (tfunction->is_oneway() ? ".oneway" : 
".call") << ", "
    +              << "sequenceID: 0)" << endl;
    +
    +  indent(out) << "let args = " << argsname << "(";
    +
    +  // write out function parameters
    +
    +  const vector<t_field*>& fields = arg_struct->get_members();
    +  vector<t_field*>::const_iterator f_iter;
    +
    +  for (f_iter = fields.begin(); f_iter != fields.end();) {
    +    t_field *tfield = (*f_iter);
    +    out << tfield->get_name() << ": " << tfield->get_name();
    +    if (++f_iter != fields.end()) {
    +      out << ", ";
    +    }
    +  }
    +  out << ")" << endl;
    +  indent(out) << "try args.write(to: outProtocol)" << endl;
    +
    +  indent(out) << "try outProtocol.writeMessageEnd()" << endl;
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generates a function that will recv the result for a
    + * service function via a protocol.
    + *
    + * @param tservice  The service to generate
    + * @param tfunction The function to generate
    + * @param needs_protocol
    + *                  Wether the first parameter must be a protocol or if
    + *                  the protocol is to be assumed
    + */
    +void 
t_swift_3_generator::generate_swift_service_client_recv_function_implementation(ofstream&
 out,
    +                                                                           
        t_service* tservice,
    +                                                                           
        t_function* tfunction,
    +                                                                           
        bool needs_protocol) {
    +
    +  // Open function
    +  indent(out) << "private func recv_" << tfunction->get_name() << "(";
    +
    +  if (needs_protocol) {
    +    out << "on inProtocol: TProtocol";
    +  }
    +
    +  out << ") throws";
    +
    +  if (!tfunction->get_returntype()->is_void()) {
    +    out << " -> " << type_name(tfunction->get_returntype());
    +  }
    +
    +  block_open(out);
    +
    +  // check for an exception
    +
    +  indent(out) << "try inProtocol.readResultMessageBegin() " << endl;
    +
    +  string resultname = function_result_helper_struct_type(tservice, 
tfunction);
    +  indent(out);
    +  if (!tfunction->get_returntype()->is_void() || 
!tfunction->get_xceptions()->get_members().empty()) {
    +    out << "let result = ";
    +  } else {
    +    out << "_ = ";
    +  }
    +
    +  string return_type_name = type_name(tfunction->get_returntype());
    +  out << "try " << resultname << ".read(from: inProtocol)" << endl;
    +
    +  indent(out) << "try inProtocol.readMessageEnd()" << endl << endl;
    +
    +  // Careful, only return _result if not a void function
    +  if (!tfunction->get_returntype()->is_void()) {
    +    indent(out) << "if let success = result.success";
    +    block_open(out);
    +    indent(out) << "return success" << endl;
    +    block_close(out);
    +  }
    +
    +  t_struct* xs = tfunction->get_xceptions();
    +  const 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) {
    +    indent(out) << "if let " << (*x_iter)->get_name() << " = result." << 
(*x_iter)->get_name();
    +    block_open(out);
    +    indent(out) << "throw " << (*x_iter)->get_name() << endl;
    +    block_close(out);
    +  }
    +
    +  // If you get here it's an exception, unless a void function
    +  if (!tfunction->get_returntype()->is_void()) {
    +    indent(out) << "throw TApplicationError(error: 
.missingResult(methodName: \""
    +                << tfunction->get_name() << "\"))" << endl;
    +  }
    +
    +  // Close function
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generates an invocation of a given the send function for the
    + * service function.
    + *
    + * @param tfunction The service to generate an implementation for
    + */
    +void 
t_swift_3_generator::generate_swift_service_client_send_function_invocation(ofstream&
 out,
    +                                                                           
    t_function* tfunction) {
    +
    +  indent(out) << "try send_" << tfunction->get_name() << "(";
    +
    +  t_struct* arg_struct = tfunction->get_arglist();
    +
    +  const vector<t_field*>& fields = arg_struct->get_members();
    +  vector<t_field*>::const_iterator f_iter;
    +
    +  for (f_iter = fields.begin(); f_iter != fields.end();) {
    +    out << (*f_iter)->get_name() << ": " << (*f_iter)->get_name();
    +    if (++f_iter != fields.end()) {
    +      out << ", ";
    +    }
    +  }
    +
    +  out << ")" << endl;
    +}
    +
    +/**
    + * Generates an invocation of a given the send function for the
    + * service function. This is for asynchronous protocols.
    + *
    + * @param tfunction The service to generate an implementation for
    + */
    +void 
t_swift_3_generator::generate_swift_service_client_send_async_function_invocation(ofstream&
 out,
    +                                                                           
          t_function* tfunction) {
    +
    +  t_struct* arg_struct = tfunction->get_arglist();
    +  const vector<t_field*>& fields = arg_struct->get_members();
    +  vector<t_field*>::const_iterator f_iter;
    +
    +  indent(out) << "try send_" << tfunction->get_name() << "(on: proto";
    +
    +  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    +    out << ", " << (*f_iter)->get_name() << ": " << (*f_iter)->get_name();
    +  }
    +
    +  out << ")" << endl;
    +}
    +
    +/**
    + * Generates a service client protocol implementation via extension.
    + *
    + * @param tservice The service to generate an implementation for
    + */
    +void 
t_swift_3_generator::generate_swift_service_client_implementation(ofstream& out,
    +                                                                     
t_service* tservice) {
    +
    +  string name = tservice->get_name() + "Client";
    +
    +  indent(out) << "extension " << name << " : " << tservice->get_name();
    +
    +  block_open(out);
    +
    +  out << 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) {
    +
    +    generate_swift_service_client_send_function_implementation(out, 
tservice, *f_iter, false);
    +
    +    if (!(*f_iter)->is_oneway()) {
    +      generate_swift_service_client_recv_function_implementation(out, 
tservice, *f_iter, false);
    +    }
    +
    +    // Open function
    +    indent(out) << "public " << function_signature(*f_iter);
    +
    +    block_open(out);
    +
    +    generate_swift_service_client_send_function_invocation(out, *f_iter);
    +
    +    indent(out) << "try outProtocol.transport.flush()" << endl;
    +
    +    if (!(*f_iter)->is_oneway()) {
    +      if ((*f_iter)->get_returntype()->is_void()) {
    +        indent(out) << "try recv_" << (*f_iter)->get_name() << "()" << 
endl;
    +      } else {
    +        indent(out) << "return try recv_" << (*f_iter)->get_name() << "()" 
<< endl;
    +      }
    +    }
    +
    +    block_close(out);
    +
    +    out << endl;
    +  }
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generates a service asynchronous client protocol implementation via 
extension.
    + *
    + * @param tservice The service to generate an implementation for
    + */
    +void 
t_swift_3_generator::generate_swift_service_client_async_implementation(ofstream&
 out,
    +                                                                           
t_service* tservice) {
    +
    +  string name = tservice->get_name() + "AsyncClient";
    +  string protocol_name = tservice->get_name() + "Async";
    +
    +  indent(out) << "extension " << name << " : " << protocol_name;
    +
    +  block_open(out);
    +
    +  out << 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) {
    +
    +    generate_swift_service_client_send_function_implementation(out, 
tservice, *f_iter, true);
    +
    +    if (!(*f_iter)->is_oneway()) {
    +      generate_swift_service_client_recv_function_implementation(out, 
tservice, *f_iter, true);
    +    }
    +
    +    indent(out) << "public " << async_function_signature(*f_iter);
    +    block_open(out);
    +
    +    out << endl;
    +
    +    out << indent() << "let transport   = factory.newTransport()" << endl
    +        << indent() << "let proto = Protocol(on: transport)" << endl
    +        << endl;
    +
    +    generate_swift_service_client_send_async_function_invocation(out, 
*f_iter);
    +
    +    out << endl;
    +
    +    bool ret_is_void = (*f_iter)->get_returntype()->is_void();
    +    bool is_oneway = (*f_iter)->is_oneway();
    +
    +    string error_completion_call = ret_is_void ? "completion(error)" : 
"completion(nil, error)";
    +    indent(out) << "transport.flush";
    +    block_open(out);
    +    out << indent() << "(trans, error) in" << endl << endl;
    +    out << indent() << "if let error = error";
    +    block_open(out);
    +    out << indent() << error_completion_call << endl;
    +    block_close(out);
    +
    +    if (!is_oneway) {
    +      out << indent() << "do";
    +      block_open(out);
    +      indent(out);
    +      if (!ret_is_void) {
    +        out << "let result = ";
    +      }
    +      out << "try self.recv_" << (*f_iter)->get_name() << "(on: proto)" << 
endl;
    +
    +      out << indent() << (ret_is_void ? "completion(nil)" : 
"completion(result, nil)") << endl;
    +      block_close(out);
    +
    +      out << indent() << "catch let error";
    +      block_open(out);
    +      out << indent() << error_completion_call << endl;
    +
    +      block_close(out);
    +    } else {
    +      out << indent() << "completion(nil)" << endl;
    +    }
    +
    +    block_close(out);
    +
    +    block_close(out);
    +
    +  }
    +
    +  block_close(out);
    +
    +  out << endl;
    +}
    +
    +/**
    + * Generates a service server implementation.
    + *
    + * Implemented by generating a block for each service function that
    + * handles the processing of that function. The blocks are stored in
    + * a map and looked up via function/message name.
    + *
    + * @param tservice The service to generate an implementation for
    + */
    +void 
t_swift_3_generator::generate_swift_service_server_implementation(ofstream& out,
    +                                                                     
t_service* tservice) {
    +
    +  string name = tservice->get_name() + "Processor";
    +
    +  indent(out) << "extension " << name << " : TProcessor";
    +  block_open(out);
    +
    +  out << endl;
    +
    +  indent(out) << "static let processorHandlers: ProcessorHandlerDictionary 
=";
    +  block_open(out);
    +
    +  out << endl;
    +
    +  out << indent() << "var processorHandlers = 
ProcessorHandlerDictionary()" << endl << endl;
    +
    +  // generate method map for routing incoming calls
    +  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_function* tfunction = *f_iter;
    +
    +    string args_type = function_args_helper_struct_type(tservice, *f_iter);
    +
    +    out << indent() << "processorHandlers[\"" << tfunction->get_name() << 
"\"] = { sequenceID, inProtocol, outProtocol, handler in" << endl
    +        << endl;
    +
    +    indent_up();
    +    out << indent() << "let args = try " << args_type << ".read(from: 
inProtocol)" << endl
    +        << endl
    +        << indent() << "try inProtocol.readMessageEnd()" << endl
    +        << endl;
    +
    +    if (!tfunction->is_oneway() ) {
    +      string result_type = function_result_helper_struct_type(tservice, 
tfunction);
    +      indent(out) << "var result = " << result_type << "()" << endl;
    +
    +      indent(out) << "do";
    +      block_open(out);
    +
    +      indent(out);
    +      if (!tfunction->get_returntype()->is_void()) {
    +        out << "result.success = ";
    +      }
    +      out << "try handler." << tfunction->get_name() << "(";
    +
    +      t_struct* arg_struct = tfunction->get_arglist();
    +      const vector<t_field*>& fields = arg
    --- End diff --
    
    I'd rather see the response be represented as something other than two 
Optionals so users of the client APIs don't have to worry about unexpected 
cases. (For example, can an API return both a response struct and an error?)
    
    There are a couple different ways to represent this...
    
    1. as a new `TAsyncResponse<Response>: TEnum` type, where the error is an 
Error
    2. same as \#1, but with a type parameter for the specific TError(s) that a 
call may throw
    3. a closure of signature `() throws -> Response` that allows the caller to 
process errors with the `catch` construct without being forced to re-throw the 
error after unwrapping. As a bonus, callers that don't care about the response 
can opt to just not call this closure and avoid parsing the response 
altogether. (The closure isn't marked `@escaping` so it should be possible to 
do everything lazily inside the closure. It would be considered an error to 
call it more than once.)
    
    Personally I'm kind of liking option \#3 at the moment.


> Swift Library
> -------------
>
>                 Key: THRIFT-3773
>                 URL: https://issues.apache.org/jira/browse/THRIFT-3773
>             Project: Thrift
>          Issue Type: New Feature
>          Components: Swift - Library
>            Reporter: Thomas Bartelmess
>
> We already have the option to generate Swift code in the Cocoa compiler, 
> however large parts of the (Objective-C) Cocoa Library still depend on Cocoa 
> and  Objective-C.
> It would be good to have a native Swift library that doesn't depend on the 
> Cocoa libraries.
> Design goals:
> - Fully compatible with the code that is currently generated by the Cocoa 
> compiler (both Objective-C and Swift).
> - Ability to run on Linux
> - Pure Swift, no Objective-C code.
> - No dependencies on closed source apple libraries
> - Keep the same interface, so that the library is compatible with the code 
> the current cocoa compiler generates
> - Better server support that the current Objective-C library.
> - Follow the new Swift packaging format to be compatible with the Swift 
> Package manager



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to