meson: Move all code generation scripts to utils/codegen/

We have multiple code generation scripts in utils/, mixed with other
miscellaneous utilities, as well as a larger code base based on mojom in
utils/ipc/. To make code sharing easier between the generator scripts,
without creating a mess in the utils/ directory, move all the code
generation code to utils/codegen/.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
This commit is contained in:
Laurent Pinchart 2024-08-08 18:13:00 +03:00
parent d3bf27180e
commit 50c92cc7e2
91 changed files with 15 additions and 15 deletions

View file

@ -0,0 +1,37 @@
{#-
# SPDX-License-Identifier: LGPL-2.1-or-later
# Copyright (C) 2020, Google Inc.
-#}
{%- import "definition_functions.tmpl" as funcs -%}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2020, Google Inc.
*
* libcamera core definitions for Image Processing Algorithms
*
* This file is auto-generated. Do not edit.
*/
#pragma once
{% if has_map %}#include <map>{% endif %}
{% if has_array %}#include <vector>{% endif %}
#include <libcamera/ipa/ipa_interface.h>
namespace libcamera {
{# \todo Use const char * instead of std::string for strings #}
{% for const in consts %}
static const {{const.kind|name}} {{const.mojom_name}} = {{const.value}};
{% endfor %}
{% for enum in enums_gen_header %}
{{funcs.define_enum(enum)}}
{% endfor %}
{%- for struct in structs_gen_header %}
{{funcs.define_struct(struct)}}
{% endfor %}
} /* namespace libcamera */

View file

@ -0,0 +1,44 @@
{#-
# SPDX-License-Identifier: LGPL-2.1-or-later
# Copyright (C) 2020, Google Inc.
-#}
{%- import "serializer.tmpl" as serializer -%}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2020, Google Inc.
*
* Data serializer for core libcamera definitions for IPA
*
* This file is auto-generated. Do not edit.
*/
#pragma once
#include <tuple>
#include <vector>
#include <libcamera/ipa/core_ipa_interface.h>
#include "libcamera/internal/control_serializer.h"
#include "libcamera/internal/ipa_data_serializer.h"
namespace libcamera {
LOG_DECLARE_CATEGORY(IPADataSerializer)
{% for struct in structs_gen_serializer %}
template<>
class IPADataSerializer<{{struct|name}}>
{
public:
{{- serializer.serializer(struct, "")}}
{%- if struct|has_fd %}
{{serializer.deserializer_fd(struct, "")}}
{%- else %}
{{serializer.deserializer_no_fd(struct, "")}}
{{serializer.deserializer_fd_simple(struct, "")}}
{%- endif %}
};
{% endfor %}
} /* namespace libcamera */

View file

@ -0,0 +1,56 @@
{#-
# SPDX-License-Identifier: LGPL-2.1-or-later
# Copyright (C) 2020, Google Inc.
-#}
{#
# \brief Generate enum definition
#
# \param enum Enum object whose definition is to be generated
#}
{%- macro define_enum(enum) -%}
enum{{" class" if enum|is_scoped}} {{enum.mojom_name}} {
{%- for field in enum.fields %}
{{field.mojom_name}} = {{field.numeric_value}},
{%- endfor %}
};
{%- endmacro -%}
{#
# \brief Generate struct definition
#
# \param struct Struct object whose definition is to be generated
#}
{%- macro define_struct(struct) -%}
struct {{struct.mojom_name}}
{
public:
#ifndef __DOXYGEN__
{{struct.mojom_name}}() {%- if struct|has_default_fields %}
:{% endif %}
{%- for field in struct.fields|with_default_values -%}
{{" " if loop.first}}{{field.mojom_name}}({{field|default_value}}){{", " if not loop.last}}
{%- endfor %}
{
}
{{struct.mojom_name}}(
{%- for field in struct.fields -%}
{{"const " if not field|is_pod}}{{field|name}} {{"&" if not field|is_pod}}_{{field.mojom_name}}{{", " if not loop.last}}
{%- endfor -%}
)
:
{%- for field in struct.fields -%}
{{" " if loop.first}}{{field.mojom_name}}(_{{field.mojom_name}}){{", " if not loop.last}}
{%- endfor %}
{
}
#endif
{% for field in struct.fields %}
{{field|name}} {{field.mojom_name}};
{%- endfor %}
};
{%- endmacro -%}

View file

@ -0,0 +1,14 @@
# SPDX-License-Identifier: CC0-1.0
mojom_template_files = files([
'core_ipa_interface.h.tmpl',
'core_ipa_serializer.h.tmpl',
'definition_functions.tmpl',
'module_ipa_interface.h.tmpl',
'module_ipa_proxy.cpp.tmpl',
'module_ipa_proxy.h.tmpl',
'module_ipa_proxy_worker.cpp.tmpl',
'module_ipa_serializer.h.tmpl',
'proxy_functions.tmpl',
'serializer.tmpl',
])

View file

@ -0,0 +1,84 @@
{#-
# SPDX-License-Identifier: LGPL-2.1-or-later
# Copyright (C) 2020, Google Inc.
-#}
{%- import "definition_functions.tmpl" as funcs -%}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2020, Google Inc.
*
* Image Processing Algorithm interface for {{module_name}}
*
* This file is auto-generated. Do not edit.
*/
#pragma once
#include <libcamera/ipa/core_ipa_interface.h>
#include <libcamera/ipa/ipa_interface.h>
{% if has_map %}#include <map>{% endif %}
{% if has_array %}#include <vector>{% endif %}
namespace libcamera {
{%- if has_namespace %}
{% for ns in namespace %}
namespace {{ns}} {
{% endfor %}
{%- endif %}
{% for const in consts %}
const {{const.kind|name}} {{const.mojom_name}} = {{const.value}};
{% endfor %}
enum class {{cmd_enum_name}} {
Exit = 0,
{%- for method in interface_main.methods %}
{{method.mojom_name|cap}} = {{loop.index}},
{%- endfor %}
};
enum class {{cmd_event_enum_name}} {
{%- for method in interface_event.methods %}
{{method.mojom_name|cap}} = {{loop.index}},
{%- endfor %}
};
{% for enum in enums %}
{{funcs.define_enum(enum)}}
{% endfor %}
{%- for struct in structs_nonempty %}
{{funcs.define_struct(struct)}}
{% endfor %}
{#-
Any consts or #defines should be moved to the mojom file.
#}
class {{interface_name}} : public IPAInterface
{
public:
{% for method in interface_main.methods %}
virtual {{method|method_return_value}} {{method.mojom_name}}(
{%- for param in method|method_parameters %}
{{param}}{{- "," if not loop.last}}
{%- endfor -%}
) = 0;
{% endfor %}
{%- for method in interface_event.methods %}
Signal<
{%- for param in method.parameters -%}
{{"const " if not param|is_pod}}{{param|name}}{{" &" if not param|is_pod and not param|is_enum}}
{{- ", " if not loop.last}}
{%- endfor -%}
> {{method.mojom_name}};
{% endfor -%}
};
{%- if has_namespace %}
{% for ns in namespace|reverse %}
} /* namespace {{ns}} */
{% endfor %}
{%- endif %}
} /* namespace libcamera */

View file

@ -0,0 +1,255 @@
{#-
# SPDX-License-Identifier: LGPL-2.1-or-later
# Copyright (C) 2020, Google Inc.
-#}
{%- import "proxy_functions.tmpl" as proxy_funcs -%}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2020, Google Inc.
*
* Image Processing Algorithm proxy for {{module_name}}
*
* This file is auto-generated. Do not edit.
*/
#include <libcamera/ipa/{{module_name}}_ipa_proxy.h>
#include <memory>
#include <string>
#include <vector>
#include <libcamera/ipa/ipa_module_info.h>
#include <libcamera/ipa/{{module_name}}_ipa_interface.h>
#include <libcamera/ipa/{{module_name}}_ipa_serializer.h>
#include <libcamera/base/log.h>
#include <libcamera/base/thread.h>
#include "libcamera/internal/control_serializer.h"
#include "libcamera/internal/ipa_data_serializer.h"
#include "libcamera/internal/ipa_module.h"
#include "libcamera/internal/ipa_proxy.h"
#include "libcamera/internal/ipc_pipe.h"
#include "libcamera/internal/ipc_pipe_unixsocket.h"
#include "libcamera/internal/ipc_unixsocket.h"
#include "libcamera/internal/process.h"
namespace libcamera {
LOG_DECLARE_CATEGORY(IPAProxy)
{%- if has_namespace %}
{% for ns in namespace %}
namespace {{ns}} {
{% endfor %}
{%- endif %}
{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate)
: IPAProxy(ipam), isolate_(isolate),
controlSerializer_(ControlSerializer::Role::Proxy), seq_(0)
{
LOG(IPAProxy, Debug)
<< "initializing {{module_name}} proxy: loading IPA from "
<< ipam->path();
if (isolate_) {
const std::string proxyWorkerPath = resolvePath("{{module_name}}_ipa_proxy");
if (proxyWorkerPath.empty()) {
LOG(IPAProxy, Error)
<< "Failed to get proxy worker path";
return;
}
ipc_ = std::make_unique<IPCPipeUnixSocket>(ipam->path().c_str(),
proxyWorkerPath.c_str());
if (!ipc_->isConnected()) {
LOG(IPAProxy, Error) << "Failed to create IPCPipe";
return;
}
ipc_->recv.connect(this, &{{proxy_name}}::recvMessage);
valid_ = true;
return;
}
if (!ipam->load())
return;
IPAInterface *ipai = ipam->createInterface();
if (!ipai) {
LOG(IPAProxy, Error)
<< "Failed to create IPA context for " << ipam->path();
return;
}
ipa_ = std::unique_ptr<{{interface_name}}>(static_cast<{{interface_name}} *>(ipai));
proxy_.setIPA(ipa_.get());
{% for method in interface_event.methods %}
ipa_->{{method.mojom_name}}.connect(this, &{{proxy_name}}::{{method.mojom_name}}Thread);
{%- endfor %}
valid_ = true;
}
{{proxy_name}}::~{{proxy_name}}()
{
if (isolate_) {
IPCMessage::Header header =
{ static_cast<uint32_t>({{cmd_enum_name}}::Exit), seq_++ };
IPCMessage msg(header);
ipc_->sendAsync(msg);
}
}
{% if interface_event.methods|length > 0 %}
void {{proxy_name}}::recvMessage(const IPCMessage &data)
{
size_t dataSize = data.data().size();
{{cmd_event_enum_name}} _cmd = static_cast<{{cmd_event_enum_name}}>(data.header().cmd);
switch (_cmd) {
{%- for method in interface_event.methods %}
case {{cmd_event_enum_name}}::{{method.mojom_name|cap}}: {
{{method.mojom_name}}IPC(data.data().cbegin(), dataSize, data.fds());
break;
}
{%- endfor %}
default:
LOG(IPAProxy, Error) << "Unknown command " << static_cast<uint32_t>(_cmd);
}
}
{%- endif %}
{% for method in interface_main.methods %}
{{proxy_funcs.func_sig(proxy_name, method)}}
{
if (isolate_)
{{"return " if method|method_return_value != "void"}}{{method.mojom_name}}IPC(
{%- for param in method|method_param_names -%}
{{param}}{{- ", " if not loop.last}}
{%- endfor -%}
);
else
{{"return " if method|method_return_value != "void"}}{{method.mojom_name}}Thread(
{%- for param in method|method_param_names -%}
{{param}}{{- ", " if not loop.last}}
{%- endfor -%}
);
}
{{proxy_funcs.func_sig(proxy_name, method, "Thread")}}
{
{%- if method.mojom_name == "stop" %}
{{proxy_funcs.stop_thread_body()}}
{%- elif method.mojom_name == "init" %}
{{ method|method_return_value + " _ret = " if method|method_return_value != "void" -}}
ipa_->{{method.mojom_name}}(
{%- for param in method|method_param_names -%}
{{param}}{{- ", " if not loop.last}}
{%- endfor -%}
);
proxy_.moveToThread(&thread_);
return {{ "_ret" if method|method_return_value != "void" }};
{%- elif method.mojom_name == "start" %}
state_ = ProxyRunning;
thread_.start();
{{ "return " if method|method_return_value != "void" -}}
proxy_.invokeMethod(&ThreadProxy::start, ConnectionTypeBlocking
{{- ", " if method|method_param_names}}
{%- for param in method|method_param_names -%}
{{param}}{{- ", " if not loop.last}}
{%- endfor -%}
);
{%- elif not method|is_async %}
{{ "return " if method|method_return_value != "void" -}}
ipa_->{{method.mojom_name}}(
{%- for param in method|method_param_names -%}
{{param}}{{- ", " if not loop.last}}
{%- endfor -%}
);
{% elif method|is_async %}
ASSERT(state_ == ProxyRunning);
proxy_.invokeMethod(&ThreadProxy::{{method.mojom_name}}, ConnectionTypeQueued
{%- for param in method|method_param_names -%}
, {{param}}
{%- endfor -%}
);
{%- endif %}
}
{{proxy_funcs.func_sig(proxy_name, method, "IPC")}}
{
{%- if method.mojom_name == "configure" %}
controlSerializer_.reset();
{%- endif %}
{%- set has_output = true if method|method_param_outputs|length > 0 or method|method_return_value != "void" %}
{%- set cmd = cmd_enum_name + "::" + method.mojom_name|cap %}
IPCMessage::Header _header = { static_cast<uint32_t>({{cmd}}), seq_++ };
IPCMessage _ipcInputBuf(_header);
{%- if has_output %}
IPCMessage _ipcOutputBuf;
{%- endif %}
{{proxy_funcs.serialize_call(method|method_param_inputs, '_ipcInputBuf.data()', '_ipcInputBuf.fds()')}}
{% if method|is_async %}
int _ret = ipc_->sendAsync(_ipcInputBuf);
{%- else %}
int _ret = ipc_->sendSync(_ipcInputBuf
{{- ", &_ipcOutputBuf" if has_output -}}
);
{%- endif %}
if (_ret < 0) {
LOG(IPAProxy, Error) << "Failed to call {{method.mojom_name}}";
{%- if method|method_return_value != "void" %}
return static_cast<{{method|method_return_value}}>(_ret);
{%- else %}
return;
{%- endif %}
}
{% if method|method_return_value != "void" %}
{{method|method_return_value}} _retValue = IPADataSerializer<{{method|method_return_value}}>::deserialize(_ipcOutputBuf.data(), 0);
{{proxy_funcs.deserialize_call(method|method_param_outputs, '_ipcOutputBuf.data()', '_ipcOutputBuf.fds()', init_offset = method|method_return_value|byte_width|int)}}
return _retValue;
{% elif method|method_param_outputs|length > 0 %}
{{proxy_funcs.deserialize_call(method|method_param_outputs, '_ipcOutputBuf.data()', '_ipcOutputBuf.fds()')}}
{% endif -%}
}
{% endfor %}
{% for method in interface_event.methods %}
{{proxy_funcs.func_sig(proxy_name, method, "Thread")}}
{
ASSERT(state_ != ProxyStopped);
{{method.mojom_name}}.emit({{method.parameters|params_comma_sep}});
}
void {{proxy_name}}::{{method.mojom_name}}IPC(
[[maybe_unused]] std::vector<uint8_t>::const_iterator data,
[[maybe_unused]] size_t dataSize,
[[maybe_unused]] const std::vector<SharedFD> &fds)
{
{%- for param in method.parameters %}
{{param|name}} {{param.mojom_name}};
{%- endfor %}
{{proxy_funcs.deserialize_call(method.parameters, 'data', 'fds', false, false, true, 'dataSize')}}
{{method.mojom_name}}.emit({{method.parameters|params_comma_sep}});
}
{% endfor %}
{%- if has_namespace %}
{% for ns in namespace|reverse %}
} /* namespace {{ns}} */
{% endfor %}
{%- endif %}
} /* namespace libcamera */

View file

@ -0,0 +1,132 @@
{#-
# SPDX-License-Identifier: LGPL-2.1-or-later
# Copyright (C) 2020, Google Inc.
-#}
{%- import "proxy_functions.tmpl" as proxy_funcs -%}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2020, Google Inc.
*
* Image Processing Algorithm proxy for {{module_name}}
*
* This file is auto-generated. Do not edit.
*/
#pragma once
#include <libcamera/ipa/ipa_interface.h>
#include <libcamera/ipa/{{module_name}}_ipa_interface.h>
#include <libcamera/base/object.h>
#include <libcamera/base/thread.h>
#include "libcamera/internal/control_serializer.h"
#include "libcamera/internal/ipa_proxy.h"
#include "libcamera/internal/ipc_pipe.h"
#include "libcamera/internal/ipc_pipe_unixsocket.h"
#include "libcamera/internal/ipc_unixsocket.h"
namespace libcamera {
{%- if has_namespace %}
{% for ns in namespace %}
namespace {{ns}} {
{% endfor %}
{%- endif %}
class {{proxy_name}} : public IPAProxy, public {{interface_name}}, public Object
{
public:
{{proxy_name}}(IPAModule *ipam, bool isolate);
~{{proxy_name}}();
{% for method in interface_main.methods %}
{{proxy_funcs.func_sig(proxy_name, method, "", false, true)|indent(8, true)}};
{% endfor %}
{%- for method in interface_event.methods %}
Signal<
{%- for param in method.parameters -%}
{{"const " if not param|is_pod}}{{param|name}}{{" &" if not param|is_pod and not param|is_enum}}
{{- ", " if not loop.last}}
{%- endfor -%}
> {{method.mojom_name}};
{% endfor %}
private:
void recvMessage(const IPCMessage &data);
{% for method in interface_main.methods %}
{{proxy_funcs.func_sig(proxy_name, method, "Thread", false)|indent(8, true)}};
{{proxy_funcs.func_sig(proxy_name, method, "IPC", false)|indent(8, true)}};
{% endfor %}
{% for method in interface_event.methods %}
{{proxy_funcs.func_sig(proxy_name, method, "Thread", false)|indent(8, true)}};
void {{method.mojom_name}}IPC(
std::vector<uint8_t>::const_iterator data,
size_t dataSize,
const std::vector<SharedFD> &fds);
{% endfor %}
/* Helper class to invoke async functions in another thread. */
class ThreadProxy : public Object
{
public:
ThreadProxy()
: ipa_(nullptr)
{
}
void setIPA({{interface_name}} *ipa)
{
ipa_ = ipa;
}
void stop()
{
ipa_->stop();
}
{% for method in interface_main.methods %}
{%- if method|is_async %}
{{proxy_funcs.func_sig(proxy_name, method, "", false)|indent(16)}}
{
ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}});
}
{%- elif method.mojom_name == "start" %}
{{proxy_funcs.func_sig(proxy_name, method, "", false)|indent(16)}}
{
{%- if method|method_return_value != "void" %}
return ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}});
{%- else %}
ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}}
{{- ", " if method|method_param_outputs|params_comma_sep -}}
{{- method|method_param_outputs|params_comma_sep}});
{%- endif %}
}
{%- endif %}
{%- endfor %}
private:
{{interface_name}} *ipa_;
};
Thread thread_;
ThreadProxy proxy_;
std::unique_ptr<{{interface_name}}> ipa_;
const bool isolate_;
std::unique_ptr<IPCPipeUnixSocket> ipc_;
ControlSerializer controlSerializer_;
{# \todo Move this to IPCPipe #}
uint32_t seq_;
};
{%- if has_namespace %}
{% for ns in namespace|reverse %}
} /* namespace {{ns}} */
{% endfor %}
{%- endif %}
} /* namespace libcamera */

View file

@ -0,0 +1,246 @@
{#-
# SPDX-License-Identifier: LGPL-2.1-or-later
# Copyright (C) 2020, Google Inc.
-#}
{%- import "proxy_functions.tmpl" as proxy_funcs -%}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2020, Google Inc.
*
* Image Processing Algorithm proxy worker for {{module_name}}
*
* This file is auto-generated. Do not edit.
*/
{#- \todo Split proxy worker into IPC worker and proxy worker. #}
#include <algorithm>
#include <iostream>
#include <sys/types.h>
#include <tuple>
#include <unistd.h>
#include <libcamera/ipa/ipa_interface.h>
#include <libcamera/ipa/{{module_name}}_ipa_interface.h>
#include <libcamera/ipa/{{module_name}}_ipa_serializer.h>
#include <libcamera/logging.h>
#include <libcamera/base/event_dispatcher.h>
#include <libcamera/base/log.h>
#include <libcamera/base/thread.h>
#include <libcamera/base/unique_fd.h>
#include "libcamera/internal/camera_sensor.h"
#include "libcamera/internal/control_serializer.h"
#include "libcamera/internal/ipa_data_serializer.h"
#include "libcamera/internal/ipa_module.h"
#include "libcamera/internal/ipa_proxy.h"
#include "libcamera/internal/ipc_pipe.h"
#include "libcamera/internal/ipc_pipe_unixsocket.h"
#include "libcamera/internal/ipc_unixsocket.h"
using namespace libcamera;
LOG_DEFINE_CATEGORY({{proxy_worker_name}})
{%- if has_namespace %}
{% for ns in namespace -%}
using namespace {{ns}};
{% endfor %}
{%- endif %}
class {{proxy_worker_name}}
{
public:
{{proxy_worker_name}}()
: ipa_(nullptr),
controlSerializer_(ControlSerializer::Role::Worker),
exit_(false) {}
~{{proxy_worker_name}}() {}
void readyRead()
{
IPCUnixSocket::Payload _message;
int _retRecv = socket_.receive(&_message);
if (_retRecv) {
LOG({{proxy_worker_name}}, Error)
<< "Receive message failed: " << _retRecv;
return;
}
IPCMessage _ipcMessage(_message);
{{cmd_enum_name}} _cmd = static_cast<{{cmd_enum_name}}>(_ipcMessage.header().cmd);
switch (_cmd) {
case {{cmd_enum_name}}::Exit: {
exit_ = true;
break;
}
{% for method in interface_main.methods %}
case {{cmd_enum_name}}::{{method.mojom_name|cap}}: {
{%- if method.mojom_name == "configure" %}
controlSerializer_.reset();
{%- endif %}
{{proxy_funcs.deserialize_call(method|method_param_inputs, '_ipcMessage.data()', '_ipcMessage.fds()', false, true)|indent(16, true)}}
{% for param in method|method_param_outputs %}
{{param|name}} {{param.mojom_name}};
{% endfor %}
{%- if method|method_return_value != "void" %}
{{method|method_return_value}} _callRet =
{%- endif -%}
ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}}
{{- ", " if method|method_param_outputs|params_comma_sep -}}
{%- for param in method|method_param_outputs -%}
&{{param.mojom_name}}{{", " if not loop.last}}
{%- endfor -%}
);
{% if not method|is_async %}
IPCMessage::Header header = { _ipcMessage.header().cmd, _ipcMessage.header().cookie };
IPCMessage _response(header);
{%- if method|method_return_value != "void" %}
std::vector<uint8_t> _callRetBuf;
std::tie(_callRetBuf, std::ignore) =
IPADataSerializer<{{method|method_return_value}}>::serialize(_callRet);
_response.data().insert(_response.data().end(), _callRetBuf.cbegin(), _callRetBuf.cend());
{%- endif %}
{{proxy_funcs.serialize_call(method|method_param_outputs, "_response.data()", "_response.fds()")|indent(16, true)}}
int _ret = socket_.send(_response.payload());
if (_ret < 0) {
LOG({{proxy_worker_name}}, Error)
<< "Reply to {{method.mojom_name}}() failed: " << _ret;
}
LOG({{proxy_worker_name}}, Debug) << "Done replying to {{method.mojom_name}}()";
{%- endif %}
break;
}
{% endfor %}
default:
LOG({{proxy_worker_name}}, Error) << "Unknown command " << _ipcMessage.header().cmd;
}
}
int init(std::unique_ptr<IPAModule> &ipam, UniqueFD socketfd)
{
if (socket_.bind(std::move(socketfd)) < 0) {
LOG({{proxy_worker_name}}, Error)
<< "IPC socket binding failed";
return EXIT_FAILURE;
}
socket_.readyRead.connect(this, &{{proxy_worker_name}}::readyRead);
ipa_ = dynamic_cast<{{interface_name}} *>(ipam->createInterface());
if (!ipa_) {
LOG({{proxy_worker_name}}, Error)
<< "Failed to create IPA interface instance";
return EXIT_FAILURE;
}
{% for method in interface_event.methods %}
ipa_->{{method.mojom_name}}.connect(this, &{{proxy_worker_name}}::{{method.mojom_name}});
{%- endfor %}
return 0;
}
void run()
{
EventDispatcher *dispatcher = Thread::current()->eventDispatcher();
while (!exit_)
dispatcher->processEvents();
}
void cleanup()
{
delete ipa_;
socket_.close();
}
private:
{% for method in interface_event.methods %}
{{proxy_funcs.func_sig(proxy_name, method, "", false)|indent(8, true)}}
{
IPCMessage::Header header = {
static_cast<uint32_t>({{cmd_event_enum_name}}::{{method.mojom_name|cap}}),
0
};
IPCMessage _message(header);
{{proxy_funcs.serialize_call(method|method_param_inputs, "_message.data()", "_message.fds()")}}
int _ret = socket_.send(_message.payload());
if (_ret < 0)
LOG({{proxy_worker_name}}, Error)
<< "Sending event {{method.mojom_name}}() failed: " << _ret;
LOG({{proxy_worker_name}}, Debug) << "{{method.mojom_name}} done";
}
{% endfor %}
{{interface_name}} *ipa_;
IPCUnixSocket socket_;
ControlSerializer controlSerializer_;
bool exit_;
};
int main(int argc, char **argv)
{
{#- \todo Handle enabling debugging more dynamically. #}
/* Uncomment this for debugging. */
#if 0
std::string logPath = "/tmp/libcamera.worker." +
std::to_string(getpid()) + ".log";
logSetFile(logPath.c_str());
#endif
if (argc < 3) {
LOG({{proxy_worker_name}}, Error)
<< "Tried to start worker with no args: "
<< "expected <path to IPA so> <fd to bind unix socket>";
return EXIT_FAILURE;
}
UniqueFD fd(std::stoi(argv[2]));
LOG({{proxy_worker_name}}, Info)
<< "Starting worker for IPA module " << argv[1]
<< " with IPC fd = " << fd.get();
std::unique_ptr<IPAModule> ipam = std::make_unique<IPAModule>(argv[1]);
if (!ipam->isValid() || !ipam->load()) {
LOG({{proxy_worker_name}}, Error)
<< "IPAModule " << argv[1] << " isn't valid";
return EXIT_FAILURE;
}
/*
* Shutdown of proxy worker can be pre-empted by events like
* SIGINT/SIGTERM, even before the pipeline handler can request
* shutdown. Hence, assign a new gid to prevent signals on the
* application being delivered to the proxy.
*/
if (setpgid(0, 0) < 0) {
int err = errno;
LOG({{proxy_worker_name}}, Warning)
<< "Failed to set new gid: " << strerror(err);
}
{{proxy_worker_name}} proxyWorker;
int ret = proxyWorker.init(ipam, std::move(fd));
if (ret < 0) {
LOG({{proxy_worker_name}}, Error)
<< "Failed to initialize proxy worker";
return ret;
}
LOG({{proxy_worker_name}}, Debug) << "Proxy worker successfully initialized";
proxyWorker.run();
proxyWorker.cleanup();
return 0;
}

View file

@ -0,0 +1,45 @@
{#-
# SPDX-License-Identifier: LGPL-2.1-or-later
# Copyright (C) 2020, Google Inc.
-#}
{%- import "serializer.tmpl" as serializer -%}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2020, Google Inc.
*
* Image Processing Algorithm data serializer for {{module_name}}
*
* This file is auto-generated. Do not edit.
*/
#pragma once
#include <tuple>
#include <vector>
#include <libcamera/ipa/{{module_name}}_ipa_interface.h>
#include <libcamera/ipa/core_ipa_serializer.h>
#include "libcamera/internal/control_serializer.h"
#include "libcamera/internal/ipa_data_serializer.h"
namespace libcamera {
LOG_DECLARE_CATEGORY(IPADataSerializer)
{% for struct in structs_nonempty %}
template<>
class IPADataSerializer<{{struct|name_full}}>
{
public:
{{- serializer.serializer(struct, namespace_str)}}
{%- if struct|has_fd %}
{{serializer.deserializer_fd(struct, namespace_str)}}
{%- else %}
{{serializer.deserializer_no_fd(struct, namespace_str)}}
{{serializer.deserializer_fd_simple(struct, namespace_str)}}
{%- endif %}
};
{% endfor %}
} /* namespace libcamera */

View file

@ -0,0 +1,202 @@
{#-
# SPDX-License-Identifier: LGPL-2.1-or-later
# Copyright (C) 2020, Google Inc.
-#}
{#
# \brief Generate function prototype
#
# \param class Class name
# \param method mojom Method object
# \param suffix Suffix to append to \a method function name
# \param need_class_name If true, generate class name with function
# \param override If true, generate override tag after the function prototype
#}
{%- macro func_sig(class, method, suffix = "", need_class_name = true, override = false) -%}
{{method|method_return_value}} {{class + "::" if need_class_name}}{{method.mojom_name}}{{suffix}}(
{%- for param in method|method_parameters %}
{{param}}{{- "," if not loop.last}}
{%- endfor -%}
){{" override" if override}}
{%- endmacro -%}
{#
# \brief Generate function body for IPA stop() function for thread
#}
{%- macro stop_thread_body() -%}
ASSERT(state_ != ProxyStopping);
if (state_ != ProxyRunning)
return;
state_ = ProxyStopping;
proxy_.invokeMethod(&ThreadProxy::stop, ConnectionTypeBlocking);
thread_.exit();
thread_.wait();
Thread::current()->dispatchMessages(Message::Type::InvokeMessage);
state_ = ProxyStopped;
{%- endmacro -%}
{#
# \brief Serialize multiple objects into data buffer and fd vector
#
# Generate code to serialize multiple objects, as specified in \a params
# (which are the parameters to some function), into \a buf data buffer and
# \a fds fd vector.
# This code is meant to be used by the proxy, for serializing prior to IPC calls.
#
# \todo Avoid intermediate vectors
#}
{%- macro serialize_call(params, buf, fds) %}
{%- for param in params %}
{%- if param|is_enum %}
static_assert(sizeof({{param|name_full}}) <= 4);
{%- endif %}
std::vector<uint8_t> {{param.mojom_name}}Buf;
{%- if param|has_fd %}
std::vector<SharedFD> {{param.mojom_name}}Fds;
std::tie({{param.mojom_name}}Buf, {{param.mojom_name}}Fds) =
{%- else %}
std::tie({{param.mojom_name}}Buf, std::ignore) =
{%- endif %}
{%- if param|is_flags %}
IPADataSerializer<{{param|name_full}}>::serialize({{param.mojom_name}}
{%- elif param|is_enum %}
IPADataSerializer<uint32_t>::serialize(static_cast<uint32_t>({{param.mojom_name}})
{%- else %}
IPADataSerializer<{{param|name}}>::serialize({{param.mojom_name}}
{% endif -%}
{{- ", &controlSerializer_" if param|needs_control_serializer -}}
);
{%- endfor %}
{%- if params|length > 1 %}
{%- for param in params %}
appendPOD<uint32_t>({{buf}}, {{param.mojom_name}}Buf.size());
{%- if param|has_fd %}
appendPOD<uint32_t>({{buf}}, {{param.mojom_name}}Fds.size());
{%- endif %}
{%- endfor %}
{%- endif %}
{%- for param in params %}
{{buf}}.insert({{buf}}.end(), {{param.mojom_name}}Buf.begin(), {{param.mojom_name}}Buf.end());
{%- endfor %}
{%- for param in params %}
{%- if param|has_fd %}
{{fds}}.insert({{fds}}.end(), {{param.mojom_name}}Fds.begin(), {{param.mojom_name}}Fds.end());
{%- endif %}
{%- endfor %}
{%- endmacro -%}
{#
# \brief Deserialize a single object from data buffer and fd vector
#
# \param pointer If true, deserialize the object into a dereferenced pointer
# \param iter If true, treat \a buf as an iterator instead of a vector
# \param data_size Variable that holds the size of the vector referenced by \a buf
#
# Generate code to deserialize a single object, as specified in \a param,
# from \a buf data buffer and \a fds fd vector.
# This code is meant to be used by macro deserialize_call.
#}
{%- macro deserialize_param(param, pointer, loop, buf, fds, iter, data_size) -%}
{{"*" if pointer}}{{param.mojom_name}} =
{%- if param|is_flags %}
IPADataSerializer<{{param|name_full}}>::deserialize(
{%- elif param|is_enum %}
static_cast<{{param|name_full}}>(IPADataSerializer<uint32_t>::deserialize(
{%- else %}
IPADataSerializer<{{param|name}}>::deserialize(
{%- endif %}
{{buf}}{{- ".cbegin()" if not iter}} + {{param.mojom_name}}Start,
{%- if loop.last and not iter %}
{{buf}}.cend()
{%- elif not iter %}
{{buf}}.cbegin() + {{param.mojom_name}}Start + {{param.mojom_name}}BufSize
{%- elif iter and loop.length == 1 %}
{{buf}} + {{data_size}}
{%- else %}
{{buf}} + {{param.mojom_name}}Start + {{param.mojom_name}}BufSize
{%- endif -%}
{{- "," if param|has_fd}}
{%- if param|has_fd %}
{{fds}}.cbegin() + {{param.mojom_name}}FdStart,
{%- if loop.last %}
{{fds}}.cend()
{%- else %}
{{fds}}.cbegin() + {{param.mojom_name}}FdStart + {{param.mojom_name}}FdsSize
{%- endif -%}
{%- endif -%}
{{- "," if param|needs_control_serializer}}
{%- if param|needs_control_serializer %}
&controlSerializer_
{%- endif -%}
){{")" if param|is_enum and not param|is_flags}};
{%- endmacro -%}
{#
# \brief Deserialize multiple objects from data buffer and fd vector
#
# \param pointer If true, deserialize objects into pointers, and adds a null check.
# \param declare If true, declare the objects in addition to deserialization.
# \param iter if true, treat \a buf as an iterator instead of a vector
# \param data_size Variable that holds the size of the vector referenced by \a buf
#
# Generate code to deserialize multiple objects, as specified in \a params
# (which are the parameters to some function), from \a buf data buffer and
# \a fds fd vector.
# This code is meant to be used by the proxy, for deserializing after IPC calls.
#
# \todo Avoid intermediate vectors
#}
{%- macro deserialize_call(params, buf, fds, pointer = true, declare = false, iter = false, data_size = '', init_offset = 0) -%}
{% set ns = namespace(size_offset = init_offset) %}
{%- if params|length > 1 %}
{%- for param in params %}
[[maybe_unused]] const size_t {{param.mojom_name}}BufSize = readPOD<uint32_t>({{buf}}, {{ns.size_offset}}
{%- if iter -%}
, {{buf}} + {{data_size}}
{%- endif -%}
);
{%- set ns.size_offset = ns.size_offset + 4 %}
{%- if param|has_fd %}
[[maybe_unused]] const size_t {{param.mojom_name}}FdsSize = readPOD<uint32_t>({{buf}}, {{ns.size_offset}}
{%- if iter -%}
, {{buf}} + {{data_size}}
{%- endif -%}
);
{%- set ns.size_offset = ns.size_offset + 4 %}
{%- endif %}
{%- endfor %}
{%- endif %}
{% for param in params %}
{%- if loop.first %}
const size_t {{param.mojom_name}}Start = {{ns.size_offset}};
{%- else %}
const size_t {{param.mojom_name}}Start = {{loop.previtem.mojom_name}}Start + {{loop.previtem.mojom_name}}BufSize;
{%- endif %}
{%- endfor %}
{% for param in params|with_fds %}
{%- if loop.first %}
const size_t {{param.mojom_name}}FdStart = 0;
{%- else %}
const size_t {{param.mojom_name}}FdStart = {{loop.previtem.mojom_name}}FdStart + {{loop.previtem.mojom_name}}FdsSize;
{%- endif %}
{%- endfor %}
{% for param in params %}
{%- if pointer %}
if ({{param.mojom_name}}) {
{{deserialize_param(param, pointer, loop, buf, fds, iter, data_size)|indent(16, True)}}
}
{%- else %}
{{param|name + " " if declare}}{{deserialize_param(param, pointer, loop, buf, fds, iter, data_size)|indent(8)}}
{%- endif %}
{% endfor %}
{%- endmacro -%}

View file

@ -0,0 +1,319 @@
{#-
# SPDX-License-Identifier: LGPL-2.1-or-later
# Copyright (C) 2020, Google Inc.
-#}
{#
# \brief Verify that there is enough bytes to deserialize
#
# Generate code that verifies that \a size is not greater than \a dataSize.
# Otherwise log an error with \a name and \a typename.
#}
{%- macro check_data_size(size, dataSize, name, typename) %}
if ({{dataSize}} < {{size}}) {
LOG(IPADataSerializer, Error)
<< "Failed to deserialize " << "{{name}}"
<< ": not enough {{typename}}, expected "
<< ({{size}}) << ", got " << ({{dataSize}});
return ret;
}
{%- endmacro %}
{#
# \brief Serialize a field into return vector
#
# Generate code to serialize \a field into retData, including size of the
# field and fds (where appropriate).
# This code is meant to be used by the IPADataSerializer specialization.
#
# \todo Avoid intermediate vectors
#}
{%- macro serializer_field(field, namespace, loop) %}
{%- if field|is_pod or field|is_enum %}
std::vector<uint8_t> {{field.mojom_name}};
std::tie({{field.mojom_name}}, std::ignore) =
{%- if field|is_pod %}
IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}});
{%- elif field|is_flags %}
IPADataSerializer<{{field|name_full}}>::serialize(data.{{field.mojom_name}});
{%- elif field|is_enum_scoped %}
IPADataSerializer<uint{{field|bit_width}}_t>::serialize(static_cast<uint{{field|bit_width}}_t>(data.{{field.mojom_name}}));
{%- elif field|is_enum %}
IPADataSerializer<uint{{field|bit_width}}_t>::serialize(data.{{field.mojom_name}});
{%- endif %}
retData.insert(retData.end(), {{field.mojom_name}}.begin(), {{field.mojom_name}}.end());
{%- elif field|is_fd %}
std::vector<uint8_t> {{field.mojom_name}};
std::vector<SharedFD> {{field.mojom_name}}Fds;
std::tie({{field.mojom_name}}, {{field.mojom_name}}Fds) =
IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}});
retData.insert(retData.end(), {{field.mojom_name}}.begin(), {{field.mojom_name}}.end());
retFds.insert(retFds.end(), {{field.mojom_name}}Fds.begin(), {{field.mojom_name}}Fds.end());
{%- elif field|is_controls %}
if (data.{{field.mojom_name}}.size() > 0) {
std::vector<uint8_t> {{field.mojom_name}};
std::tie({{field.mojom_name}}, std::ignore) =
IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}}, cs);
appendPOD<uint32_t>(retData, {{field.mojom_name}}.size());
retData.insert(retData.end(), {{field.mojom_name}}.begin(), {{field.mojom_name}}.end());
} else {
appendPOD<uint32_t>(retData, 0);
}
{%- elif field|is_plain_struct or field|is_array or field|is_map or field|is_str %}
std::vector<uint8_t> {{field.mojom_name}};
{%- if field|has_fd %}
std::vector<SharedFD> {{field.mojom_name}}Fds;
std::tie({{field.mojom_name}}, {{field.mojom_name}}Fds) =
{%- else %}
std::tie({{field.mojom_name}}, std::ignore) =
{%- endif %}
{%- if field|is_array or field|is_map %}
IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}}, cs);
{%- elif field|is_str %}
IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}});
{%- else %}
IPADataSerializer<{{field|name_full}}>::serialize(data.{{field.mojom_name}}, cs);
{%- endif %}
appendPOD<uint32_t>(retData, {{field.mojom_name}}.size());
{%- if field|has_fd %}
appendPOD<uint32_t>(retData, {{field.mojom_name}}Fds.size());
{%- endif %}
retData.insert(retData.end(), {{field.mojom_name}}.begin(), {{field.mojom_name}}.end());
{%- if field|has_fd %}
retFds.insert(retFds.end(), {{field.mojom_name}}Fds.begin(), {{field.mojom_name}}Fds.end());
{%- endif %}
{%- else %}
/* Unknown serialization for {{field.mojom_name}}. */
{%- endif %}
{%- endmacro %}
{#
# \brief Deserialize a field into return struct
#
# Generate code to deserialize \a field into object ret.
# This code is meant to be used by the IPADataSerializer specialization.
#}
{%- macro deserializer_field(field, namespace, loop) %}
{% if field|is_pod or field|is_enum %}
{%- set field_size = (field|bit_width|int / 8)|int %}
{{- check_data_size(field_size, 'dataSize', field.mojom_name, 'data')}}
{%- if field|is_pod %}
ret.{{field.mojom_name}} = IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field_size}});
{%- elif field|is_flags %}
ret.{{field.mojom_name}} = IPADataSerializer<{{field|name_full}}>::deserialize(m, m + {{field_size}});
{%- else %}
ret.{{field.mojom_name}} = static_cast<{{field|name_full}}>(IPADataSerializer<uint{{field|bit_width}}_t>::deserialize(m, m + {{field_size}}));
{%- endif %}
{%- if not loop.last %}
m += {{field_size}};
dataSize -= {{field_size}};
{%- endif %}
{% elif field|is_fd %}
{%- set field_size = 4 %}
{{- check_data_size(field_size, 'dataSize', field.mojom_name, 'data')}}
ret.{{field.mojom_name}} = IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field_size}}, n, n + 1, cs);
{%- if not loop.last %}
m += {{field_size}};
dataSize -= {{field_size}};
n += ret.{{field.mojom_name}}.isValid() ? 1 : 0;
fdsSize -= ret.{{field.mojom_name}}.isValid() ? 1 : 0;
{%- endif %}
{% elif field|is_controls %}
{%- set field_size = 4 %}
{{- check_data_size(field_size, 'dataSize', field.mojom_name + 'Size', 'data')}}
const size_t {{field.mojom_name}}Size = readPOD<uint32_t>(m, 0, dataEnd);
m += {{field_size}};
dataSize -= {{field_size}};
{%- set field_size = field.mojom_name + 'Size' -%}
{{- check_data_size(field_size, 'dataSize', field.mojom_name, 'data')}}
if ({{field.mojom_name}}Size > 0)
ret.{{field.mojom_name}} =
IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field.mojom_name}}Size, cs);
{%- if not loop.last %}
m += {{field_size}};
dataSize -= {{field_size}};
{%- endif %}
{% elif field|is_plain_struct or field|is_array or field|is_map or field|is_str %}
{%- set field_size = 4 %}
{{- check_data_size(field_size, 'dataSize', field.mojom_name + 'Size', 'data')}}
const size_t {{field.mojom_name}}Size = readPOD<uint32_t>(m, 0, dataEnd);
m += {{field_size}};
dataSize -= {{field_size}};
{%- if field|has_fd %}
{%- set field_size = 4 %}
{{- check_data_size(field_size, 'dataSize', field.mojom_name + 'FdsSize', 'data')}}
const size_t {{field.mojom_name}}FdsSize = readPOD<uint32_t>(m, 0, dataEnd);
m += {{field_size}};
dataSize -= {{field_size}};
{{- check_data_size(field.mojom_name + 'FdsSize', 'fdsSize', field.mojom_name, 'fds')}}
{%- endif %}
{%- set field_size = field.mojom_name + 'Size' -%}
{{- check_data_size(field_size, 'dataSize', field.mojom_name, 'data')}}
ret.{{field.mojom_name}} =
{%- if field|is_str %}
IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field.mojom_name}}Size);
{%- elif field|has_fd and (field|is_array or field|is_map) %}
IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field.mojom_name}}Size, n, n + {{field.mojom_name}}FdsSize, cs);
{%- elif field|has_fd and (not (field|is_array or field|is_map)) %}
IPADataSerializer<{{field|name_full}}>::deserialize(m, m + {{field.mojom_name}}Size, n, n + {{field.mojom_name}}FdsSize, cs);
{%- elif (not field|has_fd) and (field|is_array or field|is_map) %}
IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field.mojom_name}}Size, cs);
{%- else %}
IPADataSerializer<{{field|name_full}}>::deserialize(m, m + {{field.mojom_name}}Size, cs);
{%- endif %}
{%- if not loop.last %}
m += {{field_size}};
dataSize -= {{field_size}};
{%- if field|has_fd %}
n += {{field.mojom_name}}FdsSize;
fdsSize -= {{field.mojom_name}}FdsSize;
{%- endif %}
{%- endif %}
{% else %}
/* Unknown deserialization for {{field.mojom_name}}. */
{%- endif %}
{%- endmacro %}
{#
# \brief Serialize a struct
#
# Generate code for IPADataSerializer specialization, for serializing
# \a struct.
#}
{%- macro serializer(struct, namespace) %}
static std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
serialize(const {{struct|name_full}} &data,
{%- if struct|needs_control_serializer %}
ControlSerializer *cs)
{%- else %}
[[maybe_unused]] ControlSerializer *cs = nullptr)
{%- endif %}
{
std::vector<uint8_t> retData;
{%- if struct|has_fd %}
std::vector<SharedFD> retFds;
{%- endif %}
{%- for field in struct.fields %}
{{serializer_field(field, namespace, loop)}}
{%- endfor %}
{% if struct|has_fd %}
return {retData, retFds};
{%- else %}
return {retData, {}};
{%- endif %}
}
{%- endmacro %}
{#
# \brief Deserialize a struct that has fds
#
# Generate code for IPADataSerializer specialization, for deserializing
# \a struct, in the case that \a struct has file descriptors.
#}
{%- macro deserializer_fd(struct, namespace) %}
static {{struct|name_full}}
deserialize(std::vector<uint8_t> &data,
std::vector<SharedFD> &fds,
{%- if struct|needs_control_serializer %}
ControlSerializer *cs)
{%- else %}
ControlSerializer *cs = nullptr)
{%- endif %}
{
return IPADataSerializer<{{struct|name_full}}>::deserialize(data.cbegin(), data.cend(), fds.cbegin(), fds.cend(), cs);
}
{# \todo Don't inline this function #}
static {{struct|name_full}}
deserialize(std::vector<uint8_t>::const_iterator dataBegin,
std::vector<uint8_t>::const_iterator dataEnd,
std::vector<SharedFD>::const_iterator fdsBegin,
std::vector<SharedFD>::const_iterator fdsEnd,
{%- if struct|needs_control_serializer %}
ControlSerializer *cs)
{%- else %}
[[maybe_unused]] ControlSerializer *cs = nullptr)
{%- endif %}
{
{{struct|name_full}} ret;
std::vector<uint8_t>::const_iterator m = dataBegin;
std::vector<SharedFD>::const_iterator n = fdsBegin;
size_t dataSize = std::distance(dataBegin, dataEnd);
[[maybe_unused]] size_t fdsSize = std::distance(fdsBegin, fdsEnd);
{%- for field in struct.fields -%}
{{deserializer_field(field, namespace, loop)}}
{%- endfor %}
return ret;
}
{%- endmacro %}
{#
# \brief Deserialize a struct that has fds, using non-fd
#
# Generate code for IPADataSerializer specialization, for deserializing
# \a struct, in the case that \a struct has no file descriptors but requires
# deserializers with file descriptors.
#}
{%- macro deserializer_fd_simple(struct, namespace) %}
static {{struct|name_full}}
deserialize(std::vector<uint8_t> &data,
[[maybe_unused]] std::vector<SharedFD> &fds,
ControlSerializer *cs = nullptr)
{
return IPADataSerializer<{{struct|name_full}}>::deserialize(data.cbegin(), data.cend(), cs);
}
static {{struct|name_full}}
deserialize(std::vector<uint8_t>::const_iterator dataBegin,
std::vector<uint8_t>::const_iterator dataEnd,
[[maybe_unused]] std::vector<SharedFD>::const_iterator fdsBegin,
[[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd,
ControlSerializer *cs = nullptr)
{
return IPADataSerializer<{{struct|name_full}}>::deserialize(dataBegin, dataEnd, cs);
}
{%- endmacro %}
{#
# \brief Deserialize a struct that has no fds
#
# Generate code for IPADataSerializer specialization, for deserializing
# \a struct, in the case that \a struct does not have file descriptors.
#}
{%- macro deserializer_no_fd(struct, namespace) %}
static {{struct|name_full}}
deserialize(std::vector<uint8_t> &data,
{%- if struct|needs_control_serializer %}
ControlSerializer *cs)
{%- else %}
ControlSerializer *cs = nullptr)
{%- endif %}
{
return IPADataSerializer<{{struct|name_full}}>::deserialize(data.cbegin(), data.cend(), cs);
}
{# \todo Don't inline this function #}
static {{struct|name_full}}
deserialize(std::vector<uint8_t>::const_iterator dataBegin,
std::vector<uint8_t>::const_iterator dataEnd,
{%- if struct|needs_control_serializer %}
ControlSerializer *cs)
{%- else %}
[[maybe_unused]] ControlSerializer *cs = nullptr)
{%- endif %}
{
{{struct|name_full}} ret;
std::vector<uint8_t>::const_iterator m = dataBegin;
size_t dataSize = std::distance(dataBegin, dataEnd);
{%- for field in struct.fields -%}
{{deserializer_field(field, namespace, loop)}}
{%- endfor %}
return ret;
}
{%- endmacro %}