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

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_r80355496
  
    --- 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");
    --- End diff --
    
    What is the use case for the `debug_descriptions` option? I tested this and 
it just forces me to implement debugDescription for all the structs instead of 
being opt-in for the structs I may choose to conform to 
`CustomDebugStringConvertible`.


> 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