chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl

{%- import "interface_macros.tmpl" as interface_macros %}
{%- import "struct_macros.tmpl" as struct_macros %}

{%- set class_name = interface.name %}
{%- set proxy_name = interface.name ~ "Proxy" %}
{%- set namespace_as_string = "%s"|format(module_namespace|replace(".","::")) %}
{%- set namespace_as_string_with_variant = namespace_as_string ~ ("::" ~ variant if variant) %}
{%- set qualified_class_name = ("::" ~ namespace_as_string_with_variant if namespace_as_string_with_variant) ~ "::" ~ class_name %}

{%- macro alloc_params(struct, params, message, method_number, is_response) %}
  {# Allow people to search for deserialization error strings #}
  // Validation for {{class_name}}.{{method_number}}
  bool success = true;
{%-   for param in struct.packed.packed_fields_in_ordinal_order %}
{%-     if param|is_nullable_value_kind_packed_field %}
{%-       if param|is_primary_nullable_value_kind_packed_field %}
  {{param.original_field.kind|cpp_wrapper_call_type}} p_{{param.original_field.name}}{};
{%-       endif %}
{%-     else %}
  {{param.field.kind|cpp_wrapper_call_type}} p_{{param.field.name}}{ {{- param.field|default_value -}} };
{%-     endif %}
{%-   endfor %}
  {{struct.name}}DataView input_data_view({{params}}, {{message}});
  {{struct_macros.deserialize(struct, "input_data_view", "p_%s", "success")}}
  if (!success) {
    ReportValidationErrorForMessage(
        {{message}},
        mojo::internal::VALIDATION_ERROR_DESERIALIZATION_FAILED,
        {{class_name}}::Name_, {{method_number}}, {{is_response}});
    return false;
  }
{%- endmacro %}

{%- macro pass_params(parameters) %}
{%-   for param in parameters %}
{%- if param.kind|is_non_const_ref_kind %}
p_{{param.name}}
{%- else %}
std::move(p_{{param.name}})
{%- endif %}
{%-     if not loop.last %}, {% endif %}
{%-   endfor %}
{%- endmacro %}

{%- macro feature_enabled_helper(iface) %}
{%- set feature=iface.runtime_feature|get_qualified_name_for_feature %}
// static
bool {{iface.name}}::RuntimeFeature_IsEnabled_(bool expected) {
  bool enabled = base::FeatureList::IsEnabled({{feature}});
#if DCHECK_IS_ON()
  if (expected) {
    DCHECK(enabled) << "RuntimeFeature {{feature}} for {{iface.name}} is not enabled";
  }
#endif
  return enabled;
}
{%- endmacro %}

{%- macro check_feature_for_method(method) %}
{%-   if method.runtime_feature %}
{%-     set feature_cpp = method.runtime_feature|get_qualified_name_for_feature %}
CHECK(base::FeatureList::IsEnabled({{feature_cpp}}));
{%-   endif %}
{%- endmacro %}

{#--- Function with signature of GenericValidationInfo.request_validator ---#}
{%- macro define_validate_with_runtime_feature(class_name, method) %}
{%-  set feature_cpp = method.runtime_feature|get_qualified_name_for_feature %}
bool ValidateWithRuntimeFeature_{{class_name}}_{{method.name}}(
  const void* data, mojo::internal::ValidationContext* validation_context) {
  if (!base::FeatureList::IsEnabled({{feature_cpp}})) {
    return false;
  }
  return internal::{{class_name}}_{{method.name}}_Params_Data::Validate(
    data, validation_context);
}
{%- endmacro %}

{%- macro request_validator(class_name, method) %}
{%-   if method.runtime_feature -%}
&ValidateWithRuntimeFeature_{{class_name}}_{{method.name}}
{%-   else -%}
&internal::{{class_name}}_{{method.name}}_Params_Data::Validate
{%-   endif -%}
{%- endmacro -%}

{#--- Begin #}
const char {{class_name}}::Name_[] = "{{module_namespace}}.{{class_name}}";
{%-  if interface.uuid %}
constexpr base::Token {{class_name}}::Uuid_;
{%-  endif %}

{#--- Constants #}
{%-  for constant in interface.constants %}
{%-   if constant.kind|is_string_kind %}
const char {{interface.name}}::{{constant.name}}[] = {{constant|constant_value}};
{%-   else %}
constexpr {{constant.kind|cpp_pod_type}} {{interface.name}}::{{constant.name}};
{%-   endif %}
{%- endfor %}

{{interface.name}}::IPCStableHashFunction {{interface.name}}::MessageToMethodInfo_(mojo::Message& message) {
#if !BUILDFLAG(IS_FUCHSIA)
{%- if interface.methods %}
  switch (static_cast<messages::{{interface.name}}>(message.name())) {
{%-   for method in interface.methods %}
    case messages::{{interface.name}}::k{{method.name}}: {
      return &{{interface.name}}::{{method.name}}_Sym::IPCStableHash;
    }
{%-   endfor %}
  }
{%- endif %}
#endif  // !BUILDFLAG(IS_FUCHSIA)
  return nullptr;
}


const char* {{interface.name}}::MessageToMethodName_(mojo::Message& message) {
#if BUILDFLAG(MOJO_TRACE_ENABLED)
{%- if interface.methods %}
  bool is_response = message.has_flag(mojo::Message::kFlagIsResponse);
  if (!is_response) {
    switch (static_cast<messages::{{interface.name}}>(message.name())) {
{%-   for method in interface.methods %}
      case messages::{{interface.name}}::k{{method.name}}:
            return "Receive {{namespace_as_string}}::{{interface.name}}::{{method.name}}";
{%-   endfor %}
    }
  } else {
    switch (static_cast<messages::{{interface.name}}>(message.name())) {
{%-   for method in interface.methods %}
      case messages::{{interface.name}}::k{{method.name}}:
            return "Receive reply {{namespace_as_string}}::{{interface.name}}::{{method.name}}";
{%-   endfor %}
    }
  }
{%- endif %}
  return "Receive unknown mojo message";
#else
  bool is_response = message.has_flag(mojo::Message::kFlagIsResponse);
  if (is_response) {
    return "Receive mojo reply";
  } else {
    return "Receive mojo message";
  }
#endif // BUILDFLAG(MOJO_TRACE_ENABLED)
}

#if !BUILDFLAG(IS_FUCHSIA)
{%-   for method in interface.methods %}
uint32_t {{interface.name}}::{{method.name}}_Sym::IPCStableHash() {
  // This method's address is used for indetifiying the mojo method name after
  // symbolization. So each IPCStableHash should have a unique address.
  // We cannot use NO_CODE_FOLDING() here - it relies on the uniqueness of
  // __LINE__ value, which is not unique accross different mojo modules.
  // The code below is very similar to NO_CODE_FOLDING, but it uses a unique
  // hash instead of __LINE__.
  constexpr uint32_t kHash = base::MD5Hash32Constexpr(
          "(Impl){{namespace_as_string}}::{{interface.name}}::{{method.name}}");
  const uint32_t hash = kHash;
  base::debug::Alias(&hash);
  return hash;
}
{%-   endfor %}
# endif // !BUILDFLAG(IS_FUCHSIA)

{%-   if interface.runtime_feature %}
{{feature_enabled_helper(interface)}}
{%-   endif %}

{%- for method in interface.methods %}
{%-   if method.sync %}
bool {{class_name}}::{{method.name}}({{interface_macros.declare_sync_method_params("", method)}}) {
  NOTREACHED();
}
{%-   endif %}
{%- endfor %}

{#--- ForwardToCallback definition #}
{%- for method in interface.methods -%}
{%-   if method.response_parameters != None %}
{%-     if method.sync %}
class {{class_name}}_{{method.name}}_HandleSyncResponse
    : public mojo::MessageReceiver {
 public:
  {{class_name}}_{{method.name}}_HandleSyncResponse(
      bool* result
{%-       for param in method.response_parameters -%}
      , {{param.kind|cpp_wrapper_call_type}}* out_{{param.name}}
{%-       endfor %})
      : result_(result)
{%-       for param in method.response_parameters -%}
        , out_{{param.name}}_(out_{{param.name}})
{%-       endfor %} {
    DCHECK(!*result_);
  }

  {{class_name}}_{{method.name}}_HandleSyncResponse(const {{class_name}}_{{method.name}}_HandleSyncResponse&) = delete;
  {{class_name}}_{{method.name}}_HandleSyncResponse& operator=(const {{class_name}}_{{method.name}}_HandleSyncResponse&) = delete;

  bool Accept(mojo::Message* message) override;
 private:
  bool* result_;
{%-       for param in method.response_parameters %}
  {{param.kind|cpp_wrapper_call_type}}* out_{{param.name}}_;
{%-       endfor -%}
};
{%-     endif %}

class {{class_name}}_{{method.name}}_ForwardToCallback
    : public mojo::MessageReceiver {
 public:
  {{class_name}}_{{method.name}}_ForwardToCallback(
      {{class_name}}::{{method.name}}Callback callback
      ) : callback_(std::move(callback)) {
  }

  {{class_name}}_{{method.name}}_ForwardToCallback(const {{class_name}}_{{method.name}}_ForwardToCallback&) = delete;
  {{class_name}}_{{method.name}}_ForwardToCallback& operator=(const {{class_name}}_{{method.name}}_ForwardToCallback&) = delete;

  bool Accept(mojo::Message* message) override;
 private:
  {{class_name}}::{{method.name}}Callback callback_;
};
{%-   endif %}
{%- endfor %}

{{proxy_name}}::{{proxy_name}}(mojo::MessageReceiverWithResponder* receiver)
    : receiver_(receiver) {
{%- if interface|has_estimate_size_methods %}
  if (base::FeatureList::IsEnabled(mojo::features::kMojoPredictiveAllocation)) {
{%-   for method in interface.methods %}
{%-     if method.estimate_message_size %}
{%-       set message_name =
              "base::to_underlying(messages::%s::k%s)"|format(interface.name, method.name) %}
    size_estimator_.EnablePredictiveAllocation({{message_name}});
{%-     endif %}
{%-   endfor %}
  }
{%- endif %}
}

{#--- Proxy definitions #}

{%- for method in interface.methods %}
{%-   set message_name =
          "base::to_underlying(messages::%s::k%s)"|format(interface.name, method.name) %}
{%-   set params_struct = method.param_struct %}
{%-   set params_description =
          "%s.%s request"|format(interface.name, method.name) %}
{%-   set message_typename = "%s_%s_Message"|format(proxy_name, method.name) %}

{%-   if method.sync %}
bool {{proxy_name}}::{{method.name}}(
    {{interface_macros.declare_sync_method_params("param_", method)}}) {
#if BUILDFLAG(MOJO_TRACE_ENABLED)
{%-     set event_name = "Call %s::%s::%s (sync)" % (namespace_as_string,
                                                    class_name, method.name) %}
  {{interface_macros.trace_event(prefix="param_",
                                 method_parameters=method.parameters,
                                 method_name=event_name,
                                 parameter_group="input_parameters",
                                 trace_event_type='_BEGIN')}}
#else
{#- Output a minimal trace event if MOJO_TRACE_ENABLED is false. #}
{%-     set event_name = "%s::%s" % (class_name, method.name) %}
  {{interface_macros.trace_event(method_name=event_name)}}
#endif
  {{check_feature_for_method(method)|indent(2)}}
  const bool kExpectsResponse = true;
  const bool kIsSync = true;
  const bool kAllowInterrupt =
      {% if method.allow_interrupt %}true{% else %}false{% endif %};
{%-   if method.supports_urgent %}
  const bool is_urgent = mojo::UrgentMessageScope::IsInUrgentScope();
{%    else %}
  const bool is_urgent = false;
{%-   endif %}
{{interface_macros.build_message_flags(False, "kIsSync", "kAllowInterrupt",
                                        "is_urgent", "kExpectsResponse",
                                        "kFlags")}}
{{interface_macros.build_serialized_message(
    message_name, method, "param_%s", params_struct, params_description,
    "kFlags", "message")}}

#if defined(ENABLE_IPC_FUZZER)
  message.set_interface_name({{class_name}}::Name_);
  message.set_method_name("{{method.name}}");
#endif

  bool result = false;
  std::unique_ptr<mojo::MessageReceiver> responder(
      new {{class_name}}_{{method.name}}_HandleSyncResponse(
          &result
{%-     for param in method.response_parameters -%}
          , out_param_{{param.name}}
{%-     endfor %}));
  ::mojo::internal::SendMojoMessage(*receiver_, message, std::move(responder));
#if BUILDFLAG(MOJO_TRACE_ENABLED)
  {{interface_macros.trace_event(prefix="out_param_",
                                 method_parameters=method.response_parameters,
                                 method_name=event_name,
                                 parameter_group="sync_response_parameters",
                                 trace_event_type='_END',
                                 dereference_parameters=True)}}
#endif
  return result;
}
{%-   endif %}  {#- if method.sync #}

void {{proxy_name}}::{{method.name}}(
    {{interface_macros.declare_request_params("in_", method)}}) {
#if BUILDFLAG(MOJO_TRACE_ENABLED)
{%- set event_name = "Send %s::%s::%s" % (namespace_as_string, class_name,
                                          method.name) %}
  {{interface_macros.trace_event(prefix="in_",
                                 method_parameters=method.parameters,
                                 method_name=event_name,
                                 parameter_group="input_parameters")}}
#endif
{{check_feature_for_method(method)|indent(2)}}
{%- if method.response_parameters != None %}
  const bool kExpectsResponse = true;
{%- else %}
  const bool kExpectsResponse = false;
{%- endif %}
  const bool kIsSync = false;
  const bool kAllowInterrupt = true;
{%-   if method.supports_urgent %}
  const bool is_urgent = mojo::UrgentMessageScope::IsInUrgentScope();
{%    else %}
  const bool is_urgent = false;
{%-   endif %}
{{interface_macros.build_message_flags(False, "kIsSync", "kAllowInterrupt",
                                       "is_urgent", "kExpectsResponse",
                                       "kFlags")}}
{{interface_macros.build_serialized_message(
    message_name, method, "in_%s", params_struct, params_description,
    "kFlags", "message", True)}}

#if defined(ENABLE_IPC_FUZZER)
  message.set_interface_name({{class_name}}::Name_);
  message.set_method_name("{{method.name}}");
#endif

{%- if method.estimate_message_size %}
  size_estimator_.TrackPayloadSize({{message_name}}, message.payload_num_bytes());
{%- endif %}

{%- if method.response_parameters != None %}
  std::unique_ptr<mojo::MessageReceiver> responder(
      new {{class_name}}_{{method.name}}_ForwardToCallback(
          std::move(callback)));
  ::mojo::internal::SendMojoMessage(*receiver_, message, std::move(responder));
{%- else %}
  // This return value may be ignored as false implies the Connector has
  // encountered an error, which will be visible through other means.
  ::mojo::internal::SendMojoMessage(*receiver_, message);
{%- endif %}
}
{%- endfor %}

{#--- ProxyToResponder definition #}
{%- for method in interface.methods -%}
{%-   if method.response_parameters != None %}
{%-     set message_name =
            "base::to_underlying(messages::%s::k%s)"|format(interface.name, method.name) %}
{%-     set response_params_struct = method.response_param_struct %}
{%-     set params_description =
            "%s.%s response"|format(interface.name, method.name) %}
{%-     set response_message_typename =
            "%s_%s_Response_Message"|format(interface.name, method.name) %}
class {{class_name}}_{{method.name}}_ProxyToResponder : public ::mojo::internal::ProxyToResponder {
 public:
  static {{class_name}}::{{method.name}}Callback CreateCallback(
      ::mojo::Message& message,
      std::unique_ptr<mojo::MessageReceiverWithStatus> responder) {
    std::unique_ptr<{{class_name}}_{{method.name}}_ProxyToResponder> proxy(
        new {{class_name}}_{{method.name}}_ProxyToResponder(
            message, std::move(responder)));
    return base::BindOnce(&{{class_name}}_{{method.name}}_ProxyToResponder::Run,
                          std::move(proxy));
  }

  ~{{class_name}}_{{method.name}}_ProxyToResponder() {
#if DCHECK_IS_ON()
    if (responder_) {
      // If we're being destroyed without being run, we want to ensure the
      // binding endpoint has been closed. This checks for that asynchronously.
      // We pass a bound generated callback to handle the response so that any
      // resulting DCHECK stack will have useful interface type information.
      // Instantiate a ScopedFizzleBlockShutdownTasks to allow this request to
      // fizzle if this happens after shutdown and the endpoint is bound to a
      // BLOCK_SHUTDOWN sequence.
      base::ThreadPoolInstance::ScopedFizzleBlockShutdownTasks fizzler;
      responder_->IsConnectedAsync(base::BindOnce(&OnIsConnectedComplete));
    }
#endif
  }

 private:
  {{class_name}}_{{method.name}}_ProxyToResponder(
      ::mojo::Message& message,
      std::unique_ptr<mojo::MessageReceiverWithStatus> responder)
      : ::mojo::internal::ProxyToResponder(message, std::move(responder)) {
  }

#if DCHECK_IS_ON()
  static void OnIsConnectedComplete(bool connected) {
    DCHECK(!connected)
        << "{{class_name}}::{{method.name}}Callback was destroyed without "
        << "first either being run or its corresponding binding being closed. "
        << "It is an error to drop response callbacks which still correspond "
        << "to an open interface pipe.";
  }
#endif

  void Run(
      {{interface_macros.declare_params("in_", method.response_parameters)}});
};

bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept(
    mojo::Message* message) {
  DCHECK(message->is_serialized());
  internal::{{class_name}}_{{method.name}}_ResponseParams_Data* params =
      reinterpret_cast<
          internal::{{class_name}}_{{method.name}}_ResponseParams_Data*>(
              message->mutable_payload());

{%-     set desc = class_name~"::"~method.name~" response" %}
  {{alloc_params(method.response_param_struct, "params", "message", method.sequential_ordinal, "true")}}
  if (!callback_.is_null())
    std::move(callback_).Run({{pass_params(method.response_parameters)}});
  return true;
}

void {{class_name}}_{{method.name}}_ProxyToResponder::Run(
    {{interface_macros.declare_params("in_", method.response_parameters)}}) {
#if BUILDFLAG(MOJO_TRACE_ENABLED)
{%-     set event_name = "Send reply %s::%s::%s"
               % (namespace_as_string, class_name, method.name) %}
  {{interface_macros.trace_event(prefix="in_",
                                 method_parameters=method.response_parameters,
                                 method_name=event_name,
                                 parameter_group="async_response_parameters",
                                 dereference_parameters=False)}}
#endif
{{interface_macros.build_message_flags(True, "is_sync_", "true", "false",
                                       "false", "kFlags")}}
{{interface_macros.build_serialized_message(
    message_name, method, "in_%s", response_params_struct,
    response_params_description, "kFlags", "message")}}

#if defined(ENABLE_IPC_FUZZER)
  message.set_interface_name({{class_name}}::Name_);
  message.set_method_name("{{method.name}}");
#endif

  message.set_request_id(request_id_);
  message.set_trace_nonce(trace_nonce_);
  ::mojo::internal::SendMojoMessage(*responder_, message);
  // SendMojoMessage() fails silently if the responder connection is closed,
  // or if the message is malformed.
  //
  // TODO(darin): If Accept() returns false due to a malformed message, that
  // may be good reason to close the connection. However, we don't have a
  // way to do that from here. We should add a way.
  responder_ = nullptr;
}
{%-   endif -%}

{%-   if method.sync %}
bool {{class_name}}_{{method.name}}_HandleSyncResponse::Accept(
    mojo::Message* message) {
  DCHECK(message->is_serialized());
  internal::{{class_name}}_{{method.name}}_ResponseParams_Data* params =
      reinterpret_cast<internal::{{class_name}}_{{method.name}}_ResponseParams_Data*>(
          message->mutable_payload());

{%-       set desc = class_name~"::"~method.name~" response" %}
  {{alloc_params(method.response_param_struct, "params", "message", method.sequential_ordinal, "true")}}

{%-       for param in method.response_parameters %}
  *out_{{param.name}}_ = std::move(p_{{param.name}});
{%-       endfor %}
  *result_ = true;
  return true;
}
{%- endif %}

{%- endfor %}

{#--- StubDispatch definition #}

// static
bool {{class_name}}StubDispatch::Accept(
    {{interface.name}}* impl,
    mojo::Message* message) {
{%- if interface.methods %}
{%-   if interface.dispatch_debug_alias %}
  const uint64_t kDebugAliasSentinel0 = 0xC0FFEE42;
  const uint64_t kMessageName = message->header()->name;
  const uint64_t kDebugAliasSentinel1 = 0xDECAFBAD;
  base::debug::Alias(&kDebugAliasSentinel0);
  base::debug::Alias(&kMessageName);
  base::debug::Alias(&kDebugAliasSentinel1);
{%-   endif %}
  switch (static_cast<messages::{{class_name}}>(message->header()->name)) {
{%-   for method in interface.methods %}
    case messages::{{class_name}}::k{{method.name}}: {
{%-     if method.response_parameters == None %}
      DCHECK(message->is_serialized());
      internal::{{class_name}}_{{method.name}}_Params_Data* params =
          reinterpret_cast<internal::{{class_name}}_{{method.name}}_Params_Data*>(
              message->mutable_payload());

{%-       set desc = class_name~"::"~method.name %}
      {{alloc_params(method.param_struct, "params", "message", method.sequential_ordinal, "false")|
          indent(4)}}
      // A null |impl| means no implementation was bound.
      DCHECK(impl);
      impl->{{method.name}}({{pass_params(method.parameters)|indent(8, True)}});
      return true;
{%-     else %}
      break;
{%-     endif %}
    }
{%-   endfor %}
  }
{%- endif %}
  return false;
}

// static
bool {{class_name}}StubDispatch::AcceptWithResponder(
    {{interface.name}}* impl,
    mojo::Message* message,
    std::unique_ptr<mojo::MessageReceiverWithStatus> responder) {
{%- if interface.methods %}
  [[maybe_unused]] const bool message_is_sync =
      message->has_flag(mojo::Message::kFlagIsSync);
  [[maybe_unused]] const uint64_t request_id = message->request_id();
  switch (static_cast<messages::{{class_name}}>(message->header()->name)) {
{%-   for method in interface.methods %}
    case messages::{{class_name}}::k{{method.name}}: {
{%-     if method.response_parameters != None %}
      internal::{{class_name}}_{{method.name}}_Params_Data* params =
          reinterpret_cast<
              internal::{{class_name}}_{{method.name}}_Params_Data*>(
                  message->mutable_payload());

{%-       set desc = class_name~"::"~method.name %}
      {{alloc_params(method.param_struct, "params", "message", method.sequential_ordinal, "false")|
          indent(4)}}
      {{class_name}}::{{method.name}}Callback callback =
          {{class_name}}_{{method.name}}_ProxyToResponder::CreateCallback(
              *message, std::move(responder));
      // A null |impl| means no implementation was bound.
      DCHECK(impl);
      impl->{{method.name}}(
{%- if method.parameters -%}{{pass_params(method.parameters)|indent(8,True)}}, {% endif -%}std::move(callback));
      return true;
{%-     else %}
      break;
{%-     endif %}
    }
{%-   endfor %}
  }
{%- endif %}
  return false;
}

{#--- Feature validators for methods with [RuntimeFeature=] ---#}
{%- if interface.methods|selectattr('runtime_feature') %}
namespace {
{%-   for method in interface.methods %}
{%-     if method.runtime_feature %}
{{ define_validate_with_runtime_feature(class_name, method)}}
{%-     endif %}
{%-   endfor %}
}  // namespace
{%- endif %}

{#--- Table of validation functions (packed or sparse) ---#}
{% if interface.methods and (interface | has_packed_method_ordinals) %}
static const mojo::internal::GenericValidationInfo k{{class_name}}ValidationInfo[] = {
{%-   for i in range(interface.methods | map(attribute='ordinal') | max + 1) -%}
{%-     set method = (interface.methods | selectattr('ordinal', 'equalto', i) | list)[0] %}
{%-     if method %}
    { {{request_validator(class_name, method)}},
{%-       if method.response_parameters != None %}
     &internal::{{class_name}}_{{method.name}}_ResponseParams_Data::Validate},
{%-       else %}
     nullptr /* no response */},
{%-       endif %}
{%-     else %}
    {nullptr, nullptr},  // nonexistent
{%-     endif %}
{%-   endfor %}
};
{%- elif interface.methods %}
static const std::pair<uint32_t, mojo::internal::GenericValidationInfo> k{{class_name}}ValidationInfo[] = {
{%-   for method in interface.methods %}
    {base::to_underlying(messages::{{class_name}}::k{{method.name}}),
     { {{request_validator(class_name, method)}},
{%-     if method.response_parameters != None %}
      &internal::{{class_name}}_{{method.name}}_ResponseParams_Data::Validate}},
{%-     else %}
      nullptr /* no response */}},
{%-     endif %}
{%-   endfor %}
};
{%- endif %}

{#--- Request validator definitions #}

bool {{class_name}}RequestValidator::Accept(mojo::Message* message) {
  {#- Not simply Name_ because there is a mojom interface called MessageReceiver #}
  const char* name = {{qualified_class_name}}::Name_;
{%- if not interface.methods %}
  return mojo::internal::ValidateRequestGeneric(message, name, {});
{%- elif interface | has_packed_method_ordinals %}
  return mojo::internal::ValidateRequestGenericPacked(message, name, k{{class_name}}ValidationInfo);
{%- else %}
  return mojo::internal::ValidateRequestGeneric(message, name, k{{class_name}}ValidationInfo);
{%- endif %}
}

{#--- Response validator definitions #}
{% if interface|has_callbacks %}
bool {{class_name}}ResponseValidator::Accept(mojo::Message* message) {
  const char* name = {{qualified_class_name}}::Name_;
{%-  if interface | has_packed_method_ordinals %}
  return mojo::internal::ValidateResponseGenericPacked(message, name, k{{class_name}}ValidationInfo);
{%-  else %}
  return mojo::internal::ValidateResponseGeneric(message, name, k{{class_name}}ValidationInfo);
{%   endif %}
}
{%- endif -%}