chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl

{#  TODO(yzshen): Make these templates more readable. #}

{#  Serializes the specified struct.
    |struct| is the struct definition.
    |struct_display_name| is the display name for the struct that can be showed
    in error/log messages, for example, "FooStruct", "FooMethod request".
    |input_field_pattern| should be a pattern that contains one string
    placeholder, for example, "input->%s", "p_%s". The placeholder will be
    substituted with struct field names to refer to the input fields.
    |fragment| is the name of the MessageFragment to serialize into.
    |input_may_be_temp|: please see the comments of get_serialized_size.
    This macro is expanded to do serialization for both:
    - user-defined structs: the input is an instance of the corresponding struct
      wrapper class.
    - method parameters/response parameters: the input is a list of
      arguments. #}
{%- macro serialize(struct, struct_display_name, input_field_pattern, fragment,
                    input_may_be_temp=False) -%}
  {{fragment}}.Allocate();
{%- for pf in struct.packed.packed_fields_in_ordinal_order %}

{%-   if pf|is_nullable_value_kind_packed_field %}
{%-     if pf|is_primary_nullable_value_kind_packed_field %}
{%-       set original_field = pf.original_field %}
{%-       set has_value_pf = pf %}
{%-       set value_pf = pf.linked_value_packed_field %}
{%-       set input_field = input_field_pattern|format(original_field.name) %}
{%-       set name = original_field.name %}
{%-       set kind = original_field.kind %}
{%-       set serializer_type = value_pf.field.kind|unmapped_type_for_serializer %}
  {{fragment}}->{{has_value_pf.field.name}} = {{input_field}}.has_value();
{%-       if kind|is_enum_kind %}
  if ({{input_field}}.has_value()) {
    mojo::internal::Serialize<{{serializer_type}}>(
        {{input_field}}.value(), &{{fragment}}->{{value_pf.field.name}});
  } else {
    {{fragment}}->{{value_pf.field.name}} =
        static_cast<int32_t>({{serializer_type}}::kMinValue);
  }
{%-       else %}
  if ({{input_field}}.has_value()) {
    {{fragment}}->{{value_pf.field.name}} = {{input_field}}.value();
  }
{%-       endif %}
{%-     endif %}
{%-   else %}

{%-     set input_field = input_field_pattern|format(pf.field.name) %}
{%-     set name = pf.field.name %}
{%-     set kind = pf.field.kind %}
{%-     set serializer_type = kind|unmapped_type_for_serializer %}

{%-     if kind|is_object_kind or kind|is_any_handle_or_interface_kind %}
{%-       set original_input_field = input_field_pattern|format(name) %}
{%-       set input_field = "in_%s"|format(name) if input_may_be_temp
                                                 else original_input_field %}
{%-       if input_may_be_temp %}
  decltype({{original_input_field}}) in_{{name}} = {{original_input_field}};
{%-       endif %}
{%-     endif %}

{%-     if kind|is_object_kind %}
{%-       if kind|is_array_kind or kind|is_map_kind %}
  mojo::internal::MessageFragment<
      typename decltype({{fragment}}->{{name}})::BaseType>
      {{name}}_fragment({{fragment}}.message());
  constexpr const mojo::internal::ContainerValidateParams& {{name}}_validate_params =
      {{kind|get_container_validate_params_ctor_args|indent(6)}};
  mojo::internal::Serialize<{{serializer_type}}>(
      {{input_field}}, {{name}}_fragment, &{{name}}_validate_params);
  {{fragment}}->{{name}}.Set(
      {{name}}_fragment.is_null() ? nullptr : {{name}}_fragment.data());
{%-       elif kind|is_union_kind %}
  mojo::internal::MessageFragment<decltype({{fragment}}->{{name}})>
      {{name}}_fragment({{fragment}}.message());
  {{name}}_fragment.Claim(&{{fragment}}->{{name}});
  mojo::internal::Serialize<{{serializer_type}}>(
      {{input_field}}, {{name}}_fragment, true);
{%-       else %}
  mojo::internal::MessageFragment<
      typename decltype({{fragment}}->{{name}})::BaseType> {{name}}_fragment(
          {{fragment}}.message());
  mojo::internal::Serialize<{{serializer_type}}>(
      {{input_field}}, {{name}}_fragment);
  {{fragment}}->{{name}}.Set(
      {{name}}_fragment.is_null() ? nullptr : {{name}}_fragment.data());
{%-       endif %}
{%-       if not kind|is_nullable_kind %}
  MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
      {{fragment}}->{{name}}.is_null(),
      mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
      "null {{name}} in {{struct_display_name}}");
{%-       endif %}

{%-     elif kind|is_any_handle_or_interface_kind %}
  mojo::internal::Serialize<{{serializer_type}}>(
      {{input_field}}, &{{fragment}}->{{name}}, &{{fragment}}.message());
{%-       if not kind|is_nullable_kind %}
  MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
      !mojo::internal::IsHandleOrInterfaceValid({{fragment}}->{{name}}),
{%-         if kind|is_associated_kind %}
      mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID,
{%-         else %}
      mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
{%-         endif %}
      "invalid {{name}} in {{struct_display_name}}");
{%-       endif %}

{%-     elif kind|is_enum_kind %}
  mojo::internal::Serialize<{{serializer_type}}>(
      {{input_field}}, &{{fragment}}->{{name}});

{%-     else %}
  {{fragment}}->{{name}} = {{input_field}};
{%-     endif %}
{%-   endif %}
{%- endfor %}
{%- endmacro -%}

{#  Deserializes the specified struct.
    |struct| is the struct definition.
    |input| is the name of the input struct data view. It is expected to be
    non-null.
    |output_field_pattern| should be a pattern that contains one string
    placeholder, for example, "result->%s", "p_%s". The placeholder will be
    substituted with struct field names to refer to the output fields.
    |message| is the name of the Message object we're deserializing.
    |success| is the name of a bool variable to track success of the operation.
    This macro is expanded to do deserialization for both:
    - user-defined structs: the output is an instance of the corresponding
      struct wrapper class.
    - method parameters/response parameters: the output is a list of
      arguments. #}
{%- macro deserialize(struct, input, output_field_pattern, success) -%}
{%-   for pf in struct.packed.packed_fields_in_ordinal_order %}
{%-     if pf|is_nullable_value_kind_packed_field %}
{%-       if pf|is_primary_nullable_value_kind_packed_field %}
{%-         set original_field = pf.original_field %}
{%-         set output_field = output_field_pattern|format(original_field.name) %}
{%-         set name = original_field.name %}
{%-         set kind = original_field.kind %}
{%-         if kind|is_enum_kind %}
  if ({{success}} && !{{input}}.Read{{name|under_to_camel}}(&{{output_field}})) {
    {{success}} = false;
{%-         else %}
  if ({{success}}) {
    {{output_field}} = {{input}}.{{name}}();
{%-         endif %}
  }
{%-       endif %}
{%-     else %}
{%-       set output_field = output_field_pattern|format(pf.field.name) %}
{%-       set name = pf.field.name %}
{%-       set kind = pf.field.kind %}
{%-       if kind|is_object_kind or kind|is_enum_kind %}
  if ({{success}} && !{{input}}.Read{{name|under_to_camel}}(&{{output_field}}))
    {{success}} = false;
{%-       elif kind|is_any_handle_kind %}
  if ({{success}})
    {{output_field}} = {{input}}.Take{{name|under_to_camel}}();
{%-       elif kind|is_any_interface_kind %}
  if ({{success}}) {
    {{output_field}} =
        {{input}}.Take{{name|under_to_camel}}<decltype({{output_field}})>();
  }
{%-       else %}
  if ({{success}})
    {{output_field}} = {{input}}.{{name}}();
{%-       endif %}
{%-     endif %}
{%-   endfor %}
{%- endmacro %}

{%- macro assert_nullable_output_type_if_necessary(kind, name) -%}
{%-   if kind|is_nullable_kind and not kind|is_native_only_kind %}
static_assert(
    mojo::internal::IsValidUserTypeForOptionalValue<
        {{kind|unmapped_type_for_serializer}}, UserType>(),
    "Attempting to read the optional `{{name}}` field into a type which "
    "cannot represent a null value. Either wrap the destination object "
    "with std::optional, ensure that any corresponding "
    "{Struct/Union/Array/String}Traits define the necessary IsNull and "
    "SetToNull methods, or use `MaybeRead{{name|under_to_camel}}` instead "
    "of `Read{{name|under_to_camel}} if you're fine with null values being "
    "silently ignored in this case.");
{%-   endif %}
{%- endmacro %}