void t_swift_generator::generate_swift_struct_reader()

in compiler/cpp/src/thrift/generate/t_swift_generator.cc [1128:1326]


void t_swift_generator::generate_swift_struct_reader(ostream& out,
                                                     t_struct* tstruct,
                                                     bool is_private) {

  if (!gen_cocoa_) {
    /** Swift 3 case */
    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()" << '\n';

    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) << '\n';
    }

    out << '\n';

    // Loop over reading in fields
    indent(out) << "fields: while true";
    block_open(out);
    out << '\n';

    indent(out) << "let (_, fieldType, fieldID) = try proto.readFieldBegin()" << '\n' << '\n';
    indent(out) << "switch (fieldID, fieldType)";
    block_open(out);
    indent(out) << "case (_, .stop):            break fields" << '\n';


    // Generate deserialization code for known cases
    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()) << "):";
      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:
          case t_base_type::TYPE_UUID:
            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 = "            ";
      }

      out << padding << maybe_escape_identifier((*f_iter)->get_name()) << " = try "
          << type_name((*f_iter)->get_type(), false, false) << ".read(from: proto)" << '\n';
    }

    indent(out) << "case let (_, unknownType):  try proto.skip(type: unknownType)" << '\n';
    block_close(out);
    out << '\n';

    // Read field end marker
    indent(out) << "try proto.readFieldEnd()" << '\n';
    block_close(out);
    out << '\n';
    indent(out) << "try proto.readStructEnd()" << '\n';

    if (struct_has_required_fields(tstruct)) {
      // performs various checks (e.g. check that all required fields are set)
      indent(out) << "// Required fields" << '\n';

      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
        if (field_is_optional(*f_iter)) {
          continue;
        }
        indent(out) << "try proto.validateValue(" << maybe_escape_identifier((*f_iter)->get_name()) << ", "
                    << "named: \"" << (*f_iter)->get_name() << "\")" << '\n';
      }
    }

    out << '\n';

    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 << ", ";
      }
    }

  } else {
    /** Legacy Swif2/Cocoa case */
    string visibility = is_private ? "private" : "public";

    indent(out) << visibility << " static func readValueFromProtocol(__proto: TProtocol) throws -> "
                << tstruct->get_name();

    block_open(out);
    out << '\n';
    indent(out) << "try __proto.readStructBegin()" << '\n' << '\n';

    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) << '\n';
    }

    out << '\n';

    // Loop over reading in fields
    indent(out) << "fields: while true";
    block_open(out);
    out << '\n';

    indent(out) << "let (_, fieldType, fieldID) = try __proto.readFieldBegin()" << '\n' << '\n';
    indent(out) << "switch (fieldID, fieldType)";

    block_open(out);

    indent(out) << "case (_, .STOP):" << '\n';
    indent_up();
    indent(out) << "break fields" << '\n' << '\n';
    indent_down();

    // Generate deserialization code for known cases
    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()) << "):" << '\n';
      indent_up();
      indent(out) << maybe_escape_identifier((*f_iter)->get_name()) << " = try __proto.readValue() as "
                  << type_name((*f_iter)->get_type()) << '\n' << '\n';
      indent_down();

    }

    indent(out) << "case let (_, unknownType):" << '\n';
    indent_up();
    indent(out) << "try __proto.skipType(unknownType)" << '\n';
    indent_down();
    block_close(out);
    out << '\n';

    // Read field end marker
    indent(out) << "try __proto.readFieldEnd()" << '\n';

    block_close(out);
    out << '\n';
    indent(out) << "try __proto.readStructEnd()" << '\n';
    out << '\n';

    if (struct_has_required_fields(tstruct)) {
      // performs various checks (e.g. check that all required fields are set)
      indent(out) << "// Required fields" << '\n';

      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() << "\")" << '\n';
      }
    }

    out << '\n';

    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 << ")" << '\n';

  block_close(out);

  out << '\n';
}