// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package codegen

const fragmentUnionTmpl = `
{{- define "UnionForwardDeclaration" }}
{{ EnsureNamespace . }}
class {{ .Name }};
{{- end }}

{{/* TODO(fxbug.dev/36441): Remove __Fuchsia__ ifdefs once we have non-Fuchsia
     emulated handles for C++. */}}
{{- define "UnionDeclaration" }}
{{ EnsureNamespace . }}
{{ if .IsResourceType }}
{{- IfdefFuchsia -}}
{{- end }}
extern "C" const fidl_type_t {{ .CodingTableType }};
{{ .Docs }}
class {{ .Name }} {
  public:
  {{ .Name }}() : ordinal_({{ .WireInvalidOrdinal }}), envelope_{} {}

  {{ .Name }}(const {{ .Name }}&) = default;
  {{ .Name }}& operator=(const {{ .Name }}&) = default;
  {{ .Name }}({{ .Name }}&&) = default;
  {{ .Name }}& operator=({{ .Name }}&&) = default;

  enum class {{ .TagEnum.Self }} : fidl_xunion_tag_t {
  {{- range .Members }}
    {{ .TagName.Self }} = {{ .Ordinal }},  // {{ .Ordinal | printf "%#x" }}
  {{- end }}
  {{- if .IsFlexible }}
    {{ .TagUnknown.Self }} = ::std::numeric_limits<::fidl_union_tag_t>::max(),
  {{- end }}
  };

  bool has_invalid_tag() const { return ordinal_ == {{ .WireInvalidOrdinal }}; }

  {{- range $index, $member := .Members }}

  bool is_{{ .Name }}() const { return ordinal_ == {{ .WireOrdinalName }}; }

  static {{ $.Name }} With{{ .UpperCamelCaseName }}(::fidl::ObjectView<{{ .Type }}> val) {
    {{ $.Name }} result;
    result.set_{{ .Name }}(val);
    return result;
  }

  template <typename... Args>
  static {{ $.Name }} With{{ .UpperCamelCaseName }}(::fidl::AnyAllocator& allocator, Args&&... args) {
    {{ $.Name }} result;
    result.set_{{ .Name }}(::fidl::ObjectView<{{ .Type }}>(allocator,
                           std::forward<Args>(args)...));
    return result;
  }
{{ "" }}
  {{- .Docs }}
  void set_{{ .Name }}(::fidl::ObjectView<{{ .Type }}> elem) {
    ordinal_ = {{ .WireOrdinalName }};
    envelope_.data = ::fidl::ObjectView<void>::FromExternal(static_cast<void*>(elem.get()));
  }

  template <typename... Args>
  void set_{{ .Name }}(::fidl::AnyAllocator& allocator, Args&&... args) {
    ordinal_ = {{ .WireOrdinalName }};
    set_{{ .Name }}(::fidl::ObjectView<{{ .Type }}>(allocator, std::forward<Args>(args)...));
  }
{{ "" }}
  {{- .Docs }}
  {{ .Type }}& mutable_{{ .Name }}() {
    ZX_ASSERT(ordinal_ == {{ .WireOrdinalName }});
    return *static_cast<{{ .Type }}*>(envelope_.data.get());
  }
  const {{ .Type }}& {{ .Name }}() const {
    ZX_ASSERT(ordinal_ == {{ .WireOrdinalName }});
    return *static_cast<{{ .Type }}*>(envelope_.data.get());
  }
  {{- end }}

  {{- if .IsFlexible }}
  {{ .TagEnum }} which() const;
  {{- else }}
  {{ .TagEnum }} which() const {
    ZX_ASSERT(!has_invalid_tag());
    return static_cast<{{ .TagEnum }}>(ordinal_);
  }
  {{- end }}

  static constexpr const fidl_type_t* Type = &{{ .CodingTableType }};
  static constexpr uint32_t MaxNumHandles = {{ .MaxHandles }};
  static constexpr uint32_t PrimarySize = {{ .InlineSize }};
  [[maybe_unused]]
  static constexpr uint32_t MaxOutOfLine = {{ .MaxOutOfLine }};
  static constexpr bool HasPointer = {{ .HasPointer }};

  {{- if .IsResourceType }}

  void _CloseHandles();
  {{- end }}

 private:
  enum class {{ .WireOrdinalEnum.Self }} : fidl_xunion_tag_t {
    {{ .WireInvalidOrdinal.Self }} = 0,
  {{- range .Members }}
    {{ .WireOrdinalName.Self }} = {{ .Ordinal }},  // {{ .Ordinal | printf "%#x" }}
  {{- end }}
  };

  static void SizeAndOffsetAssertionHelper();

  {{- /* All fields are private to maintain standard layout */}}
  {{ .WireOrdinalEnum }} ordinal_;
  FIDL_ALIGNDECL
  ::fidl::Envelope<void> envelope_;
};

{{- if .IsResourceType }}
{{- EndifFuchsia -}}
{{- end }}
{{- end }}

{{/* TODO(fxbug.dev/36441): Remove __Fuchsia__ ifdefs once we have non-Fuchsia
     emulated handles for C++. */}}
{{- define "UnionDefinition" }}
{{- if .IsResourceType }}
{{- IfdefFuchsia -}}
{{- end }}
{{- if .IsFlexible }}
auto {{ . }}::which() const -> {{ .TagEnum }} {
  ZX_ASSERT(!has_invalid_tag());
  switch (ordinal_) {
  {{- range .Members }}
  case {{ .WireOrdinalName }}:
  {{- end }}
    return static_cast<{{ .TagEnum }}>(ordinal_);
  default:
    return {{ .TagUnknown }};
  }
}
{{- end }}

void {{ . }}::SizeAndOffsetAssertionHelper() {
  static_assert(sizeof({{ .Name }}) == sizeof(fidl_xunion_t));
  static_assert(offsetof({{ .Name }}, ordinal_) == offsetof(fidl_xunion_t, tag));
  static_assert(offsetof({{ .Name }}, envelope_) == offsetof(fidl_xunion_t, envelope));
}

{{- if .IsResourceType }}
void {{ . }}::_CloseHandles() {
  switch (ordinal_) {
  {{- range .Members }}
    {{- if .Type.IsResource }}
      case {{ .WireOrdinalName }}: {
        {{- CloseHandles . false true }}
        break;
      }
    {{- end }}
  {{- end }}
  default:
    break;
  }
}
{{- end }}

{{- if .IsResourceType }}
{{- EndifFuchsia -}}
{{- end }}
{{- end }}

{{/* TODO(fxbug.dev/36441): Remove __Fuchsia__ ifdefs once we have non-Fuchsia
     emulated handles for C++. */}}
{{- define "UnionTraits" }}
{{ if .IsResourceType }}
{{- IfdefFuchsia -}}
{{- end }}
template <>
struct IsFidlType<{{ . }}> : public std::true_type {};
template <>
struct IsUnion<{{ . }}> : public std::true_type {};
static_assert(std::is_standard_layout_v<{{ . }}>);
{{- if .IsResourceType }}
{{- EndifFuchsia -}}
{{- end }}
{{- end }}
`
