Index: third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl |
diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl |
index 623ebb441c69938da26e8489662eb65641f82f5d..03911b9b39b47e10ae9386c56624cb41e2c08d09 100644 |
--- a/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl |
+++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl |
@@ -1,124 +1,118 @@ |
-{%- macro validate(struct, class_name) %} |
- if (!data) |
- return true; |
+{# TODO(yzshen): Make these templates more readable. #} |
- if (!ValidateStructHeader( |
- data, sizeof({{class_name}}), |
- {{struct.packed.packed_fields|length}}, bounds_checker)) { |
- return false; |
- } |
- |
- const {{class_name}}* object = static_cast<const {{class_name}}*>(data); |
- MOJO_ALLOW_UNUSED_LOCAL(object); |
- |
-{%- for packed_field in struct.packed.packed_fields %} |
-{%- set name = packed_field.field.name %} |
-{%- set kind = packed_field.field.kind %} |
-{%- if kind|is_object_kind %} |
-{%- set wrapper_type = kind|cpp_wrapper_type %} |
-{%- if not kind|is_nullable_kind %} |
- if (!object->{{name}}.offset) { |
- ReportValidationError( |
- mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, |
- "null {{name}} field in {{struct.name}} struct"); |
- return false; |
- } |
-{%- endif %} |
- if (!mojo::internal::ValidateEncodedPointer(&object->{{name}}.offset)) { |
- ReportValidationError(mojo::internal::VALIDATION_ERROR_ILLEGAL_POINTER); |
- return false; |
- } |
-{%- if kind|is_array_kind or kind|is_string_kind %} |
- if (!{{wrapper_type}}::Data_::Validate< |
- {{kind|get_array_validate_params|indent(10)}}>( |
- mojo::internal::DecodePointerRaw(&object->{{name}}.offset), |
- bounds_checker)) { |
-{%- elif kind|is_map_kind %} |
- if (!{{wrapper_type}}::Data_::Validate< |
- {{kind.value_kind|get_map_validate_params|indent(10)}}>( |
- mojo::internal::DecodePointerRaw(&object->{{name}}.offset), |
- bounds_checker)) { |
-{%- elif kind|is_struct_kind %} |
- if (!{{kind|get_name_for_kind}}::Data_::Validate( |
- mojo::internal::DecodePointerRaw(&object->{{name}}.offset), |
- bounds_checker)) { |
-{%- else %} |
- if (!{{wrapper_type}}::Data_::Validate( |
- mojo::internal::DecodePointerRaw(&object->{{name}}.offset), |
- bounds_checker)) { |
-{%- endif %} |
- return false; |
- } |
-{%- elif kind|is_any_handle_kind %} |
-{%- if not kind|is_nullable_kind %} |
- if (object->{{name}}.value() == mojo::internal::kEncodedInvalidHandleValue) { |
- ReportValidationError( |
- mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, |
- "invalid {{name}} field in {{struct.name}} struct"); |
- return false; |
- } |
-{%- endif %} |
- if (!bounds_checker->ClaimHandle(object->{{name}})) { |
- ReportValidationError(mojo::internal::VALIDATION_ERROR_ILLEGAL_HANDLE); |
- return false; |
- } |
-{%- endif %} |
+{# Computes the serialized size for the specified struct. |
+ |struct| is the struct definition. |
+ |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. |
+ This macro is expanded to compute seriailized size 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. |
+ It declares |size| of type size_t to store the resulting size. #} |
+{%- macro get_serialized_size(struct, input_field_pattern) -%} |
+ size_t size = sizeof(internal::{{struct.name}}_Data); |
+{%- for pf in struct.packed.packed_fields_in_ordinal_order if pf.field.kind|is_object_kind %} |
+ size += GetSerializedSize_({{input_field_pattern|format(pf.field.name)}}); |
{%- endfor %} |
+{%- endmacro -%} |
- return true; |
-{%- endmacro %} |
- |
-{%- macro field_line(field) %} |
-{%- set type = field.kind|cpp_field_type %} |
-{%- set name = field.name -%} |
-{%- if field.kind.spec == 'b' -%} |
- uint8_t {{name}} : 1; |
-{%- elif field.kind|is_enum_kind -%} |
- int32_t {{name}}; |
-{%- else -%} |
- {{type}} {{name}}; |
-{%- endif %} |
-{%- endmacro %} |
- |
-{%- macro fields(struct) %} |
-{%- for packed_field in struct.packed.packed_fields %} |
- {{field_line(packed_field.field)}} |
-{%- if not loop.last %} |
-{%- set next_pf = struct.packed.packed_fields[loop.index0 + 1] %} |
-{%- set pad = next_pf.offset - (packed_field.offset + packed_field.size) %} |
-{%- if pad > 0 %} |
- uint8_t pad{{loop.index0}}_[{{pad}}]; |
-{%- endif %} |
+{# 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. |
+ |output| is the name of the output struct instance. |
+ |buffer| is the name of the Buffer instance used. |
+ 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, output, buffer) -%} |
+ internal::{{struct.name}}_Data* {{output}} = |
+ internal::{{struct.name}}_Data::New({{buffer}}); |
+{%- for pf in struct.packed.packed_fields_in_ordinal_order %} |
+{%- set input_field = input_field_pattern|format(pf.field.name) %} |
+{%- set name = pf.field.name %} |
+{%- set kind = pf.field.kind %} |
+{%- if kind|is_object_kind %} |
+{%- if kind|is_array_kind %} |
+ mojo::SerializeArray_<{{kind|get_array_validate_params|indent(24)}}>( |
+ mojo::internal::Forward({{input_field}}), {{buffer}}, &{{output}}->{{name}}.ptr); |
+{%- elif kind|is_map_kind %} |
+ mojo::SerializeMap_<{{kind.value_kind|get_map_validate_params|indent(24)}}>( |
+ mojo::internal::Forward({{input_field}}), {{buffer}}, &{{output}}->{{name}}.ptr); |
+{%- else %} |
+ Serialize_(mojo::internal::Forward({{input_field}}), {{buffer}}, &{{output}}->{{name}}.ptr); |
{%- endif %} |
-{%- endfor -%} |
- |
-{%- set num_fields = struct.packed.packed_fields|length %} |
-{%- if num_fields > 0 %} |
-{%- set last_field = struct.packed.packed_fields[num_fields - 1] %} |
-{%- set offset = last_field.offset + last_field.size %} |
-{%- set pad = offset|get_pad(8) -%} |
-{%- if pad > 0 %} |
- uint8_t padfinal_[{{pad}}]; |
+{%- if not kind|is_nullable_kind %} |
+ MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( |
+ !{{output}}->{{name}}.ptr, |
+ mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, |
+ "null {{name}} in {{struct_display_name}}"); |
{%- endif %} |
-{%- endif %} |
-{%- endmacro %} |
- |
-{%- macro encodes(struct) -%} |
-{%- for pf in struct.packed.packed_fields %} |
-{%- if pf.field.kind|is_object_kind %} |
-mojo::internal::Encode(&{{pf.field.name}}, handles); |
-{%- elif pf.field.kind|is_any_handle_kind %} |
-mojo::internal::EncodeHandle(&{{pf.field.name}}, handles); |
+{%- elif kind|is_any_handle_kind %} |
+{%- if kind|is_interface_kind or kind|is_interface_request_kind %} |
+ {{output}}->{{name}} = {{input_field}}.PassMessagePipe().release(); |
+{%- else %} |
+ {{output}}->{{name}} = {{input_field}}.release(); |
{%- endif %} |
-{%- endfor %} |
+{%- if not kind|is_nullable_kind %} |
+ MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( |
+ !{{output}}->{{name}}.is_valid(), |
+ mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, |
+ "invalid {{name}} in {{struct_display_name}}"); |
+{%- endif %} |
+{%- else %} |
+ {{output}}->{{name}} = {{input_field}}; |
+{%- endif %} |
+{%- endfor %} |
{%- endmacro -%} |
-{%- macro decodes(struct) -%} |
-{%- for pf in struct.packed.packed_fields %} |
-{%- if pf.field.kind|is_object_kind %} |
-mojo::internal::Decode(&{{pf.field.name}}, handles); |
-{%- elif pf.field.kind|is_any_handle_kind %} |
-mojo::internal::DecodeHandle(&{{pf.field.name}}, handles); |
+{# Deserializes the specified struct. |
+ |struct| is the struct definition. |
+ |input| is the name of the input struct instance. |
+ |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. |
+ 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) -%} |
+ do { |
+ // NOTE: The memory backing |{{input}}| may has be smaller than |
+ // |sizeof(*{{input}})| if the message comes from an older version. |
+{#- Before deserialize fields introduced at a certain version, we need to add |
+ a version check, which makes sure we skip further deserialization if |
+ |input| is from an earlier version. |last_checked_version| records the |
+ last version that we have added such version check. #} |
+{%- set last_checked_version = 0 %} |
+{%- for pf in struct.packed.packed_fields_in_ordinal_order %} |
+{%- set output_field = output_field_pattern|format(pf.field.name) %} |
+{%- set name = pf.field.name %} |
+{%- set kind = pf.field.kind %} |
+{%- if pf.min_version > last_checked_version %} |
+{%- set last_checked_version = pf.min_version %} |
+ if ({{input}}->header_.version < {{pf.min_version}}) |
+ break; |
+{%- endif %} |
+{%- if kind|is_object_kind %} |
+ Deserialize_({{input}}->{{name}}.ptr, &{{output_field}}); |
+{%- elif kind|is_interface_kind or kind|is_interface_request_kind %} |
+ {{output_field}}.Bind(mojo::MakeScopedHandle(mojo::internal::FetchAndReset(&{{input}}->{{name}}))); |
+{%- elif kind|is_any_handle_kind %} |
+ {{output_field}}.reset(mojo::internal::FetchAndReset(&{{input}}->{{name}})); |
+{%- elif kind|is_enum_kind %} |
+ {{output_field}} = static_cast<{{kind|cpp_wrapper_type}}>({{input}}->{{name}}); |
+{%- else %} |
+ {{output_field}} = {{input}}->{{name}}; |
{%- endif %} |
{%- endfor %} |
-{%- endmacro -%} |
+ } while (false); |
+{%- endmacro %} |