[
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)