summaryrefslogtreecommitdiff
path: root/utils/codegen/ipc/generators/libcamera_templates/serializer.tmpl
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2024-08-08 18:13:00 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2024-08-15 23:59:08 +0300
commit50c92cc7e2924009ecab3e4004448b01d687707c (patch)
treec22b49816a3c79dae4727780962aa0928df42b52 /utils/codegen/ipc/generators/libcamera_templates/serializer.tmpl
parentd3bf27180ef1d91b86b7b87a2378e559eaff5455 (diff)
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>
Diffstat (limited to 'utils/codegen/ipc/generators/libcamera_templates/serializer.tmpl')
-rw-r--r--utils/codegen/ipc/generators/libcamera_templates/serializer.tmpl319
1 files changed, 319 insertions, 0 deletions
diff --git a/utils/codegen/ipc/generators/libcamera_templates/serializer.tmpl b/utils/codegen/ipc/generators/libcamera_templates/serializer.tmpl
new file mode 100644
index 00000000..323e1293
--- /dev/null
+++ b/utils/codegen/ipc/generators/libcamera_templates/serializer.tmpl
@@ -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 %}