void t_c_glib_generator::generate_service_handler()

in compiler/cpp/src/thrift/generate/t_c_glib_generator.cc [1837:2052]


void t_c_glib_generator::generate_service_handler(t_service* tservice) {
  vector<t_function*> functions = tservice->get_functions();
  vector<t_function*>::const_iterator function_iter;

  string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_));
  string service_name_uc = to_upper_case(service_name_lc);

  string service_handler_name = service_name_ + "Handler";

  string class_name = this->nspace + service_handler_name;
  string class_name_lc = this->nspace_lc + initial_caps_to_underscores(service_handler_name);
  string class_name_uc = to_upper_case(class_name_lc);

  string parent_class_name;
  string parent_type_name;

  string args_indent;

  // The service this service extends, or nullptr if it extends no service
  t_service* extends_service = tservice->get_extends();

  // Determine the name of our parent service (if any) and the handler class'
  // parent class name and type
  if (extends_service) {
    string parent_service_name = extends_service->get_name();
    string parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name));
    string parent_service_name_uc = to_upper_case(parent_service_name_lc);

    parent_class_name = this->nspace + parent_service_name + "Handler";
    parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_HANDLER";
  } else {
    parent_class_name = "GObject";
    parent_type_name = "G_TYPE_OBJECT";
  }

  // Generate the handler class' definition in the header file

  // Generate the handler instance definition
  f_header_ << "/* " << service_name_ << " handler (abstract base class) */" << '\n' << "struct _"
            << class_name << '\n' << "{" << '\n';
  indent_up();
  f_header_ << indent() << parent_class_name << " parent;" << '\n';
  indent_down();
  f_header_ << "};" << '\n' << "typedef struct _" << class_name << " " << class_name << ";" << '\n'
            << '\n';

  // Generate the handler class definition, including its class members
  // (methods)
  f_header_ << "struct _" << class_name << "Class" << '\n' << "{" << '\n';
  indent_up();
  f_header_ << indent() << parent_class_name << "Class parent;" << '\n' << '\n';

  for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
    string method_name = initial_caps_to_underscores((*function_iter)->get_name());
    t_type* return_type = (*function_iter)->get_returntype();
    t_struct* arg_list = (*function_iter)->get_arglist();
    t_struct* x_list = (*function_iter)->get_xceptions();
    bool has_return = !return_type->is_void();
    bool has_args = arg_list->get_members().size() == 0;
    bool has_xceptions = x_list->get_members().size() == 0;

    string params = "(" + this->nspace + service_name_ + "If *iface"
                    + (has_return ? ", " + type_name(return_type) + "* _return" : "")
                    + (has_args ? "" : (", " + argument_list(arg_list)))
                    + (has_xceptions ? "" : (", " + xception_list(x_list))) + ", GError **error)";

    indent(f_header_) << "gboolean (*" << method_name << ") " << params << ";" << '\n';
  }
  indent_down();

  f_header_ << "};" << '\n' << "typedef struct _" << class_name << "Class " << class_name
            << "Class;" << '\n' << '\n';

  // Generate the remaining header boilerplate
  f_header_ << "GType " << class_name_lc << "_get_type (void);" << '\n' << "#define "
            << this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER "
            << "(" << class_name_lc << "_get_type())" << '\n' << "#define " << class_name_uc
            << "(obj) "
            << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_"
            << service_name_uc << "_HANDLER, " << class_name << "))" << '\n' << "#define "
            << this->nspace_uc << "IS_" << service_name_uc << "_HANDLER(obj) "
            << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_"
            << service_name_uc << "_HANDLER))" << '\n' << "#define " << class_name_uc
            << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_"
            << service_name_uc << "_HANDLER, " << class_name << "Class))" << '\n' << "#define "
            << this->nspace_uc << "IS_" << service_name_uc << "_HANDLER_CLASS(c) "
            << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc
            << "_HANDLER))" << '\n' << "#define " << this->nspace_uc << service_name_uc
            << "_HANDLER_GET_CLASS(obj) "
            << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_"
            << service_name_uc << "_HANDLER, " << class_name << "Class))" << '\n' << '\n';

  // Generate the handler class' method definitions
  for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
    string method_name = initial_caps_to_underscores((*function_iter)->get_name());
    t_type* return_type = (*function_iter)->get_returntype();
    t_struct* arg_list = (*function_iter)->get_arglist();
    t_struct* x_list = (*function_iter)->get_xceptions();
    bool has_return = !return_type->is_void();
    bool has_args = arg_list->get_members().size() == 0;
    bool has_xceptions = x_list->get_members().size() == 0;

    string params = "(" + this->nspace + service_name_ + "If *iface"
                    + (has_return ? ", " + type_name(return_type) + "* _return" : "")
                    + (has_args ? "" : (", " + argument_list(arg_list)))
                    + (has_xceptions ? "" : (", " + xception_list(x_list))) + ", GError **error)";

    f_header_ << "gboolean " << class_name_lc << "_" << method_name << " " << params << ";" << '\n';
  }
  f_header_ << '\n';

  // Generate the handler's implementation in the implementation file

  // Generate the implementation boilerplate
  f_service_ << "static void" << '\n' << class_name_lc << "_" << service_name_lc
             << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface);"
             << '\n' << '\n';

  args_indent = string(25, ' ');
  f_service_ << "G_DEFINE_TYPE_WITH_CODE (" << class_name << ", " << '\n' << args_indent
             << class_name_lc << "," << '\n' << args_indent << parent_type_name << "," << '\n'
             << args_indent << "G_IMPLEMENT_INTERFACE (" << this->nspace_uc << "TYPE_"
             << service_name_uc << "_IF," << '\n';
  args_indent += string(23, ' ');
  f_service_ << args_indent << class_name_lc << "_" << service_name_lc << "_if_interface_init))"
             << '\n' << '\n';

  // Generate the handler method implementations
  for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
    string function_name = (*function_iter)->get_name();
    string method_name = initial_caps_to_underscores(function_name);
    t_type* return_type = (*function_iter)->get_returntype();
    t_struct* arg_list = (*function_iter)->get_arglist();
    t_struct* x_list = (*function_iter)->get_xceptions();

    const vector<t_field*>& args = arg_list->get_members();
    const vector<t_field*>& xceptions = x_list->get_members();

    vector<t_field*>::const_iterator field_iter;

    t_function implementing_function(return_type,
                                     service_name_lc + "_handler_" + method_name,
                                     arg_list,
                                     x_list,
                                     (*function_iter)->is_oneway());

    indent(f_service_) << function_signature(&implementing_function) << '\n';
    scope_up(f_service_);
    f_service_ << indent() << "g_return_val_if_fail (" << this->nspace_uc << "IS_"
               << service_name_uc << "_HANDLER (iface), FALSE);" << '\n' << '\n' << indent()
               << "return " << class_name_uc << "_GET_CLASS (iface)"
               << "->" << method_name << " (iface, ";

    if (!return_type->is_void()) {
      f_service_ << "_return, ";
    }
    for (field_iter = args.begin(); field_iter != args.end(); ++field_iter) {
      f_service_ << (*field_iter)->get_name() << ", ";
    }
    for (field_iter = xceptions.begin(); field_iter != xceptions.end(); ++field_iter) {
      f_service_ << (*field_iter)->get_name() << ", ";
    }
    f_service_ << "error);" << '\n';
    scope_down(f_service_);
    f_service_ << '\n';
  }

  // Generate the handler interface initializer
  f_service_ << "static void" << '\n' << class_name_lc << "_" << service_name_lc
             << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface)"
             << '\n';
  scope_up(f_service_);
  if (functions.size() > 0) {
    for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
      string method_name = initial_caps_to_underscores((*function_iter)->get_name());

      f_service_ << indent() << "iface->" << method_name << " = " << class_name_lc << "_"
                 << method_name << ";" << '\n';
    }
  }
  else {
    f_service_ << "THRIFT_UNUSED_VAR (iface);" << '\n';
  }
  scope_down(f_service_);
  f_service_ << '\n';

  // Generate the handler instance initializer
  f_service_ << "static void" << '\n' << class_name_lc << "_init (" << class_name << " *self)"
             << '\n';
  scope_up(f_service_);
  f_service_ << indent() << "THRIFT_UNUSED_VAR (self);" << '\n';
  scope_down(f_service_);
  f_service_ << '\n';

  // Generate the handler class initializer
  f_service_ << "static void" << '\n'
             << class_name_lc << "_class_init (" << class_name << "Class *cls)"
             << '\n';
  scope_up(f_service_);
  if (functions.size() > 0) {
    for (function_iter = functions.begin();
         function_iter != functions.end();
         ++function_iter) {
      string function_name = (*function_iter)->get_name();
      string method_name = initial_caps_to_underscores(function_name);

      // All methods are pure virtual and must be implemented by subclasses
      f_service_ << indent() << "cls->" << method_name << " = NULL;" << '\n';
    }
  }
  else {
    f_service_ << indent() << "THRIFT_UNUSED_VAR (cls);" << '\n';
  }
  scope_down(f_service_);
  f_service_ << '\n';
}