blob: 0b5f8a8a7578f16ec00520834f807a4eebe62954 [file] [log] [blame]
{%- import "interface_macros.tmpl" as interface_macros %}
{%- import "struct_macros.tmpl" as struct_macros %}
{%- from "enum_macros.tmpl" import is_valid_enum_def %}
{%- from "enum_macros.tmpl" import global_enum_operators_def %}
{%- set class_name = interface.name %}
{%- set proxy_name = interface.name ~ "Proxy" %}
{%- macro alloc_params(struct) %}
{%- for param in struct.packed.packed_fields_in_ordinal_order %}
{{param.field.kind|cpp_result_type}} p_{{param.field.name}} {};
{%- endfor %}
{{struct_macros.deserialize(struct, "params", "p_%s")}}
{%- endmacro %}
{%- macro pass_params(parameters) %}
{%- for param in parameters %}
{%- if param.kind|is_move_only_kind -%}
p_{{param.name}}.Pass()
{%- else -%}
p_{{param.name}}
{%- endif -%}
{%- if not loop.last %}, {% endif %}
{%- endfor %}
{%- endmacro %}
{%- macro build_message(struct, struct_display_name) -%}
{{struct_macros.serialize(struct, struct_display_name, "in_%s", "params", "builder.buffer()", false)}}
params->EncodePointersAndHandles(builder.message()->mutable_handles());
{%- endmacro %}
{#--- Begin #}
{%- if interface.service_name %}
const char {{class_name}}::Name_[] = "{{interface.service_name}}";
{%- endif %}
const uint32_t {{class_name}}::Version_;
{#--- Constants #}
{%- for constant in interface.constants %}
{%- if constant.kind|is_integral_kind %}
const {{constant.kind|cpp_pod_type}} {{interface.name}}::{{constant.name}};
{%- else %}
const {{constant.kind|cpp_pod_type}} {{interface.name}}::{{constant.name}} = {{constant|constant_value}};
{%- endif %}
{%- endfor %}
{#--- Enums #}
{%- for enum in interface.enums %}
{{is_valid_enum_def(enum, class_name=interface.name)}}
{{global_enum_operators_def(enum, class_name=interface.name)}}
{%- endfor %}
{#--- ForwardToCallback definition #}
{%- for method in interface.methods -%}
{%- if method.response_parameters != None %}
class {{class_name}}_{{method.name}}_ForwardToCallback
: public mojo::MessageReceiver {
public:
{{class_name}}_{{method.name}}_ForwardToCallback(
const {{class_name}}::{{method.name}}Callback& callback)
: callback_(callback) {
}
bool Accept(mojo::Message* message) override;
private:
{{class_name}}::{{method.name}}Callback callback_;
MOJO_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());
params->DecodePointersAndHandles(message->mutable_handles());
{{alloc_params(method.response_param_struct)}}
callback_.Run({{pass_params(method.response_parameters)}});
return true;
}
{%- endif %}
{%- endfor %}
{{proxy_name}}::{{proxy_name}}(mojo::MessageReceiverWithResponder* receiver)
: ControlMessageProxy(receiver) {
}
{#--- Proxy definitions #}
{%- for method in interface.methods %}
{%- set message_name =
"%s::MessageOrdinals::%s"|format(interface.name, method.name) %}
{%- set params_struct = method.param_struct %}
{%- set params_description =
"%s.%s request"|format(interface.name, method.name) %}
void {{proxy_name}}::{{method.name}}(
{{interface_macros.declare_request_params("in_", method)}}) {
{{struct_macros.get_serialized_size(params_struct, "in_%s")}}
{%- if method.response_parameters != None %}
mojo::RequestMessageBuilder builder(
static_cast<uint32_t>({{message_name}}), size);
{%- else %}
mojo::MessageBuilder builder(
static_cast<uint32_t>({{message_name}}), size);
{%- endif %}
{{build_message(params_struct, params_description)}}
{%- if method.response_parameters != None %}
mojo::MessageReceiver* responder =
new {{class_name}}_{{method.name}}_ForwardToCallback(callback);
if (!receiver_->AcceptWithResponder(builder.message(), responder))
delete responder;
{%- else %}
bool ok = receiver_->Accept(builder.message());
// This return value may be ignored as !ok implies the Connector has
// encountered an error, which will be visible through other means.
MOJO_ALLOW_UNUSED_LOCAL(ok);
{%- endif %}
}
{%- endfor %}
{#--- ProxyToResponder definition #}
{%- for method in interface.methods -%}
{%- if method.response_parameters != None %}
{%- set message_name =
"%s::MessageOrdinals::%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) %}
// This class implements a method's response callback: it serializes the
// response args into a mojo message and passes it to the MessageReceiver it
// was created with.
class {{class_name}}_{{method.name}}_ProxyToResponder
: public {{class_name}}::{{method.name}}Callback::Runnable {
public:
~{{class_name}}_{{method.name}}_ProxyToResponder() override {
// Is the Mojo application destroying the callback without running it
// and without first closing the pipe?
bool callback_was_dropped = responder_ && responder_->IsValid();
// If the Callback was dropped then deleting the responder will close
// the pipe so the calling application knows to stop waiting for a reply.
delete responder_;
MOJO_DCHECK(!callback_was_dropped) << "The callback passed to "
"{{class_name}}::{{method.name}}({%- if method.parameters -%}{{pass_params(method.parameters)}}, {% endif -%}callback) "
"was never run.";
}
{{class_name}}_{{method.name}}_ProxyToResponder(
uint64_t request_id,
mojo::MessageReceiverWithStatus* responder)
: request_id_(request_id),
responder_(responder) {
}
void Run({{interface_macros.declare_params_as_args("in_", method.response_parameters)}}) const override;
private:
uint64_t request_id_;
mutable mojo::MessageReceiverWithStatus* responder_;
MOJO_DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ProxyToResponder);
};
void {{class_name}}_{{method.name}}_ProxyToResponder::Run(
{{interface_macros.declare_params_as_args("in_", method.response_parameters)}}) const {
{{struct_macros.get_serialized_size(response_params_struct, "in_%s")}}
mojo::ResponseMessageBuilder builder(
static_cast<uint32_t>({{message_name}}), size, request_id_);
{{build_message(response_params_struct, params_description)}}
bool ok = responder_->Accept(builder.message());
MOJO_ALLOW_UNUSED_LOCAL(ok);
// TODO(darin): !ok returned here 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.
delete responder_;
responder_ = nullptr;
}
{%- endif -%}
{%- endfor %}
{{class_name}}Stub::{{class_name}}Stub()
: sink_(nullptr),
control_message_handler_({{interface.name}}::Version_) {
}
{{class_name}}Stub::~{{interface.name}}Stub() {}
{#--- Stub definition #}
bool {{class_name}}Stub::Accept(mojo::Message* message) {
if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
return control_message_handler_.Accept(message);
{%- if interface.methods %}
{{interface.name}}::MessageOrdinals method_ordinal =
static_cast<{{interface.name}}::MessageOrdinals>(message->header()->name);
switch (method_ordinal) {
{%- for method in interface.methods %}
case {{interface.name}}::MessageOrdinals::{{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());
params->DecodePointersAndHandles(message->mutable_handles());
{{alloc_params(method.param_struct)|indent(4)}}
// A null |sink_| means no implementation was bound.
assert(sink_);
sink_->{{method.name}}({{pass_params(method.parameters)}});
return true;
{%- else %}
break;
{%- endif %}
}
{%- endfor %}
}
{%- endif %}
return false;
}
bool {{class_name}}Stub::AcceptWithResponder(
mojo::Message* message, mojo::MessageReceiverWithStatus* responder) {
if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
return control_message_handler_.AcceptWithResponder(message, responder);
{%- if interface.methods %}
{{interface.name}}::MessageOrdinals method_ordinal =
static_cast<{{interface.name}}::MessageOrdinals>(message->header()->name);
switch (method_ordinal) {
{%- for method in interface.methods %}
case {{interface.name}}::MessageOrdinals::{{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());
params->DecodePointersAndHandles(message->mutable_handles());
{{class_name}}::{{method.name}}Callback::Runnable* runnable =
new {{class_name}}_{{method.name}}_ProxyToResponder(
message->request_id(), responder);
{{class_name}}::{{method.name}}Callback callback(runnable);
{{alloc_params(method.param_struct)|indent(4)}}
// A null |sink_| means no implementation was bound.
assert(sink_);
sink_->{{method.name}}(
{%- if method.parameters -%}{{pass_params(method.parameters)}}, {% endif -%}callback);
return true;
{%- else %}
break;
{%- endif %}
}
{%- endfor %}
}
{%- endif %}
return false;
}
{#--- Request validator definitions #}
mojo::internal::ValidationError {{class_name}}RequestValidator::Validate(
const mojo::Message* message,
std::string* err) {
mojo::internal::ValidationError retval;
if (mojo::internal::ControlMessageHandler::IsControlMessage(message)) {
retval = mojo::internal::ValidateControlRequest(message, err);
if (retval != mojo::internal::ValidationError::NONE) {
MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err)
<< "request validation error for interface '{{interface.name}}', "
"message name '" << message->header()->name << "': " <<
(err ? *err : "");
ReportValidationError(retval, err);
return retval;
}
return mojo::internal::ValidationError::NONE;
}
{{interface.name}}::MessageOrdinals method_ordinal =
static_cast<{{interface.name}}::MessageOrdinals>(message->header()->name);
switch (method_ordinal) {
{%- for method in interface.methods %}
case {{interface.name}}::MessageOrdinals::{{method.name}}: {
{%- if method.response_parameters != None %}
retval =
mojo::internal::ValidateMessageIsRequestExpectingResponse(message,
err);
if (retval != mojo::internal::ValidationError::NONE) {
MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err)
<< "request validation error for interface '{{interface.name}}', "
"message name '" << message->header()->name << "': " <<
(err ? *err : "");
ReportValidationError(retval, err);
return retval;
}
{%- else %}
retval = mojo::internal::ValidateMessageIsRequestWithoutResponse(message,
err);
if (retval != mojo::internal::ValidationError::NONE) {
MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err)
<< "request validation error for interface '{{interface.name}}', "
"message name '" << message->header()->name << "': " <<
(err ? *err : "");
ReportValidationError(retval, err);
return retval;
}
{%- endif %}
retval = mojo::internal::ValidateMessagePayload<
internal::{{class_name}}_{{method.name}}_Params_Data>(message,
err);
if (retval != mojo::internal::ValidationError::NONE) {
MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err)
<< "request validation error for interface '{{interface.name}}', "
"message name '" << message->header()->name << "': " <<
(err ? *err : "");
ReportValidationError(retval, err);
return retval;
}
return mojo::internal::ValidationError::NONE;
}
{%- endfor %}
default:
break;
}
// Unrecognized message.
MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << "unknown request message name '"
<< message->header()->name
<< "' for interface "
"'{{interface.name}}'";
ReportValidationError(
mojo::internal::ValidationError::MESSAGE_HEADER_UNKNOWN_METHOD, err);
return mojo::internal::ValidationError::MESSAGE_HEADER_UNKNOWN_METHOD;
}
{#--- Response validator definitions #}
{% if interface|has_callbacks %}
mojo::internal::ValidationError {{class_name}}ResponseValidator::Validate(
const mojo::Message* message,
std::string* err) {
mojo::internal::ValidationError retval;
if (mojo::internal::ControlMessageHandler::IsControlMessage(message)) {
retval = mojo::internal::ValidateControlResponse(message, err);
if (retval != mojo::internal::ValidationError::NONE) {
MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err)
<< "response validation error for interface '{{interface.name}}',"
" message name '" << message->header()->name << "': " <<
(err ? *err : "");
ReportValidationError(retval, err);
return retval;
}
return mojo::internal::ValidationError::NONE;
}
retval = mojo::internal::ValidateMessageIsResponse(message, err);
if (retval != mojo::internal::ValidationError::NONE) {
MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err)
<< "response validation error for interface '{{interface.name}}',"
" message name '" << message->header()->name << "': " <<
(err ? *err : "");
ReportValidationError(retval, err);
return retval;
}
{{class_name}}::MessageOrdinals method_ordinal =
static_cast<{{class_name}}::MessageOrdinals>(message->header()->name);
switch (method_ordinal) {
{%- for method in interface.methods if method.response_parameters != None %}
case {{class_name}}::MessageOrdinals::{{method.name}}: {
retval = mojo::internal::ValidateMessagePayload<
internal::{{class_name}}_{{method.name}}_ResponseParams_Data>(
message, err);
if (retval != mojo::internal::ValidationError::NONE) {
MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err)
<< "response validation error for interface '{{interface.name}}',"
" message name '" << message->header()->name << "': " <<
(err ? *err : "");
ReportValidationError(retval, err);
return retval;
}
return mojo::internal::ValidationError::NONE;
}
{%- endfor %}
default:
break;
}
// Unrecognized message.
MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << "unknown response message name '"
<< message->header()->name
<< "' for interface "
"'{{interface.name}}'";
ReportValidationError(
mojo::internal::ValidationError::MESSAGE_HEADER_UNKNOWN_METHOD, err);
return mojo::internal::ValidationError::MESSAGE_HEADER_UNKNOWN_METHOD;
}
{%- endif -%}