utils: ipc: Add support for Flags
Add Flags<E> as a supported type in the IPA interface. It is used in mojom with the [flags] attribute. Any field or parameter type E that is prefixed with the [flags] attribute will direct the code generator to generate the type name "Flags<E>" and appropriate serialization/deserialization code for Flags<E> instead of for E. It is usable and has been tested in struct members, function input and output parameters, and Signal parameters. This does not add support for returning Flags as direct return values. Additionally, the [scopedEnum] attribute can be used on enum definitions, which will instruct the code generator to convert it to an enum class instead of a raw enum. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
This commit is contained in:
parent
fc6b5f49e1
commit
207c9e1c1d
8 changed files with 62 additions and 11 deletions
|
@ -33,6 +33,15 @@ module libcamera;
|
||||||
* available for the type and there's no need to generate one
|
* available for the type and there's no need to generate one
|
||||||
* - hasFd - struct fields or empty structs only
|
* - hasFd - struct fields or empty structs only
|
||||||
* - Designate that this field or empty struct contains a SharedFD
|
* - Designate that this field or empty struct contains a SharedFD
|
||||||
|
* - scopedEnum - enum definitions
|
||||||
|
* - Designate that this enum should be an enum class, as opposed to a pure
|
||||||
|
* enum
|
||||||
|
* - flags - struct fields or function parameters that are enums
|
||||||
|
* - Designate that this enum type E should be Flags<E> in the generated C++
|
||||||
|
* code
|
||||||
|
* - For example, if a struct field is defined as `[flags] ErrorFlag f;`
|
||||||
|
* (where ErrorFlag is defined as an enum elsewhere in mojom), then the
|
||||||
|
* generated code for this field will be `Flags<ErrorFlag> f`
|
||||||
*
|
*
|
||||||
* Rules:
|
* Rules:
|
||||||
* - If the type is defined in a libcamera C++ header *and* a (de)serializer is
|
* - If the type is defined in a libcamera C++ header *and* a (de)serializer is
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <libcamera/base/flags.h>
|
||||||
#include <libcamera/base/signal.h>
|
#include <libcamera/base/signal.h>
|
||||||
|
|
||||||
#include <libcamera/controls.h>
|
#include <libcamera/controls.h>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
# \param enum Enum object whose definition is to be generated
|
# \param enum Enum object whose definition is to be generated
|
||||||
#}
|
#}
|
||||||
{%- macro define_enum(enum) -%}
|
{%- macro define_enum(enum) -%}
|
||||||
enum {{enum.mojom_name}} {
|
enum{{" class" if enum|is_scoped}} {{enum.mojom_name}} {
|
||||||
{%- for field in enum.fields %}
|
{%- for field in enum.fields %}
|
||||||
{{field.mojom_name}} = {{field.numeric_value}},
|
{{field.mojom_name}} = {{field.numeric_value}},
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
|
|
@ -69,7 +69,7 @@ public:
|
||||||
{%- for method in interface_event.methods %}
|
{%- for method in interface_event.methods %}
|
||||||
Signal<
|
Signal<
|
||||||
{%- for param in method.parameters -%}
|
{%- for param in method.parameters -%}
|
||||||
{{"const " if not param|is_pod}}{{param|name}}{{" &" if not param|is_pod}}
|
{{"const " if not param|is_pod}}{{param|name}}{{" &" if not param|is_pod and not param|is_enum}}
|
||||||
{{- ", " if not loop.last}}
|
{{- ", " if not loop.last}}
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
> {{method.mojom_name}};
|
> {{method.mojom_name}};
|
||||||
|
|
|
@ -46,7 +46,7 @@ public:
|
||||||
{%- for method in interface_event.methods %}
|
{%- for method in interface_event.methods %}
|
||||||
Signal<
|
Signal<
|
||||||
{%- for param in method.parameters -%}
|
{%- for param in method.parameters -%}
|
||||||
{{"const " if not param|is_pod}}{{param|name}}{{" &" if not param|is_pod}}
|
{{"const " if not param|is_pod}}{{param|name}}{{" &" if not param|is_pod and not param|is_enum}}
|
||||||
{{- ", " if not loop.last}}
|
{{- ", " if not loop.last}}
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
> {{method.mojom_name}};
|
> {{method.mojom_name}};
|
||||||
|
|
|
@ -62,7 +62,9 @@
|
||||||
{%- else %}
|
{%- else %}
|
||||||
std::tie({{param.mojom_name}}Buf, std::ignore) =
|
std::tie({{param.mojom_name}}Buf, std::ignore) =
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if param|is_enum %}
|
{%- 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}})
|
IPADataSerializer<uint32_t>::serialize(static_cast<uint32_t>({{param.mojom_name}})
|
||||||
{%- else %}
|
{%- else %}
|
||||||
IPADataSerializer<{{param|name}}>::serialize({{param.mojom_name}}
|
IPADataSerializer<{{param|name}}>::serialize({{param.mojom_name}}
|
||||||
|
@ -105,7 +107,9 @@
|
||||||
#}
|
#}
|
||||||
{%- macro deserialize_param(param, pointer, loop, buf, fds, iter, data_size) -%}
|
{%- macro deserialize_param(param, pointer, loop, buf, fds, iter, data_size) -%}
|
||||||
{{"*" if pointer}}{{param.mojom_name}} =
|
{{"*" if pointer}}{{param.mojom_name}} =
|
||||||
{%- if param|is_enum %}
|
{%- if param|is_flags %}
|
||||||
|
IPADataSerializer<{{param|name_full}}>::deserialize(
|
||||||
|
{%- elif param|is_enum %}
|
||||||
static_cast<{{param|name_full}}>(IPADataSerializer<uint32_t>::deserialize(
|
static_cast<{{param|name_full}}>(IPADataSerializer<uint32_t>::deserialize(
|
||||||
{%- else %}
|
{%- else %}
|
||||||
IPADataSerializer<{{param|name}}>::deserialize(
|
IPADataSerializer<{{param|name}}>::deserialize(
|
||||||
|
@ -133,7 +137,7 @@ IPADataSerializer<{{param|name}}>::deserialize(
|
||||||
{%- if param|needs_control_serializer %}
|
{%- if param|needs_control_serializer %}
|
||||||
&controlSerializer_
|
&controlSerializer_
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
){{")" if param|is_enum}};
|
){{")" if param|is_enum and not param|is_flags}};
|
||||||
{%- endmacro -%}
|
{%- endmacro -%}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,10 @@
|
||||||
std::tie({{field.mojom_name}}, std::ignore) =
|
std::tie({{field.mojom_name}}, std::ignore) =
|
||||||
{%- if field|is_pod %}
|
{%- if field|is_pod %}
|
||||||
IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}});
|
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 %}
|
{%- elif field|is_enum %}
|
||||||
IPADataSerializer<uint{{field|bit_width}}_t>::serialize(data.{{field.mojom_name}});
|
IPADataSerializer<uint{{field|bit_width}}_t>::serialize(data.{{field.mojom_name}});
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
@ -96,6 +100,8 @@
|
||||||
{{- check_data_size(field_size, 'dataSize', field.mojom_name, 'data')}}
|
{{- check_data_size(field_size, 'dataSize', field.mojom_name, 'data')}}
|
||||||
{%- if field|is_pod %}
|
{%- if field|is_pod %}
|
||||||
ret.{{field.mojom_name}} = IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field_size}});
|
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 %}
|
{%- else %}
|
||||||
ret.{{field.mojom_name}} = static_cast<{{field|name_full}}>(IPADataSerializer<uint{{field|bit_width}}_t>::deserialize(m, m + {{field_size}}));
|
ret.{{field.mojom_name}} = static_cast<{{field|name_full}}>(IPADataSerializer<uint{{field|bit_width}}_t>::deserialize(m, m + {{field_size}}));
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
|
@ -74,6 +74,8 @@ def GetDefaultValue(element):
|
||||||
return element.default
|
return element.default
|
||||||
if type(element.kind) == mojom.Kind:
|
if type(element.kind) == mojom.Kind:
|
||||||
return '0'
|
return '0'
|
||||||
|
if IsFlags(element):
|
||||||
|
return ''
|
||||||
if mojom.IsEnumKind(element.kind):
|
if mojom.IsEnumKind(element.kind):
|
||||||
return f'static_cast<{element.kind.mojom_name}>(0)'
|
return f'static_cast<{element.kind.mojom_name}>(0)'
|
||||||
if isinstance(element.kind, mojom.Struct) and \
|
if isinstance(element.kind, mojom.Struct) and \
|
||||||
|
@ -184,7 +186,7 @@ def MethodParameters(method):
|
||||||
params = []
|
params = []
|
||||||
for param in method.parameters:
|
for param in method.parameters:
|
||||||
params.append('const %s %s%s' % (GetNameForElement(param),
|
params.append('const %s %s%s' % (GetNameForElement(param),
|
||||||
'&' if not IsPod(param) else '',
|
'' if IsPod(param) or IsEnum(param) else '&',
|
||||||
param.mojom_name))
|
param.mojom_name))
|
||||||
for param in MethodParamOutputs(method):
|
for param in MethodParamOutputs(method):
|
||||||
params.append(f'{GetNameForElement(param)} *{param.mojom_name}')
|
params.append(f'{GetNameForElement(param)} *{param.mojom_name}')
|
||||||
|
@ -220,9 +222,30 @@ def IsControls(element):
|
||||||
def IsEnum(element):
|
def IsEnum(element):
|
||||||
return mojom.IsEnumKind(element.kind)
|
return mojom.IsEnumKind(element.kind)
|
||||||
|
|
||||||
|
|
||||||
|
# Only works the enum definition, not types
|
||||||
|
def IsScoped(element):
|
||||||
|
attributes = getattr(element, 'attributes', None)
|
||||||
|
if not attributes:
|
||||||
|
return False
|
||||||
|
return 'scopedEnum' in attributes
|
||||||
|
|
||||||
|
|
||||||
|
def IsEnumScoped(element):
|
||||||
|
if not IsEnum(element):
|
||||||
|
return False
|
||||||
|
return IsScoped(element.kind)
|
||||||
|
|
||||||
def IsFd(element):
|
def IsFd(element):
|
||||||
return mojom.IsStructKind(element.kind) and element.kind.mojom_name == "SharedFD"
|
return mojom.IsStructKind(element.kind) and element.kind.mojom_name == "SharedFD"
|
||||||
|
|
||||||
|
|
||||||
|
def IsFlags(element):
|
||||||
|
attributes = getattr(element, 'attributes', None)
|
||||||
|
if not attributes:
|
||||||
|
return False
|
||||||
|
return 'flags' in attributes
|
||||||
|
|
||||||
def IsMap(element):
|
def IsMap(element):
|
||||||
return mojom.IsMapKind(element.kind)
|
return mojom.IsMapKind(element.kind)
|
||||||
|
|
||||||
|
@ -251,9 +274,11 @@ def ByteWidthFromCppType(t):
|
||||||
raise Exception('invalid type')
|
raise Exception('invalid type')
|
||||||
return str(int(_bit_widths[key]) // 8)
|
return str(int(_bit_widths[key]) // 8)
|
||||||
|
|
||||||
|
|
||||||
# Get the type name for a given element
|
# Get the type name for a given element
|
||||||
def GetNameForElement(element):
|
def GetNameForElement(element):
|
||||||
|
# Flags
|
||||||
|
if IsFlags(element):
|
||||||
|
return f'Flags<{GetFullNameForElement(element.kind)}>'
|
||||||
# structs
|
# structs
|
||||||
if (mojom.IsEnumKind(element) or
|
if (mojom.IsEnumKind(element) or
|
||||||
mojom.IsInterfaceKind(element) or
|
mojom.IsInterfaceKind(element) or
|
||||||
|
@ -302,15 +327,18 @@ def GetNameForElement(element):
|
||||||
def GetFullNameForElement(element):
|
def GetFullNameForElement(element):
|
||||||
name = GetNameForElement(element)
|
name = GetNameForElement(element)
|
||||||
namespace_str = ''
|
namespace_str = ''
|
||||||
if mojom.IsStructKind(element):
|
if (mojom.IsStructKind(element) or mojom.IsEnumKind(element)):
|
||||||
namespace_str = element.module.mojom_namespace.replace('.', '::')
|
namespace_str = element.module.mojom_namespace.replace('.', '::')
|
||||||
elif (hasattr(element, 'kind') and
|
elif (hasattr(element, 'kind') and
|
||||||
(mojom.IsStructKind(element.kind) or
|
(mojom.IsStructKind(element.kind) or mojom.IsEnumKind(element.kind))):
|
||||||
mojom.IsEnumKind(element.kind))):
|
|
||||||
namespace_str = element.kind.module.mojom_namespace.replace('.', '::')
|
namespace_str = element.kind.module.mojom_namespace.replace('.', '::')
|
||||||
|
|
||||||
if namespace_str == '':
|
if namespace_str == '':
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
if IsFlags(element):
|
||||||
|
return GetNameForElement(element)
|
||||||
|
|
||||||
return f'{namespace_str}::{name}'
|
return f'{namespace_str}::{name}'
|
||||||
|
|
||||||
def ValidateZeroLength(l, s, cap=True):
|
def ValidateZeroLength(l, s, cap=True):
|
||||||
|
@ -407,10 +435,13 @@ class Generator(generator.Generator):
|
||||||
'is_array': IsArray,
|
'is_array': IsArray,
|
||||||
'is_controls': IsControls,
|
'is_controls': IsControls,
|
||||||
'is_enum': IsEnum,
|
'is_enum': IsEnum,
|
||||||
|
'is_enum_scoped': IsEnumScoped,
|
||||||
'is_fd': IsFd,
|
'is_fd': IsFd,
|
||||||
|
'is_flags': IsFlags,
|
||||||
'is_map': IsMap,
|
'is_map': IsMap,
|
||||||
'is_plain_struct': IsPlainStruct,
|
'is_plain_struct': IsPlainStruct,
|
||||||
'is_pod': IsPod,
|
'is_pod': IsPod,
|
||||||
|
'is_scoped': IsScoped,
|
||||||
'is_str': IsStr,
|
'is_str': IsStr,
|
||||||
'method_input_has_fd': MethodInputHasFd,
|
'method_input_has_fd': MethodInputHasFd,
|
||||||
'method_output_has_fd': MethodOutputHasFd,
|
'method_output_has_fd': MethodOutputHasFd,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue