blob: aba18380af7250f682a19e24850246062dcbfc17 [file] [log] [blame]
{%- 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(namespace|replace(".","::")) %}
{%- macro alloc_params(struct, params, message, description) %}
mojo::internal::SerializationContext serialization_context;
serialization_context.handles.Swap(({{message}})->mutable_handles());
serialization_context.associated_endpoint_handles.swap(
*({{message}})->mutable_associated_endpoint_handles());
bool success = true;
{%- for param in struct.packed.packed_fields_in_ordinal_order %}
{{param.field.kind|cpp_wrapper_type}} p_{{param.field.name}}{};
{%- endfor %}
{{struct.name}}DataView input_data_view({{params}}, &serialization_context);
{{struct_macros.deserialize(struct, "input_data_view", "p_%s", "success")}}
if (!success) {
ReportValidationErrorForMessage(
{{message}},
mojo::internal::VALIDATION_ERROR_DESERIALIZATION_FAILED,
"{{description}} deserializer");
return false;
}
{%- endmacro %}
{%- macro pass_params(parameters) %}
{%- for param in parameters %}
std::move(p_{{param.name}})
{%- if not loop.last %}, {% endif %}
{%- endfor %}
{%- endmacro %}
{%- macro build_message(struct, input_pattern, struct_display_name,
serialization_context) -%}
{{struct_macros.serialize(struct, struct_display_name, input_pattern,
"params", "builder.buffer()",
serialization_context)}}
({{serialization_context}})->handles.Swap(
builder.message()->mutable_handles());
({{serialization_context}})->associated_endpoint_handles.swap(
*builder.message()->mutable_associated_endpoint_handles());
{%- endmacro %}
{#--- Begin #}
const char {{class_name}}::Name_[] = "{{namespace_as_string}}::{{class_name}}";
{#--- Constants #}
{%- for constant in interface.constants %}
{%- if constant.kind|is_string_kind %}
const char {{interface.name}}::{{constant.name}}[] = {{constant|constant_value}};
{%- endif %}
{%- endfor %}
{%- for method in interface.methods %}
{%- if method.sync %}
bool {{class_name}}::{{method.name}}({{interface_macros.declare_sync_method_params("", method)}}) {
NOTREACHED();
return false;
}
{%- 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_type}}* out_{{param.name}}
{%- endfor %})
: result_(result)
{%- for param in method.response_parameters -%}
, out_{{param.name}}_(out_{{param.name}})
{%- endfor %} {
DCHECK(!*result_);
}
bool Accept(mojo::Message* message) override;
private:
bool* result_;
{%- for param in method.response_parameters %}
{{param.kind|cpp_wrapper_type}}* out_{{param.name}}_;
{%- endfor -%}
DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_HandleSyncResponse);
};
bool {{class_name}}_{{method.name}}_HandleSyncResponse::Accept(
mojo::Message* message) {
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", desc)}}
{%- for param in method.response_parameters %}
*out_{{param.name}}_ = std::move(p_{{param.name}});
{%- endfor %}
mojo::internal::SyncMessageResponseSetup::SetCurrentSyncResponseMessage(
message);
*result_ = true;
return true;
}
{%- endif %}
class {{class_name}}_{{method.name}}_ForwardToCallback
: public mojo::MessageReceiver {
public:
{{class_name}}_{{method.name}}_ForwardToCallback(
{%- if use_once_callback %}
{{class_name}}::{{method.name}}Callback callback
{%- else %}
const {{class_name}}::{{method.name}}Callback& callback
{%- endif %}
) : callback_(std::move(callback)) {
}
bool Accept(mojo::Message* message) override;
private:
{{class_name}}::{{method.name}}Callback callback_;
DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ForwardToCallback);
};
bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept(
mojo::Message* message) {
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", desc)}}
if (!callback_.is_null()) {
mojo::internal::MessageDispatchContext context(message);
std::move(callback_).Run({{pass_params(method.response_parameters)}});
}
return true;
}
{%- endif %}
{%- endfor %}
{{proxy_name}}::{{proxy_name}}(mojo::MessageReceiverWithResponder* receiver)
: receiver_(receiver) {
}
{#--- Proxy definitions #}
{%- for method in interface.methods %}
{%- set message_name =
"internal::k%s_%s_Name"|format(interface.name, method.name) %}
{%- set params_struct = method.param_struct %}
{%- set params_description =
"%s.%s request"|format(interface.name, method.name) %}
{%- if method.sync %}
bool {{proxy_name}}::{{method.name}}(
{{interface_macros.declare_sync_method_params("param_", method)}}) {
mojo::internal::SerializationContext serialization_context;
{{struct_macros.get_serialized_size(params_struct, "param_%s",
"&serialization_context")}}
mojo::internal::MessageBuilder builder(
{{message_name}},
mojo::Message::kFlagIsSync | mojo::Message::kFlagExpectsResponse,
size, serialization_context.associated_endpoint_count);
{{build_message(params_struct, "param_%s", params_description,
"&serialization_context")}}
bool result = false;
std::unique_ptr<mojo::MessageReceiver> responder(
new {{class_name}}_{{method.name}}_HandleSyncResponse(
&result
{%- for param in method.response_parameters -%}
, param_{{param.name}}
{%- endfor %}));
ignore_result(receiver_->AcceptWithResponder(builder.message(),
std::move(responder)));
return result;
}
{%- endif %}
void {{proxy_name}}::{{method.name}}(
{{interface_macros.declare_request_params("in_", method, use_once_callback)}}) {
mojo::internal::SerializationContext serialization_context;
{{struct_macros.get_serialized_size(params_struct, "in_%s",
"&serialization_context")}}
{%- if method.response_parameters != None %}
constexpr uint32_t kFlags = mojo::Message::kFlagExpectsResponse;
{%- else %}
constexpr uint32_t kFlags = 0;
{%- endif %}
mojo::internal::MessageBuilder builder(
{{message_name}}, kFlags, size,
serialization_context.associated_endpoint_count);
{{build_message(params_struct, "in_%s", params_description,
"&serialization_context")}}
{%- if method.response_parameters != None %}
std::unique_ptr<mojo::MessageReceiver> responder(
new {{class_name}}_{{method.name}}_ForwardToCallback(
std::move(callback)));
ignore_result(receiver_->AcceptWithResponder(builder.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.
ignore_result(receiver_->Accept(builder.message()));
{%- endif %}
}
{%- endfor %}
{#--- ProxyToResponder definition #}
{%- for method in interface.methods -%}
{%- if method.response_parameters != None %}
{%- set message_name =
"internal::k%s_%s_Name"|format(interface.name, method.name) %}
{%- set response_params_struct = method.response_param_struct %}
{%- set params_description =
"%s.%s response"|format(interface.name, method.name) %}
class {{class_name}}_{{method.name}}_ProxyToResponder {
public:
static {{class_name}}::{{method.name}}Callback CreateCallback(
uint64_t request_id,
bool is_sync,
std::unique_ptr<mojo::MessageReceiverWithStatus> responder) {
std::unique_ptr<{{class_name}}_{{method.name}}_ProxyToResponder> proxy(
new {{class_name}}_{{method.name}}_ProxyToResponder(
request_id, is_sync, std::move(responder)));
return base::Bind(&{{class_name}}_{{method.name}}_ProxyToResponder::Run,
base::Passed(&proxy));
}
~{{class_name}}_{{method.name}}_ProxyToResponder() {
#if DCHECK_IS_ON()
if (responder_) {
// Is the Service destroying the callback without running it
// and without first closing the pipe?
responder_->DCheckInvalid("The callback passed to "
"{{class_name}}::{{method.name}}() was never run.");
}
#endif
// If the Callback was dropped then deleting the responder will close
// the pipe so the calling application knows to stop waiting for a reply.
responder_ = nullptr;
}
private:
{{class_name}}_{{method.name}}_ProxyToResponder(
uint64_t request_id,
bool is_sync,
std::unique_ptr<mojo::MessageReceiverWithStatus> responder)
: request_id_(request_id),
is_sync_(is_sync),
responder_(std::move(responder)) {
}
void Run(
{{interface_macros.declare_responder_params(
"in_", method.response_parameters, for_blink)}});
uint64_t request_id_;
bool is_sync_;
std::unique_ptr<mojo::MessageReceiverWithStatus> responder_;
DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ProxyToResponder);
};
void {{class_name}}_{{method.name}}_ProxyToResponder::Run(
{{interface_macros.declare_responder_params(
"in_", method.response_parameters, for_blink)}}) {
mojo::internal::SerializationContext serialization_context;
{{struct_macros.get_serialized_size(response_params_struct, "in_%s",
"&serialization_context")}}
uint32_t flags = (is_sync_ ? mojo::Message::kFlagIsSync : 0) |
mojo::Message::kFlagIsResponse;
mojo::internal::MessageBuilder builder(
{{message_name}}, flags, size,
serialization_context.associated_endpoint_count);
builder.message()->set_request_id(request_id_);
{{build_message(response_params_struct, "in_%s", params_description,
"&serialization_context")}}
ignore_result(responder_->Accept(builder.message()));
// TODO(darin): Accept() returning false indicates a malformed message, and
// 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 -%}
{%- endfor %}
{#--- StubDispatch definition #}
// static
bool {{class_name}}StubDispatch::Accept(
{{interface.name}}* impl,
mojo::Message* message) {
{%- if interface.methods %}
switch (message->header()->name) {
{%- for method in interface.methods %}
case internal::k{{class_name}}_{{method.name}}_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", desc)|
indent(4)}}
// A null |impl| means no implementation was bound.
assert(impl);
TRACE_EVENT0("mojom", "{{class_name}}::{{method.name}}");
mojo::internal::MessageDispatchContext context(message);
impl->{{method.name}}({{pass_params(method.parameters)}});
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 %}
switch (message->header()->name) {
{%- for method in interface.methods %}
case internal::k{{class_name}}_{{method.name}}_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", desc)|
indent(4)}}
{{class_name}}::{{method.name}}Callback callback =
{{class_name}}_{{method.name}}_ProxyToResponder::CreateCallback(
message->request_id(),
message->has_flag(mojo::Message::kFlagIsSync),
std::move(responder));
// A null |impl| means no implementation was bound.
assert(impl);
TRACE_EVENT0("mojom", "{{class_name}}::{{method.name}}");
mojo::internal::MessageDispatchContext context(message);
impl->{{method.name}}(
{%- if method.parameters -%}{{pass_params(method.parameters)}}, {% endif -%}std::move(callback));
return true;
{%- else %}
break;
{%- endif %}
}
{%- endfor %}
}
{%- endif %}
return false;
}
{#--- Request validator definitions #}
bool {{class_name}}RequestValidator::Accept(mojo::Message* message) {
if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
return true;
mojo::internal::ValidationContext validation_context(
message->payload(), message->payload_num_bytes(),
message->handles()->size(), message->payload_num_interface_ids(), message,
"{{class_name}} RequestValidator");
switch (message->header()->name) {
{%- for method in interface.methods %}
case internal::k{{class_name}}_{{method.name}}_Name: {
{%- if method.response_parameters != None %}
if (!mojo::internal::ValidateMessageIsRequestExpectingResponse(
message, &validation_context)) {
return false;
}
{%- else %}
if (!mojo::internal::ValidateMessageIsRequestWithoutResponse(
message, &validation_context)) {
return false;
}
{%- endif %}
if (!mojo::internal::ValidateMessagePayload<
internal::{{class_name}}_{{method.name}}_Params_Data>(
message, &validation_context)) {
return false;
}
return true;
}
{%- endfor %}
default:
break;
}
// Unrecognized message.
ReportValidationError(
&validation_context,
mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD);
return false;
}
{#--- Response validator definitions #}
{% if interface|has_callbacks %}
bool {{class_name}}ResponseValidator::Accept(mojo::Message* message) {
if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
return true;
mojo::internal::ValidationContext validation_context(
message->payload(), message->payload_num_bytes(),
message->handles()->size(), message->payload_num_interface_ids(), message,
"{{class_name}} ResponseValidator");
if (!mojo::internal::ValidateMessageIsResponse(message, &validation_context))
return false;
switch (message->header()->name) {
{%- for method in interface.methods if method.response_parameters != None %}
case internal::k{{class_name}}_{{method.name}}_Name: {
if (!mojo::internal::ValidateMessagePayload<
internal::{{class_name}}_{{method.name}}_ResponseParams_Data>(
message, &validation_context)) {
return false;
}
return true;
}
{%- endfor %}
default:
break;
}
// Unrecognized message.
ReportValidationError(
&validation_context,
mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD);
return false;
}
{%- endif -%}