| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "{{module.path}}-mojolpm.h" |
| |
| #include <functional> |
| |
| #include "base/functional/bind.h" |
| #include "mojo/public/cpp/bindings/lib/default_construct_tag_internal.h" |
| |
| {% for extra_traits_header in all_extra_traits_headers %} |
| #include "{{extra_traits_header}}" |
| {%- endfor %} |
| |
| {%- import "mojolpm_macros.tmpl" as util %} |
| {%- import "mojolpm_from_proto_macros.tmpl" as from_proto %} |
| {%- import "mojolpm_to_proto_macros.tmpl" as to_proto %} |
| {%- import "mojolpm_traits_specialization_macros.tmpl" as traits_specialization %} |
| |
| namespace mojo { |
| {%- for struct in structs %} |
| {{- traits_specialization.define_struct(struct) }} |
| {%- endfor %} |
| |
| {%- for union in unions %} |
| {{ traits_specialization.define_union(union) }} |
| {%- endfor %} |
| } // namespace mojo |
| |
| namespace mojolpm { |
| {%- for enum in all_enums %} |
| {{- from_proto.define_enum(enum) }} |
| {{- to_proto.define_enum(enum) }} |
| {%- endfor %} |
| |
| {%- for struct in structs %} |
| {%- set proto_type = "::mojolpm" ~ (struct|get_qualified_name_for_kind(flatten_nested_kind=True)) %} |
| {%- set struct_type = proto_type ~ "_ProtoStruct" %} |
| {%- for field in struct.fields %} |
| {%- set name = field.name|camel_to_under %} |
| {%- set kind = field.kind %} |
| {%- if kind|is_array_kind or kind|is_map_kind %} |
| {{- from_proto.define(struct_type, kind, name) }} |
| {{- to_proto.define(struct_type, kind, name) }} |
| {%- endif %} |
| {%- endfor %} |
| {{- from_proto.define_struct(struct) }} |
| {{- to_proto.define_struct(struct) }} |
| {%- endfor %} |
| |
| {%- for union in unions %} |
| {%- set proto_type = "::mojolpm" ~ (union|get_qualified_name_for_kind(flatten_nested_kind=True)) %} |
| {%- set union_type = proto_type ~ "_ProtoUnion" %} |
| {%- for field in union.fields %} |
| {%- set name = field.name|camel_to_under %} |
| {%- set kind = field.kind %} |
| {%- if kind|is_array_kind or kind|is_map_kind %} |
| {{- from_proto.define(union_type, kind, name)}} |
| {{- to_proto.define(union_type, kind, name)}} |
| {%- endif %} |
| {%- endfor %} |
| {{- from_proto.define_union(union) }} |
| {{- to_proto.define_union(union) }} |
| {%- endfor %} |
| |
| {%- for interface in interfaces %} |
| {%- set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %} |
| {%- set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %} |
| class {{interface.name}}Impl : public {{mojom_type}} { |
| public: |
| {{interface.name}}Impl() { |
| } |
| |
| {%- for method in interface.methods -%}{{"\n"}} |
| void {{method.name}}({{ "\n" }} |
| {%- for param in method.parameters -%} |
| {%- set name = param.name|camel_to_under -%} |
| {%- set kind = param.kind -%} |
| {%- set param_mojom_type = kind|cpp_wrapper_param_type(add_same_module_namespaces=true) -%} |
| {{ ",\n" if not loop.first }} {{param_mojom_type}} {{name}} |
| {%- endfor -%} |
| {%- if method.response_parameters != None -%} |
| {{ ",\n" if method.parameters }} {{mojom_type}}::{{method.name}}Callback callback |
| {%- endif -%} |
| ) override { |
| {%- for param in method.parameters -%} |
| {%- set name = param.name|camel_to_under -%} |
| {%- set kind = param.kind -%} |
| {{ util.add_instance(kind, name, False)|indent(2, True) }} |
| {%- endfor %} |
| mojolpmdbg("{{interface.name}}Impl.{{method.name}}\n"); |
| {%- if method.response_parameters != None %} |
| mojolpm::GetContext()->AddInstance<{{mojom_type}}::{{method.name}}Callback>(std::move(callback)); |
| {%- endif %} |
| } |
| {%- endfor %} |
| }; |
| |
| bool FromProto(uint32_t input, |
| ::mojo::PendingRemote<{{mojom_type}}>& output) { |
| bool result = false; |
| ::mojo::Remote<{{mojom_type}}>* output_ptr = nullptr; |
| |
| if (input) { |
| output_ptr = mojolpm::GetContext()->GetInstance<::mojo::Remote<{{mojom_type}}>>(input); |
| if (output_ptr) { |
| // TODO(markbrand): look for a cleaner way to handle this check. |
| if (!output_ptr->is_bound() || (output_ptr->internal_state() |
| && output_ptr->internal_state()->has_pending_callbacks())) { |
| // not safe to Unbind, so fail instead. |
| output_ptr = nullptr; |
| } else { |
| output = output_ptr->Unbind(); |
| result = true; |
| } |
| } |
| } else { |
| auto impl = std::make_unique<{{interface.name}}Impl>(); |
| auto receiver_ptr = |
| std::make_unique<::mojo::Receiver<{{mojom_type}}>>( |
| impl.get(), output.InitWithNewPipeAndPassReceiver()); |
| mojolpm::GetContext()->AddInstance(std::move(impl)); |
| mojolpm::GetContext()->AddInstance(std::move(receiver_ptr)); |
| result = true; |
| } |
| |
| return result; |
| } |
| |
| bool ToProto(::mojo::PendingRemote<{{mojom_type}}>&& input, |
| uint32_t& output) { |
| ::mojo::Remote<{{mojom_type}}> remote(std::move(input)); |
| int next_id = NextId<{{mojom_type}}>(); |
| output = mojolpm::GetContext()->AddInstance(next_id, std::move(remote)); |
| return true; |
| } |
| |
| bool FromProto(uint32_t input, |
| ::mojo::PendingReceiver<{{mojom_type}}>& output) { |
| ::mojo::Remote<{{mojom_type}}> remote = ::mojo::Remote<{{mojom_type}}>(); |
| output = remote.BindNewPipeAndPassReceiver(); |
| mojolpm::GetContext()->AddInstance(input, std::move(remote)); |
| return true; |
| } |
| |
| bool ToProto(::mojo::PendingReceiver<{{mojom_type}}>&& input, |
| uint32_t& output) { |
| // This should only get called from callbacks into the fuzzer, ie from one of |
| // the XxxImpls or from a return callback. Since that is the case, we want to |
| // bind the receiver and store it. |
| |
| auto impl = std::make_unique<{{interface.name}}Impl>(); |
| auto receiver_ptr = std::make_unique<::mojo::Receiver<{{mojom_type}}>>( |
| impl.get(), std::move(input)); |
| mojolpm::GetContext()->AddInstance(std::move(impl)); |
| output = mojolpm::GetContext()->AddInstance(std::move(receiver_ptr)); |
| return true; |
| } |
| |
| bool FromProto(uint32_t input, |
| ::mojo::PendingAssociatedRemote<{{mojom_type}}>& output) { |
| mojolpmdbg("PendingAssociatedRemote {{interface.name}}\n"); |
| bool result = false; |
| ::mojo::AssociatedRemote<{{mojom_type}}>* output_ptr; |
| |
| if (input) { |
| output_ptr = mojolpm::GetContext()->GetInstance<::mojo::AssociatedRemote<{{mojom_type}}>>(input); |
| if (output_ptr) { |
| // TODO(markbrand): look for a cleaner way to handle this check. |
| if (!output_ptr->is_bound() || (output_ptr->internal_state() |
| && output_ptr->internal_state()->has_pending_callbacks())) { |
| // not safe to Unbind, so fail instead. |
| output_ptr = nullptr; |
| } else { |
| output = output_ptr->Unbind(); |
| result = true; |
| } |
| } |
| } else { |
| auto impl = std::make_unique<{{interface.name}}Impl>(); |
| auto receiver_ptr = |
| std::make_unique<::mojo::AssociatedReceiver<{{mojom_type}}>>( |
| impl.get(), output.InitWithNewEndpointAndPassReceiver()); |
| mojolpm::GetContext()->AddInstance(std::move(impl)); |
| mojolpm::GetContext()->AddInstance(std::move(receiver_ptr)); |
| result = true; |
| } |
| |
| return result; |
| } |
| |
| bool ToProto(::mojo::PendingAssociatedRemote<{{mojom_type}}>&& input, |
| uint32_t& output) { |
| ::mojo::AssociatedRemote<{{mojom_type}}> remote(std::move(input)); |
| int next_id = NextId<{{mojom_type}}>(); |
| output = mojolpm::GetContext()->AddInstance(next_id, std::move(remote)); |
| return true; |
| } |
| |
| bool FromProto(uint32_t input, |
| ::mojo::PendingAssociatedReceiver<{{mojom_type}}>& output) { |
| ::mojo::AssociatedRemote<{{mojom_type}}> remote = ::mojo::AssociatedRemote<{{mojom_type}}>(); |
| output = remote.BindNewEndpointAndPassReceiver(); |
| mojolpm::GetContext()->AddInstance(input, std::move(remote)); |
| return true; |
| } |
| |
| bool ToProto(::mojo::PendingAssociatedReceiver<{{mojom_type}}>&& input, |
| uint32_t& output) { |
| // This should only get called from callbacks into the fuzzer, ie from one of |
| // the XxxImpls or from a return callback. Since that is the case, we want to |
| // bind the receiver and store it. |
| |
| auto impl = std::make_unique<{{interface.name}}Impl>(); |
| auto receiver_ptr = std::make_unique<::mojo::AssociatedReceiver<{{mojom_type}}>>( |
| impl.get(), std::move(input)); |
| mojolpm::GetContext()->AddInstance(std::move(impl)); |
| output = mojolpm::GetContext()->AddInstance(std::move(receiver_ptr)); |
| return true; |
| }{{"\n"-}} |
| |
| {%- for method in interface.methods %} |
| {%- set method_type = proto_type ~ "::" ~ interface.name ~ "_" ~ method.name %} |
| {%- for param in method.parameters %} |
| {%- set name = param.name|camel_to_under %} |
| {%- set kind = param.kind %} |
| {%- if kind|is_array_kind or kind|is_map_kind -%} |
| {{ from_proto.define(method_type, kind, name) }} |
| {{ to_proto.define(method_type, kind, name) }} |
| {%- endif %} |
| {%- endfor %} |
| {%- endfor %} |
| {%- for method in interface.methods %} |
| {%- if method.response_parameters != None %} |
| {%- set method_type = proto_type ~ "::" ~ interface.name ~ "_" ~ method.name ~ "Response" %} |
| {%- for param in method.response_parameters %} |
| {%- set name = param.name %} |
| {%- set kind = param.kind %} |
| {%- if kind|is_array_kind or kind|is_map_kind -%} |
| {{- from_proto.define(method_type, kind, name)}} |
| {{- to_proto.define(method_type, kind, name)}} |
| {%- endif %} |
| {%- endfor %} |
| {%- endif %} |
| {%- endfor %} |
| {%- endfor %} |
| |
| {%- for interface in interfaces %} |
| {%- set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %} |
| {%- set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %} |
| {%- if interface.methods %} |
| bool HandleRemoteAction(const {{proto_type}}::RemoteAction& input) { |
| bool result = true; |
| |
| switch (input.method_case()) { |
| {%- for method in interface.methods %} |
| case {{proto_type}}::RemoteAction::k{{("m_" ~ method.name)|under_to_camel}}: { |
| result = HandleRemoteCall(input.id(), input.{{("m" ~ method.name)|camel_to_under}}()); |
| } break; |
| {%- endfor %} |
| case {{proto_type}}::RemoteAction::kReset: { |
| mojolpm::GetContext()->GetAndRemoveInstance<::mojo::Remote<{{mojom_type}}>>(input.id()); |
| } break; |
| |
| default: { |
| result = false; |
| } |
| } |
| |
| return result; |
| } |
| |
| bool HandleAssociatedRemoteAction(const {{proto_type}}::AssociatedRemoteAction& input) { |
| bool result = true; |
| |
| switch (input.method_case()) { |
| {%- for method in interface.methods %} |
| case {{proto_type}}::AssociatedRemoteAction::k{{("m_" ~ method.name)|under_to_camel}}: { |
| result = HandleAssociatedRemoteCall(input.id(), input.{{("m" ~ method.name)|camel_to_under}}()); |
| } break; |
| {%- endfor %} |
| case {{proto_type}}::AssociatedRemoteAction::kReset: { |
| mojolpm::GetContext()->GetAndRemoveInstance<::mojo::AssociatedRemote<{{mojom_type}}>>(input.id()); |
| } break; |
| |
| default: { |
| result = false; |
| } |
| } |
| |
| return result; |
| } |
| |
| bool HandleReceiverAction( |
| const {{proto_type}}::ReceiverAction& input) { |
| bool result = true; |
| switch (input.response_case()) { |
| {%- for method in interface.methods %} |
| case {{proto_type}}::ReceiverAction::k{{("m_" ~ method.name ~ "_response")|under_to_camel}}: { |
| result = HandleResponse(input.id(), input.{{("m" ~ method.name ~ "_response")|camel_to_under}}()); |
| } break; |
| {%- endfor %} |
| |
| default: { |
| result = false; |
| } |
| } |
| |
| return result; |
| }{{"\n"-}} |
| {%- for method in interface.methods %} |
| {%- if method.response_parameters != None %} |
| static void {{interface.name}}_{{method.name}}Callback( |
| {%- for param in method.response_parameters %} |
| {%- set name = param.name|camel_to_under %} |
| {%- set kind = param.kind %} |
| {%- set param_mojom_type = kind|cpp_wrapper_param_type(add_same_module_namespaces=true) %}{{ ',' if not loop.first }} |
| {{param_mojom_type}} param_{{name}} |
| {%- endfor -%} |
| ) { |
| {%- for param in method.response_parameters %} |
| {%- set name = param.name|camel_to_under %} |
| {%- set kind = param.kind %} |
| {{ util.add_instance(kind, 'param_' ~ name, False) }} |
| {%- endfor %} |
| mojolpmdbg("{{interface.name}}.{{method.name}}Callback\n"); |
| }{{"\n"-}} |
| {%- endif %} |
| template <typename T> |
| bool HandleCall(uint32_t instance_id, |
| const {{proto_type}}::{{interface.name}}_{{method.name}}& input) { |
| T* instance = |
| mojolpm::GetContext()->GetInstance<T>(instance_id); |
| if (!instance || !instance->is_bound() || !instance->is_connected()) { |
| return false; |
| } |
| |
| mojolpm::GetContext()->StartDeserialization(); |
| |
| bool mojolpm_result = true; |
| {%- for param in method.parameters %} |
| {%- set name = param.name|camel_to_under %} |
| {%- set kind = param.kind %} |
| {%- set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %} |
| {{param_mojom_type}} local_{{name}}{ {{- kind|default_constructor_args -}} }; |
| {%- if kind|is_nullable_kind %} |
| {%- set unnullable_kind = kind|to_unnullable_kind %} |
| {%- set param_maybe_mojom_type = unnullable_kind|cpp_wrapper_type(add_same_module_namespaces=true) %} |
| {{param_maybe_mojom_type}} local_maybe_{{name}}{ {{- unnullable_kind|default_constructor_args -}} }; |
| {%- endif %} |
| {%- endfor %} |
| |
| {%- for param in method.parameters -%} |
| {%- set name = param.name|camel_to_under %} |
| {%- set kind = param.kind %} |
| {%- if not kind|is_nullable_kind %} |
| mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}}); |
| {%- else %} |
| if (FromProto(input.m_{{name}}(), local_maybe_{{name}})) { |
| local_{{name}} = std::move(local_maybe_{{name}}); |
| } |
| {%- endif %} |
| {%- endfor %} |
| if (mojolpm_result) { |
| (*instance)->{{method.name}}( |
| {%- for param in method.parameters -%} |
| {%- set name = param.name|camel_to_under %} |
| {%- set kind = param.kind %} |
| std::move(local_{{name}}){{ ',' if not loop.last }} |
| {%- endfor -%} |
| {%- if method.response_parameters != None -%} |
| {{ ',' if method.parameters }} |
| base::BindOnce(&{{interface.name}}_{{method.name}}Callback)); |
| {%- else -%} |
| ); |
| {%- endif -%} |
| mojolpm::GetContext()->EndDeserialization(Context::Rollback::kNoRollback); |
| } else { |
| mojolpm::GetContext()->EndDeserialization(Context::Rollback::kRollback); |
| mojolpmdbg("call failed\n"); |
| } |
| |
| return mojolpm_result; |
| } |
| |
| bool HandleRemoteCall( |
| uint32_t instance_id, const {{proto_type}}::{{interface.name}}_{{method.name}}& input) { |
| mojolpmdbg("HandleRemoteCall({{interface.name}}::{{method.name}})\n"); |
| return HandleCall<::mojo::Remote<{{mojom_type}}>>(instance_id, input); |
| } |
| |
| bool HandleAssociatedRemoteCall( |
| uint32_t instance_id, const {{proto_type}}::{{interface.name}}_{{method.name}}& input) { |
| mojolpmdbg("HandleAssociatedRemoteCall({{interface.name}}::{{method.name}})\n"); |
| return HandleCall<::mojo::AssociatedRemote<{{mojom_type}}>>(instance_id, input); |
| } |
| |
| bool HandleResponse( |
| uint32_t callback_id, const {{proto_type}}::{{interface.name}}_{{method.name}}Response& input) { |
| mojolpmdbg("HandleResponse({{interface.name}}::{{method.name}})\n"); |
| {%- if method.response_parameters == None %} |
| return true; |
| {%- else %} |
| auto mojolpm_callback = mojolpm::GetContext()->GetAndRemoveInstance< |
| {{mojom_type}}::{{method.name}}Callback>(callback_id); |
| |
| if (!mojolpm_callback) { |
| return true; |
| } |
| |
| mojolpm::GetContext()->StartDeserialization(); |
| |
| bool mojolpm_result = true; |
| {%- for param in method.response_parameters %} |
| {%- set name = param.name|camel_to_under %} |
| {%- set kind = param.kind %} |
| {%- set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %} |
| {{param_mojom_type}} local_{{name}}{ {{- kind|default_constructor_args -}} }; |
| {%- if kind|is_nullable_kind %} |
| {%- set unnullable_kind = kind|to_unnullable_kind %} |
| {%- set param_maybe_mojom_type = unnullable_kind|cpp_wrapper_type(add_same_module_namespaces=true) %} |
| {{param_maybe_mojom_type}} local_maybe_{{name}}{ {{- unnullable_kind|default_constructor_args -}} }; |
| {%- endif %} |
| {%- endfor %} |
| |
| {%- for param in method.response_parameters -%} |
| {%- set name = param.name|camel_to_under %} |
| {%- set kind = param.kind %} |
| {%- if not kind|is_nullable_kind %} |
| mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}}); |
| mojolpmdbg("{{name}} %i\n", mojolpm_result); |
| {%- else %} |
| if (FromProto(input.m_{{name}}(), local_maybe_{{name}})) { |
| local_{{name}} = std::move(local_maybe_{{name}}); |
| } |
| {%- endif %} |
| {%- endfor %} |
| if (mojolpm_result) { |
| std::move(*mojolpm_callback).Run( |
| {%- for param in method.response_parameters -%} |
| {%- set name = param.name|camel_to_under %} |
| {%- set kind = param.kind %} |
| {%- if kind|is_interface_kind or kind|is_associated_kind %} |
| {{kind|cpp_wrapper_param_type(add_same_module_namespaces=true)}}(std::move(local_{{name}})){{ ',' if not loop.last }} |
| {%- else %} |
| std::move(local_{{name}}){{ ',' if not loop.last }} |
| {%- endif %} |
| {%- endfor -%} |
| ); |
| mojolpm::GetContext()->EndDeserialization(Context::Rollback::kNoRollback); |
| } else { |
| mojolpm::GetContext()->EndDeserialization(Context::Rollback::kRollback); |
| mojolpm::GetContext()->AddInstance< |
| {{mojom_type}}::{{method.name}}Callback>(callback_id, std::move(*mojolpm_callback)); |
| } |
| |
| return mojolpm_result; |
| {%- endif %} |
| }{{"\n"-}} |
| {%- endfor %} |
| {%- endif %} |
| {%- endfor -%} |
| } // namespace mojolpm |