{%- import "interface_macros.tmpl" as interface_macros %}
class {{interface.name}}Proxy;

template <typename ImplRefTraits>
class {{interface.name}}Stub;

class {{interface.name}}RequestValidator;
{%- if interface|has_callbacks %}
class {{interface.name}}ResponseValidator;
{%- endif %}

{%- set interface_prefix = "%s.%s"|format(module_prefix, interface.name) %}

{{ kythe_annotation(interface_prefix) }}
class {{export_attribute|append_space_if_nonempty}}{{interface.name}}
    : public {{interface.name}}InterfaceBase {
 public:
  using IPCStableHashFunction = uint32_t(*)();

  {#- Name includes namespace to prevent collision. #}
  static constexpr const char* Name_ = "{{module_namespace}}.{{interface.name}}";
  static IPCStableHashFunction MessageToMethodInfo_(mojo::Message& message);
  static const char* MessageToMethodName_(mojo::Message& message);
{%-  if interface.runtime_feature %}
  static bool RuntimeFeature_IsEnabled_(bool expected);
{%- endif %}

{%-  if interface.uuid %}
  static constexpr base::Token Uuid_{ {{interface.uuid[0]}}ULL,
                                      {{interface.uuid[1]}}ULL };
{%-  endif %}
{%- if interface.service_sandbox %}
{%- set sandbox_enum = "%s"|format(interface.service_sandbox.GetSpec()|replace(".","::")) %}
  static constexpr auto kServiceSandbox = {{ sandbox_enum }};
{%- endif %}
  static constexpr uint32_t Version_ = {{interface.version}};
  static constexpr bool PassesAssociatedKinds_ = {% if interface|passes_associated_kinds %}true{% else %}false{% endif %};
{%- set sync_method_ordinals = interface|get_sync_method_ordinals -%}
{%- if sync_method_ordinals %}
  static inline constexpr uint32_t kSyncMethodOrdinals[] = {
    {{sync_method_ordinals|sort|join(', \n')|indent(4)}}
  };
{%- endif %}
  static constexpr bool HasUninterruptableMethods_ =
      {%- if interface|has_uninterruptable_methods %} true
      {%- else %} false{% endif %};

  using Base_ = {{interface.name}}InterfaceBase;
  using Proxy_ = {{interface.name}}Proxy;

  template <typename ImplRefTraits>
  using Stub_ = {{interface.name}}Stub<ImplRefTraits>;

  using RequestValidator_ = {{interface.name}}RequestValidator;
{%- if interface|has_callbacks %}
  using ResponseValidator_ = {{interface.name}}ResponseValidator;
{%- else %}
  using ResponseValidator_ = mojo::PassThroughFilter;
{%- endif %}

{#--- Metadata #}
  enum MethodMinVersions : uint32_t {
{%- for method in interface.methods %}
    k{{method.name}}MinVersion = {{method.min_version|default(0, true)}},
{%- endfor %}
  };

// crbug.com/1340245 - this causes binary size bloat on Fuchsia, and we're OK
// with not having this data in traces there.
#if !BUILDFLAG(IS_FUCHSIA)
{#--- Per method symbols #}
{%- for method in interface.methods %}
  struct {{method.name}}_Sym {
    NOINLINE static uint32_t IPCStableHash();
  };
{%- endfor %}
#endif // !BUILDFLAG(IS_FUCHSIA)

{#--- Enums #}
{%- for enum in interface.enums %}
  {{ kythe_annotation(enum|get_full_mojom_name_for_kind()) }}
  using {{enum.name}} = {{enum|get_name_for_kind(flatten_nested_kind=True)}};
{%- endfor %}

{#--- Constants #}
{%- for constant in interface.constants %}
  {{ kythe_annotation("%s.%s"|format(interface_prefix, constant.name)) }}
  static {{constant|format_constant_declaration(nested=True)}};
{%- endfor %}

{#--- Methods #}
  virtual ~{{interface.name}}() = default;

{%- for method in interface.methods %}
{%    if method.response_parameters != None %}
{%-     if method.sync %}
  // Sync method. This signature is used by the client side; the service side
  // should implement the signature with callback below.
  {{ kythe_annotation("%s.%s"|format(interface_prefix, method.name)) }}
  virtual bool {{method.name}}({{interface_macros.declare_sync_method_params("", method)}});
{%-     endif %}

{%-     if method.result_response != None %}
  using {{method.name}}Callback = {{interface_macros.declare_result_callback(method)}};
  using {{method.name}}Result = {{interface_macros.result_response_to_expected(method.result_response)}};
{%-     else %}
  using {{method.name}}Callback = {{interface_macros.declare_callback(method, for_blink)}};
{%-     endif %}
  using {{method.name}}MojoCallback = {{interface_macros.declare_callback(method, for_blink)}};
{%   endif -%}
  {{ kythe_annotation("%s.%s"|format(interface_prefix, method.name)) }}
  virtual void {{method.name}}({{interface_macros.declare_request_params("", method)}}) = 0;
{%-   if method|has_non_const_ref_param %}
  // Default implementation for non-const ref params. This method can be
  // implemented as a performance optimization for non-const ref types.
  virtual void {{method.name}}({{interface_macros.declare_request_params("", method, allow_non_const_ref=True)}}) {
    {{method.name}}(
{%-     for param in method.parameters -%}
{%-       if param.kind|is_non_const_ref_kind -%}
            const_cast<{{param.kind|cpp_wrapper_param_type}}>({{param.name}})
{%-       else -%}
            std::move({{param.name}})
{%-       endif %}{%- if not loop.last -%}, {% endif -%}
{%-     endfor -%}
{%-     if method.response_parameters != None -%}
{%-       if method.parameters %}, {% endif -%}
          std::move(callback)
{%-     endif -%});
  }
{%-   endif %}
{%- endfor %}
};
