| {# TODO(yzshen): Make these templates more readable. #} |
| |
| {# 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 %} |
| {%- if pf.field.kind|is_union_kind %} |
| size += GetSerializedSize_({{input_field_pattern|format(pf.field.name)}}); |
| {%- elif pf.field.kind|is_struct_kind %} |
| size += {{input_field_pattern|format(pf.field.name)}}.is_null() |
| ? 0 |
| : GetSerializedSize_(*{{input_field_pattern|format(pf.field.name)}}); |
| {%- else %} |
| size += GetSerializedSize_({{input_field_pattern|format(pf.field.name)}}); |
| {%- endif %} |
| {%- endfor %} |
| {%- endmacro -%} |
| |
| {# A private macro that prints the C++ log-and-report serialization errors |
| macro, and conditionally returns if |should_return_errors| #} |
| {%- macro _validation_check_macro(condition, error_code, error_msg, should_return_errors=false) -%} |
| if ({{condition}}) { |
| MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING({{error_code}}, "{{error_msg}}"); |
| {%- if should_return_errors %} |
| return {{error_code}}; |
| {%- endif %} |
| } |
| {%- endmacro -%} |
| |
| {# The following 4 macros call |SerializeArray_|, |SerializeMap_|, |
| |SerializeUnion_| and |Serialize_| respectively. If |should_return_error| |
| is true, these macros do the extra work of propagating non-successful error |
| codes. #} |
| {%- macro call_serialize_array(name, kind, input, buffer, output, |
| should_return_errors, indent_size) -%} |
| { |
| const mojo::internal::ArrayValidateParams {{name}}_validate_params( |
| {{kind|get_array_validate_params_ctor_args|indent(indent_size)}}); |
| {%- if should_return_errors -%} |
| auto retval = |
| {%- endif -%} |
| mojo::SerializeArray_({{input}}, {{buffer}}, {{output}}, |
| &{{name}}_validate_params); |
| {%- if should_return_errors %} |
| if (retval != mojo::internal::ValidationError::NONE) |
| return retval; |
| {%- endif %} |
| } |
| {%- endmacro -%} |
| |
| {%- macro call_serialize_map(name, kind, input, buffer, output, |
| should_return_errors, indent_size) -%} |
| { |
| const mojo::internal::ArrayValidateParams {{name}}_validate_params( |
| {{kind.value_kind|get_map_validate_params_ctor_args|indent(indent_size)}}); |
| {%- if should_return_errors -%} |
| auto retval = |
| {%- endif -%} |
| mojo::SerializeMap_( |
| {{input}}, {{buffer}}, {{output}}, |
| &{{name}}_validate_params); |
| {%- if should_return_errors %} |
| if (retval != mojo::internal::ValidationError::NONE) |
| return retval; |
| {%- endif %} |
| } |
| {%- endmacro -%} |
| |
| {%- macro call_serialize_union(input, buffer, output, should_return_errors) -%} |
| { |
| {%- if should_return_errors %} |
| auto retval = |
| {%- endif %} |
| SerializeUnion_({{input}}, |
| {{buffer}}, |
| {{output}}); |
| {%- if should_return_errors %} |
| if (retval != mojo::internal::ValidationError::NONE) |
| return retval; |
| {%- endif %} |
| } |
| {%- endmacro -%} |
| |
| {%- macro call_serialize_struct(input, buffer, output, should_return_errors) -%} |
| { |
| {%- if should_return_errors -%} |
| auto retval = |
| {%- endif -%} |
| Serialize_({{input}}, |
| {{buffer}}, |
| {{output}}); |
| {%- if should_return_errors %} |
| if (retval != mojo::internal::ValidationError::NONE) |
| return retval; |
| {%- endif %} |
| } |
| {%- endmacro -%} |
| |
| {# 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. |
| |should_return_errors| is true if validation errors need to be return'd. |
| This is needed when serializing interface parameters, where you cannot |
| return. |
| |
| 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. |
| This macro is expanded within the C++ struct serialization methods #} |
| {%- macro serialize(struct, struct_display_name, input_field_pattern, |
| output, buffer, should_return_errors=false) -%} |
| 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 %} |
| {{call_serialize_array(name = name, |
| kind = kind, |
| input = '&' ~ input_field, |
| buffer = buffer, |
| output = "&%s->%s.ptr"|format(output,name), |
| should_return_errors = should_return_errors, |
| indent_size = 10)}} |
| {%- elif kind|is_map_kind %} |
| {{call_serialize_map(name = name, |
| kind = kind, |
| input = '&' ~ input_field, |
| buffer = buffer, |
| output = '&%s->%s.ptr'|format(output,name), |
| should_return_errors = should_return_errors, |
| indent_size = 10)}} |
| {%- elif kind|is_union_kind %} |
| internal::{{kind.name}}_Data* {{name}}_ptr = &{{output}}->{{name}}; |
| {{call_serialize_union(input = input_field ~ ".get()", |
| buffer = buffer, |
| output = "&%s_ptr"|format(name), |
| should_return_errors = should_return_errors)}} |
| {%- elif kind|is_string_kind %} |
| SerializeString_({{input_field}}, {{buffer}}, &{{output}}->{{name}}.ptr); |
| {%- else %} |
| {{call_serialize_struct(input = input_field ~ ".get()", |
| buffer = buffer, |
| output = "&%s->%s.ptr"|format(output,name), |
| should_return_errors = should_return_errors)}} |
| {%- endif %} |
| {%- if not kind|is_nullable_kind %} |
| {%- if kind|is_union_kind %} |
| {%- set condition = "%s->%s.is_null()" | format(output, name) %} |
| {%- else %} |
| {%- set condition = "!%s->%s.ptr" | format(output,name) %} |
| {%- endif %} |
| {{_validation_check_macro( |
| condition = condition, |
| error_code = "mojo::internal::ValidationError::UNEXPECTED_NULL_POINTER", |
| error_msg = "null %s in %s" | format(name, struct_display_name), |
| should_return_errors = should_return_errors)}} |
| {%- endif %} |
| {%- elif kind|is_any_handle_kind or kind|is_interface_kind %} |
| {%- if kind|is_interface_kind %} |
| mojo::internal::InterfaceHandleToData({{input_field}}.Pass(), |
| &{{output}}->{{name}}); |
| {%- elif kind|is_interface_request_kind %} |
| {{output}}->{{name}} = {{input_field}}.PassMessagePipe().release(); |
| {%- else %} |
| {{output}}->{{name}} = {{input_field}}.release(); |
| {%- endif %} |
| {%- if not kind|is_nullable_kind %} |
| {%- if kind|is_interface_kind %} |
| {%- set condition = "!%s->%s.handle.is_valid()" | format(output, name) %} |
| {%- else %} |
| {%- set condition = "!%s->%s.is_valid()" | format(output,name) %} |
| {%- endif %} |
| {{_validation_check_macro( |
| condition = condition, |
| error_code = "mojo::internal::ValidationError::UNEXPECTED_INVALID_HANDLE", |
| error_msg = "invalid %s in %s" | format(name, struct_display_name), |
| should_return_errors = should_return_errors)}} |
| {%- endif %} |
| {%- elif kind|is_enum_kind %} |
| {{output}}->{{name}} = |
| static_cast<int32_t>({{input_field}}); |
| {%- else %} |
| {{output}}->{{name}} = {{input_field}}; |
| {%- endif %} |
| {%- endfor %} |
| {%- endmacro -%} |
| |
| {# 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 %} |
| {%- if kind|is_union_kind %} |
| if (!{{input}}->{{name}}.is_null()) { |
| {{output_field}} = {{kind|get_name_for_kind}}::New(); |
| Deserialize_(&{{input}}->{{name}}, {{output_field}}.get()); |
| } |
| {%- elif kind|is_struct_kind %} |
| if ({{input}}->{{name}}.ptr) { |
| {{output_field}} = {{kind|get_name_for_kind}}::New(); |
| Deserialize_({{input}}->{{name}}.ptr, {{output_field}}.get()); |
| } |
| {%- else %} |
| {#- Arrays and Maps #} |
| Deserialize_({{input}}->{{name}}.ptr, &{{output_field}}); |
| {%- endif %} |
| {%- elif kind|is_interface_kind %} |
| mojo::internal::InterfaceDataToHandle(&{{input}}->{{name}}, &{{output_field}}); |
| {%- elif 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 %} |
| } while (false); |
| {%- endmacro %} |
| |
| {# Forward declares |struct|, and typedefs the appropriate Ptr wrapper |
| (|mojo::StructPtr| or |mojo::InlinedStructPtr|). This macro is expanded for |
| all generated structs: |
| - user-defined mojo structs |
| - interface method params/response params #} |
| {%- macro structptr_forward_decl(struct) -%} |
| class {{struct.name}}; |
| {% if struct|should_inline %} |
| using {{struct.name}}Ptr = mojo::InlinedStructPtr<{{struct.name}}>; |
| {% else %} |
| using {{struct.name}}Ptr = mojo::StructPtr<{{struct.name}}>; |
| {% endif %} |
| {% endmacro %} |