blob: d26f440ab893202f292b56d64a123a9877c88771 [file] [log] [blame]
{{/*
// 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.
*/}}
{{- define "Union:ForwardDeclaration:WireTypesHeader" }}
{{ EnsureNamespace . }}
class {{ .Name }};
{{- end }}
{{- define "Union:WireTypesHeader" }}
{{ EnsureNamespace . }}
{{ if .IsResourceType }}
{{- IfdefFuchsia -}}
{{- end }}
{{ .Docs }}
class {{ .Name }} {
public:
{{- range .AnonymousChildren }}
using {{ .ScopedName }} = {{ .FlattenedName }};
{{- end }}
{{ .Name }}() : ordinal_({{ .WireInvalidOrdinal }}), envelope_{} {}
{{ if .IsResourceType }}
~{{ .Name }}();
{{ .Name }}({{ .Name }}&& other) {
_Move(std::move(other));
}
{{ .Name }}& operator=({{ .Name }}&& other) {
if (this != &other) {
_Move(std::move(other));
}
return *this;
}
{{- else -}}
{{ .Name }}(const {{ .Name }}&) = default;
{{ .Name }}& operator=(const {{ .Name }}&) = default;
{{ .Name }}({{ .Name }}&&) = default;
{{ .Name }}& operator=({{ .Name }}&&) = default;
{{- end }}
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 }}
};
{{- if .IsFlexible }}
constexpr bool IsUnknown() const {
return Which() == {{ .TagUnknown }};
}
{{- end }}
bool has_invalid_tag() const { return ordinal_ == {{ .WireInvalidOrdinal }}; }
{{- range $index, $member := .Members }}
bool is_{{ .Name }}() const { return ordinal_ == {{ .WireOrdinalName }}; }
{{- if .Type.InlineInEnvelope }}
{{ .Docs }}
static {{ $.Name }} With{{ .UpperCamelCaseName }}({{ .Type }} val) {
{{ $.Name }} result;
result.ordinal_ = {{ .WireOrdinalName }};
result.envelope_.As<{{ .Type }}>().set_data(std::move(val));
return result;
}
{{- else }}
{{ .Docs }}
static {{ $.Name }} With{{ .UpperCamelCaseName }}(::fidl::ObjectView<{{ .Type }}> val) {
{{ $.Name }} result;
result.ordinal_ = {{ .WireOrdinalName }};
result.envelope_.As<{{ .Type }}>().set_data(std::move(val));
return result;
}
{{ .Docs }}
template <typename... Args>
static {{ $.Name }} With{{ .UpperCamelCaseName }}(::fidl::AnyArena& allocator, Args&&... args) {
return With{{ .UpperCamelCaseName }}(::fidl::ObjectView<{{ .Type }}>(allocator,
std::forward<Args>(args)...));
}
{{- end }}
{{ "" }}
{{- .Docs }}
{{ .Type }}& {{ .Name }}() {
ZX_ASSERT(ordinal_ == {{ .WireOrdinalName }});
return envelope_.As<{{ .Type }}>().get_data();
}
{{- .Docs }}
const {{ .Type }}& {{ .Name }}() const {
ZX_ASSERT(ordinal_ == {{ .WireOrdinalName }});
return envelope_.As<{{ .Type }}>().get_data();
}
{{- end }}
{{- if .IsFlexible }}
{{ .TagEnum }} Which() const;
{{- else }}
{{ .TagEnum }} Which() const {
ZX_ASSERT(!has_invalid_tag());
return static_cast<{{ .TagEnum }}>(ordinal_);
}
{{- end }}
{{- 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 }}
};
{{- if .IsResourceType }}
void _Move({{ .Name }}&& other);
{{- end }}
static void SizeAndOffsetAssertionHelper();
{{- /* All fields are private to maintain standard layout */}}
{{ .WireOrdinalEnum }} ordinal_;
FIDL_ALIGNDECL
::fidl::UntypedEnvelope envelope_;
};
{{- if .IsResourceType }}
{{- EndifFuchsia -}}
{{- end }}
{{- end }}
{{- define "Union:WireTypesSource" }}
{{- if .IsResourceType }}
{{- IfdefFuchsia -}}
{{- end }}
{{- if .IsFlexible }}
auto {{ . }}::Which() const -> {{ .TagEnum }} {
ZX_ASSERT(!has_invalid_tag());
{{- if .Members }}
switch (ordinal_) {
{{- range .Members }}
case {{ .WireOrdinalName }}:
{{- end }}
return static_cast<{{ .TagEnum }}>(ordinal_);
default:
return {{ .TagUnknown }};
}
{{- else }}
return {{ .TagUnknown }};
{{- end }}
}
{{- end }}
void {{ . }}::SizeAndOffsetAssertionHelper() {
static_assert(sizeof({{ .Name }}) == sizeof(fidl_union_t));
static_assert(offsetof({{ .Name }}, ordinal_) == offsetof(fidl_union_t, tag));
static_assert(offsetof({{ .Name }}, envelope_) == offsetof(fidl_union_t, envelope));
}
{{- if .IsResourceType }}
{{ . }}::~{{ .Name }}() {
switch (ordinal_) {
{{- range .Members }}
case {{ .WireOrdinalName }}:
envelope_.As<{{ .Type }}>().clear_data();
break;
{{- end }}
default:
break;
}
}
void {{ . }}::_Move({{ .Name }}&& other) {
ordinal_ = other.ordinal_;
switch (ordinal_) {
{{- range .Members }}
case {{ .WireOrdinalName }}:
envelope_.As<{{ .Type }}>() = std::move(other.envelope_.As<{{ .Type }}>());
break;
{{- end }}
default:
break;
}
}
void {{ . }}::_CloseHandles() {
switch (ordinal_) {
{{- range .Members }}
{{- if .Type.IsResource }}
case {{ .WireOrdinalName }}: {
{{- CloseHandles . true }}
break;
}
{{- end }}
{{- end }}
default:
break;
}
}
{{- end }}
{{- if .IsResourceType }}
{{- EndifFuchsia -}}
{{- end }}
{{- end }}
{{- define "Union:Traits:WireTypesHeader" }}
{{ if .IsResourceType }}
{{- IfdefFuchsia -}}
template <>
struct IsResource<{{ . }}> : public std::true_type {};
{{- end }}
template <>
struct TypeTraits<{{ . }}> {
static constexpr uint32_t kMaxNumHandles = {{ .TypeShapeV2.MaxHandles }};
static constexpr uint32_t kMaxDepth = {{ .TypeShapeV2.Depth }};
static constexpr uint32_t kPrimarySize = {{ .TypeShapeV2.InlineSize }};
[[maybe_unused]]
static constexpr uint32_t kMaxOutOfLine = {{ .TypeShapeV2.MaxOutOfLine }};
static constexpr bool kHasFlexibleEnvelope = {{ .TypeShapeV2.HasFlexibleEnvelope }};
static constexpr bool kHasPointer = {{ .TypeShapeV2.HasPointer }};
};
template <>
struct IsFidlType<{{ . }}> : public std::true_type {};
template <>
struct IsWire<{{ . }}> : public std::true_type {};
template <>
struct IsUnion<{{ . }}> : public std::true_type {};
static_assert(std::is_standard_layout_v<{{ . }}>);
template <typename Constraint, bool IsRecursive>
struct ::fidl::internal::WireCodingTraits<{{ . }}, Constraint, IsRecursive> {
static constexpr size_t inline_size = {{ .TypeShapeV2.InlineSize }};
static constexpr bool is_memcpy_compatible = false;
static void Encode(internal::WireEncoder* encoder, {{ . }}* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
if (unlikely(u->tag == 0)) {
if constexpr (Constraint::is_optional) {
*position.As<fidl_union_t>() = {};
return;
}
encoder->SetError(kCodingErrorInvalidUnionTag);
return;
}
RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 1);
if (!inner_depth.IsValid()) {
return;
}
*position.As<fidl_xunion_tag_t>() = u->tag;
{{/* Two switches here, so they are translated to lookup tables. */}}
size_t encode_inline_size;
switch (u->tag) {
{{- range .Members }}
case {{ .Ordinal }}: // {{ .TagName }}
encode_inline_size = ::fidl::internal::WireCodingTraits<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>::inline_size;
break;
{{- end }}
default:
encode_inline_size = 0;
break;
}
::fidl::internal::EncodeFn<IsRecursive> encode_fn;
switch (u->tag) {
{{- range .Members }}
case {{ .Ordinal }}: // {{ .TagName }}
encode_fn = ::fidl::internal::MakeEncodeFn<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>();
break;
{{- end }}
default:
encode_fn = nullptr;
break;
}
WireEncodeEnvelope(encode_inline_size, encode_fn, encoder, &u->envelope, position + sizeof(fidl_xunion_tag_t), inner_depth);
}
static void Decode(internal::WireDecoder* decoder, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
{{ .TagEnum }} tag = *position.As<{{ .TagEnum }}>();
if (unlikely(static_cast<uint64_t>(tag) == 0)) {
if constexpr (!Constraint::is_optional) {
decoder->SetError(kCodingErrorInvalidUnionTag);
return;
}
static_assert(sizeof(fidl_envelope_t) == sizeof(uint64_t));
if (*(position + sizeof(fidl_xunion_tag_t)).As<uint64_t>() != 0) {
decoder->SetError(kCodingErrorZeroTagButNonZeroEnvelope);
}
return;
}
RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(decoder, 1);
if (!inner_depth.IsValid()) {
return;
}
{{/* Two switches here, so they are translated to lookup tables. */}}
size_t decode_inline_size;
switch (tag) {
{{- range .Members }}
case {{ .TagName }}:
decode_inline_size = ::fidl::internal::WireCodingTraits<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>::inline_size;
break;
{{- end }}
default:
decode_inline_size = 0;
break;
}
DecodeFn<IsRecursive> decode_fn;
switch(tag) {
{{- range .Members }}
case {{ .TagName }}:
decode_fn = ::fidl::internal::MakeDecodeFn<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>();
break;
{{- end }}
default:
decode_fn = nullptr;
break;
}
{{- if .IsFlexible }}
::fidl::internal::WireDecodeFlexibleEnvelope(decode_inline_size, decode_fn, decoder, position + sizeof(fidl_xunion_tag_t), inner_depth);
{{- else }}
::fidl::internal::WireDecodeStrictEnvelope(decode_inline_size, decode_fn, decoder, position + sizeof(fidl_xunion_tag_t), inner_depth);
{{- end }}
}
};
// Top-level union.
template <bool IsRecursive>
struct ::fidl::internal::WireCodingTraits<{{ . }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
: public ::fidl::internal::WireCodingTraits<{{ . }}, ::fidl::internal::WireCodingConstraintUnion<false>, IsRecursive> {};
{{- if .IsResourceType }}
{{- EndifFuchsia -}}
{{- end }}
{{- end }}