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

{%- set union_prefix = "%s.%s"|format(module_prefix, union.name) %}

{{ kythe_annotation(union_prefix) }}
class {{export_attribute}} {{union.name}} {
 public:
  using DataView = {{union.name}}DataView;
  using Data_ = internal::{{union.name}}_Data;
  using Tag = Data_::{{union.name}}_Tag;

  template <typename... Args>
  static {{union.name}}Ptr New(Args&&... args) {
    static_assert(
        sizeof...(args) < 0,
        "Do not use Union::New(); to create a union of a given subtype, use "
        "New<SubType>(), not New() followed by set_<sub_type>(). To represent "
        "an empty union, mark the field or parameter as nullable in the mojom "
        "definition.");
    return nullptr;
  }

{%-  for field in union.fields %}
  // Construct an instance holding |{{field.name}}|.
  static {{union.name}}Ptr
  New{{field.name|under_to_camel}}(
      {{field.kind|cpp_wrapper_param_type_new}} value) {
    auto result = {{union.name}}Ptr(std::in_place);
    result->set_{{field.name}}(std::move(value));
    return result;
  }
{%- endfor %}

  template <typename U>
  static {{union.name}}Ptr From(const U& u) {
    return mojo::TypeConverter<{{union.name}}Ptr, U>::Convert(u);
  }

  template <typename U>
  U To() const {
    return mojo::TypeConverter<U, {{union.name}}>::Convert(*this);
  }

  {{union.name}}();
  ~{{union.name}}();

{%- if not union|should_inline_union %}
  // Delete the copy constructor and copy assignment operators because `data_`
  // contains raw pointers that must not be copied.
  {{union.name}}(const {{union.name}}& other) = delete;
  {{union.name}}& operator=(const {{union.name}}& other) = delete;
{%- endif %}

  // 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 UnionPtrType = {{union.name}}Ptr>
  {{union.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,
            typename std::enable_if<std::is_same<
                T, {{union.name}}>::value>::type* = nullptr>
  bool Equals(const T& other) const;

  template <typename T,
            typename std::enable_if<std::is_same<
                T, {{union.name}}>::value>::type* = nullptr>
  bool operator==(const T& rhs) const { return Equals(rhs); }

{%- if union|is_hashable %}
  size_t Hash(size_t seed) const;
{%- endif %}

  Tag which() const {
    return tag_;
  }

{%  for field in union.fields %}
  {{ kythe_annotation("%s.%s"|format(union_prefix, field.name)) }}
  bool is_{{field.name}}() const { return tag_ == Tag::k{{field.name|under_to_camel}}; }

  {{ kythe_annotation("%s.%s"|format(union_prefix, field.name)) }}
  {{field.kind|cpp_union_getter_return_type}} get_{{field.name}}() const {
    CHECK(tag_ == Tag::k{{field.name|under_to_camel}});
{%-   if field.kind|is_object_kind or
         field.kind|is_any_handle_or_interface_kind %}
    return *(data_.{{field.name}});
{%-   else %}
    return data_.{{field.name}};
{%-   endif %}
  }

  {{ kythe_annotation("%s.%s"|format(union_prefix, field.name)) }}
  void set_{{field.name}}(
      {{field.kind|cpp_wrapper_param_type_new}} {{field.name}});
{%- endfor %}

  template <typename UserType>
  static mojo::Message SerializeAsMessage(UserType* input) {
    return mojo::internal::SerializeAsMessageImpl<
        {{union.name}}::DataView>(input);
  }

  template <typename UserType>
  static bool DeserializeFromMessage(mojo::Message input,
                                     UserType* output) {
    return mojo::internal::DeserializeImpl<{{union.name}}::DataView>(
        input, input.payload(), input.payload_num_bytes(), output, Validate);
  }

 private:
  union Union_ {
    Union_() = default;
    ~Union_() = default;

{%- for field in union.fields %}
{%-   if field.kind|is_object_kind or
         field.kind|is_any_handle_or_interface_kind %}
    {{field.kind|cpp_wrapper_type}}* {{field.name}};
{%-   else %}
    {{field.kind|cpp_wrapper_type}} {{field.name}};
{%-   endif %}
{%- endfor %}
  };

  static bool Validate(const void* data,
                       mojo::internal::ValidationContext* validation_context);

  void DestroyActive();
  Tag tag_;
  Union_ data_;
};