{%- set struct_prefix = "%s.%s"|format(module_prefix, struct.name) %}
{{ kythe_annotation(struct_prefix) }}
class {{export_attribute}} {{struct.name}} {
public:
template <typename T>
using EnableIfSame = std::enable_if_t<std::is_same<{{struct.name}}, T>::value>;
using DataView = {{struct.name}}DataView;
using Data_ = internal::{{struct.name}}_Data;
{#--- Enums #}
{%- for enum in struct.enums -%}
{{ kythe_annotation(enum|get_full_mojom_name_for_kind()) }}
using {{enum.name}} = {{enum|get_name_for_kind(flatten_nested_kind=True)}};
{%- endfor %}
{#--- Constants #}
{%- for constant in struct.constants %}
{{ kythe_annotation("%s.%s"|format(struct_prefix, constant.name)) }}
static {{constant|format_constant_declaration(nested=True)}};
{%- endfor %}
template <typename... Args>
static {{struct.name}}Ptr New(Args&&... args) {
return {{struct.name}}Ptr(
std::in_place, std::forward<Args>(args)...);
}
template <typename U>
static {{struct.name}}Ptr From(const U& u) {
return mojo::TypeConverter<{{struct.name}}Ptr, U>::Convert(u);
}
template <typename U>
U To() const {
return mojo::TypeConverter<U, {{struct.name}}>::Convert(*this);
}
{% for constructor in struct|struct_constructors %}
{% if constructor.params|length == 1 %}explicit {% endif %}{{struct.name}}(
{%- for field in constructor.params %}
{%- set type = field.kind|cpp_wrapper_param_type_new %}
{%- set name = field.name %}
{{type}} {{name}}
{%- if not loop.last -%},{%- endif %}
{%- endfor %});
{% endfor %}
{%- if struct|contains_move_only_members %}
{{struct.name}}(const {{struct.name}}&) = delete;
{{struct.name}}& operator=(const {{struct.name}}&) = delete;
{%- endif %}
~{{struct.name}}();
// Clone() is a template so it is only instantiated if it is used. Thus, the
// bindings generator does not need to know whether Clone() or copy
// constructor/assignment are available for members.
template <typename StructPtrType = {{struct.name}}Ptr>
{{struct.name}}Ptr Clone() const;
// Equals() is a template so it is only instantiated if it is used. Thus, the
// bindings generator does not need to know whether Equals() or == operator
// are available for members.
template <typename T, {{struct.name}}::EnableIfSame<T>* = nullptr>
bool Equals(const T& other) const;
template <typename T, {{struct.name}}::EnableIfSame<T>* = nullptr>
bool operator==(const T& rhs) const { return Equals(rhs); }
template <typename T, {{struct.name}}::EnableIfSame<T>* = nullptr>
bool operator!=(const T& rhs) const { return !operator==(rhs); }
{%- if struct|is_hashable %}
size_t Hash(size_t seed) const;
{%- endif %}
{%- set serialization_result_type = "WTF::Vector<uint8_t>"
if for_blink else "std::vector<uint8_t>" %}
{%- if not struct|contains_handles_or_interfaces %}
template <typename UserType>
static {{serialization_result_type}} Serialize(UserType* input) {
return mojo::internal::SerializeImpl<
{{struct.name}}::DataView, {{serialization_result_type}}>(input);
}
{%- endif %}
template <typename UserType>
static mojo::Message SerializeAsMessage(UserType* input) {
return mojo::internal::SerializeAsMessageImpl<
{{struct.name}}::DataView>(input);
}
// The returned Message is serialized only if the message is moved
// cross-process or cross-language. Otherwise if the message is Deserialized
// as the same UserType |input| will just be moved to |output| in
// DeserializeFromMessage.
template <typename UserType>
static mojo::Message WrapAsMessage(UserType input) {
return mojo::Message(std::make_unique<
internal::{{struct.name}}_UnserializedMessageContext<
UserType, {{struct.name}}::DataView>>(0, 0, std::move(input)),
MOJO_CREATE_MESSAGE_FLAG_NONE);
}
template <typename UserType>
static bool Deserialize(const void* data,
size_t data_num_bytes,
UserType* output) {
mojo::Message message;
return mojo::internal::DeserializeImpl<{{struct.name}}::DataView>(
message, data, data_num_bytes, output, Validate);
}
template <typename UserType>
static bool Deserialize(base::span<const uint8_t> input,
UserType* output) {
return {{struct.name}}::Deserialize(
input.empty() ? nullptr : input.data(), input.size(), output);
}
template <typename UserType>
static bool DeserializeFromMessage(mojo::Message input,
UserType* output) {
auto context = input.TakeUnserializedContext<
internal::{{struct.name}}_UnserializedMessageContext<
UserType, {{struct.name}}::DataView>>();
if (context) {
*output = std::move(context->TakeData());
return true;
}
input.SerializeIfNecessary();
return mojo::internal::DeserializeImpl<{{struct.name}}::DataView>(
input, input.payload(), input.payload_num_bytes(), output, Validate);
}
{#--- Struct members #}
{% for field in struct.fields %}
{%- set type = field.kind|cpp_wrapper_type %}
{%- set name = field.name %}
{{ kythe_annotation("%s.%s"|format(struct_prefix, name)) }}
{{type}} {{name}};
{%- endfor %}
// Serialise this struct into a trace.
void WriteIntoTrace(perfetto::TracedValue traced_context) const;
private:
static bool Validate(const void* data,
mojo::internal::ValidationContext* validation_context);
};
// The comparison operators are templates, so they are only instantiated if they
// are used. Thus, the bindings generator does not need to know whether
// comparison operators are available for members.
template <typename T, {{struct.name}}::EnableIfSame<T>* = nullptr>
bool operator<(const T& lhs, const T& rhs);
template <typename T, {{struct.name}}::EnableIfSame<T>* = nullptr>
bool operator<=(const T& lhs, const T& rhs) {
return !(rhs < lhs);
}
template <typename T, {{struct.name}}::EnableIfSame<T>* = nullptr>
bool operator>(const T& lhs, const T& rhs) {
return rhs < lhs;
}
template <typename T, {{struct.name}}::EnableIfSame<T>* = nullptr>
bool operator>=(const T& lhs, const T& rhs) {
return !(lhs < rhs);
}