void t_cocoa_generator::generate_cocoa_service_client_implementation()

in thrift/compiler/generate/t_cocoa_generator.cc [1792:1981]


void t_cocoa_generator::generate_cocoa_service_client_implementation(
    std::ofstream& out, const t_service* tservice) {
  out << "@implementation " << cocoa_prefix_ << tservice->name() << "Client"
      << std::endl;

  // initializers
  out << "- (id) initWithProtocol: (id <TProtocol>) protocol" << std::endl;
  scope_up(out);
  out << indent()
      << "return [self initWithInProtocol: protocol outProtocol: protocol];"
      << std::endl;
  scope_down(out);
  out << std::endl;

  out << "- (id) initWithInProtocol: (id <TProtocol>) anInProtocol outProtocol: (id <TProtocol>) anOutProtocol"
      << std::endl;
  scope_up(out);
  out << indent() << "self = [super init];" << std::endl;
  out << indent() << "inProtocol = [anInProtocol retain_stub];" << std::endl;
  out << indent() << "outProtocol = [anOutProtocol retain_stub];" << std::endl;
  out << indent() << "return self;" << std::endl;
  scope_down(out);
  out << std::endl;

  // dealloc
  out << "- (void) dealloc" << std::endl;
  scope_up(out);
  out << indent() << "[inProtocol release_stub];" << std::endl;
  out << indent() << "[outProtocol release_stub];" << std::endl;
  out << indent() << "[super dealloc_stub];" << std::endl;
  scope_down(out);
  out << std::endl;

  // generate client method implementations
  for (const auto* function : tservice->get_functions()) {
    const std::string& funname = function->name();

    t_function send_function(
        &t_base_type::t_void(),
        std::string("send_") + function->name(),
        t_struct::clone_DO_NOT_USE(function->get_paramlist()));

    std::string argsname = function->name() + "_args";

    // Open function
    indent(out) << "- " << function_signature(&send_function) << std::endl;
    scope_up(out);

    // Serialize the request
    out << indent() << "[outProtocol writeMessageBeginWithName: @\"" << funname
        << "\""
        << " type: TMessageType_CALL"
        << " sequenceID: 0];" << std::endl;

    out << indent() << "[outProtocol writeStructBeginWithName: @\"" << argsname
        << "\"];" << std::endl;

    // write out function parameters
    for (const auto& param : function->get_paramlist()->fields()) {
      const std::string& fieldName = param.name();
      if (type_can_be_null(param.get_type())) {
        out << indent() << "if (" << fieldName << " != nil)";
        scope_up(out);
      }
      out << indent() << "[outProtocol writeFieldBeginWithName: @\""
          << fieldName
          << "\""
             " type: "
          << type_to_enum(param.get_type()) << " fieldID: " << param.get_key()
          << "];" << std::endl;

      generate_serialize_field(out, &param, fieldName);

      out << indent() << "[outProtocol writeFieldEnd];" << std::endl;

      if (type_can_be_null(param.get_type())) {
        scope_down(out);
      }
    }

    out << indent() << "[outProtocol writeFieldStop];" << std::endl;
    out << indent() << "[outProtocol writeStructEnd];" << std::endl;

    out << indent() << "[outProtocol writeMessageEnd];" << std::endl
        << indent() << "[[outProtocol transport] flush];" << std::endl;

    scope_down(out);
    out << std::endl;

    if (function->qualifier() != t_function_qualifier::one_way) {
      t_function recv_function(
          function->get_returntype(),
          std::string("recv_") + function->name(),
          std::make_unique<t_paramlist>(program_),
          t_struct::clone_DO_NOT_USE(function->get_xceptions()));
      // Open function
      indent(out) << "- " << function_signature(&recv_function) << std::endl;
      scope_up(out);

      // TODO(mcslee): Message validation here, was the seqid etc ok?

      // check for an exception
      out << indent() << "int msgType = 0;" << std::endl
          << indent()
          << "[inProtocol readMessageBeginReturningName: nil type: &msgType sequenceID: NULL];"
          << std::endl
          << indent() << "if (msgType == TMessageType_EXCEPTION) {" << std::endl
          << indent()
          << "  TApplicationException * x = [TApplicationException read: inProtocol];"
          << std::endl
          << indent() << "  [inProtocol readMessageEnd];" << std::endl
          << indent() << "  @throw x;" << std::endl
          << indent() << "}" << std::endl;

      // FIXME - could optimize here to reduce creation of temporary objects.
      std::string resultname = function_result_helper_struct_type(function);
      out << indent() << cocoa_prefix_ << resultname << " * result = [[["
          << cocoa_prefix_ << resultname << " alloc] init] autorelease_stub];"
          << std::endl;
      indent(out) << "[result read: inProtocol];" << std::endl;
      indent(out) << "[inProtocol readMessageEnd];" << std::endl;

      // Careful, only return _result if not a void function
      if (!function->get_returntype()->is_void()) {
        out << indent() << "if ([result successIsSet]) {" << std::endl
            << indent() << "  return [result success];" << std::endl
            << indent() << "}" << std::endl;
      }

      if (function->exceptions() != nullptr) {
        for (const auto& x : function->exceptions()->fields()) {
          out << indent() << "if ([result " << x.name() << "IsSet]) {"
              << std::endl
              << indent() << "  @throw [result " << x.name() << "];"
              << std::endl
              << indent() << "}" << std::endl;
        }
      }

      // If you get here it's an exception, unless a void function
      if (function->get_returntype()->is_void()) {
        indent(out) << "return;" << std::endl;
      } else {
        out << indent()
            << "@throw [TApplicationException exceptionWithType: TApplicationException_MISSING_RESULT"
            << std::endl
            << indent()
            << "                                         reason: @\""
            << function->name() << " failed: unknown result\"];" << std::endl;
      }

      // Close function
      scope_down(out);
      out << std::endl;
    }

    // Open function
    indent(out) << "- " << function_signature(function) << std::endl;
    scope_up(out);
    indent(out) << "[self send_" << funname;

    // Declare the function arguments
    bool first = true;
    for (const auto& param : function->get_paramlist()->fields()) {
      const std::string& fieldName = param.name();
      out << " ";
      if (first) {
        first = false;
        out << ": " << fieldName;
      } else {
        out << fieldName << ": " << fieldName;
      }
    }
    out << "];" << std::endl;

    if (function->qualifier() != t_function_qualifier::one_way) {
      out << indent();
      if (!function->get_returntype()->is_void()) {
        out << "return ";
      }
      out << "[self recv_" << funname << "];" << std::endl;
    }
    scope_down(out);
    out << std::endl;
  }

  indent_down();

  out << "@end" << std::endl << std::endl;
}