blob: b947ab0310189c71e9742dd95f911ad80dfd096b [file] [log] [blame]
{{/*
// Copyright 2018 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 "Table:ForwardDeclaration:WireTypesHeader" }}
{{ EnsureNamespace . }}
class {{ .Name }};
{{- end }}
{{- define "Table:WireTypesHeader" }}
{{ if .IsResourceType }}
{{- IfdefFuchsia -}}
{{- end }}
{{ EnsureNamespace "" }}
template<>
class {{ .WireTableBuilder }};
template<>
class {{ .WireTableExternalBuilder }};
template <>
struct {{ .WireTableFrame }} final {
public:
{{ .WireTableFrame.Self }}() = default;
// In its intended usage, WireTableFrame will be referenced by an ObjectView.
// If the ObjectView is assigned before a move or copy, then it will reference
// the old invalid object. Because this is unsafe, copies are disallowed and
// moves are only allowed by friend classes that operate safely.
{{ .WireTableFrame.Self }}(const {{ .WireTableFrame.Self }}&) = delete;
{{ .WireTableFrame.Self }}& operator=(const {{ .WireTableFrame.Self }}&) = delete;
private:
{{ .WireTableFrame.Self }}({{ .WireTableFrame.Self }}&&) noexcept = default;
{{ .WireTableFrame.Self }}& operator=({{ .WireTableFrame.Self }}&&) noexcept = default;
bool HasUnknownData() const;
uint64_t ComputeMaxOrdinal() const;
{{- range $index, $item := .FrameItems }}
{{- if $item }}
::fidl::Envelope<{{ $item.Type }}> {{ $item.Name }}_;
{{- else }}
[[maybe_unused]] ::fidl::UntypedEnvelope reserved_{{ $index }}_;
{{- end }}
{{- end }}
friend class {{ . }};
friend ::fidl::internal::WireTableBaseBuilder<{{ . }}, {{ .WireTableBuilder }}>;
friend ::fidl::internal::WireTableBaseBuilder<{{ . }}, {{ .WireTableExternalBuilder }}>;
};
{{ EnsureNamespace . }}
{{ .Docs }}
class {{ .Name }} {
public:
{{- range .AnonymousChildren }}
using {{ .ScopedName }} = {{ .FlattenedName }};
{{- end }}
{{ .Name }}() = default;
{{ .Name }}(const {{ .Name }}& other) noexcept = default;
{{ .Name }}& operator=(const {{ .Name }}& other) noexcept = default;
{{ .Name }}({{ .Name }}&& other) noexcept = default;
{{ .Name }}& operator=({{ .Name }}&& other) noexcept = default;
~{{ .Name }}() = default;
// Returns whether no field is set.
bool IsEmpty() const { return max_ordinal_ == 0; }
// Returns whether the table references unknown fields.
bool HasUnknownData() const;
{{- if .IsResourceType }}
void _CloseHandles();
{{- end }}
// Return a builder that by defaults allocates of an arena.
static {{ .WireTableBuilder }} Builder(::fidl::AnyArena& arena);
// Return a builder that relies on explicitly allocating |fidl::ObjectView|s.
static {{ .WireTableExternalBuilder }} ExternalBuilder(::fidl::ObjectView<{{ .WireTableFrame }}> frame);
{{- range .Members }}
{{ "" }}
{{- .Docs }}
[[ nodiscard ]] {{ .Type }}& {{ .Name }}() const {
ZX_ASSERT({{ .MethodHasName }}());
return frame_ptr_->{{ .Name }}_.get_data();
}
[[ nodiscard ]] bool {{ .MethodHasName }}() const {
return max_ordinal_ >= {{ .Ordinal }} && frame_ptr_->{{ .Name }}_.has_data();
}
{{- end }}
{{- /* Temporarily special case fuchsia.hardware.goldfish because of out of tree users. */}}
#if defined(FIDL_WIRE_ALLOW_DEPRECATED_MUTABLE_TABLES) || {{ eq .Namespace.String "::fuchsia_hardware_goldfish::wire" }}
public:
#else // !defined(FIDL_WIRE_ALLOW_DEPRECATED_MUTABLE_TABLES)
private:
#endif // FIDL_WIRE_ALLOW_DEPRECATED_MUTABLE_TABLES
{{ range .Members }}
{{- if .Type.InlineInEnvelope }}
{{ $.Name }}& set_{{ .Name }}({{ .Type }} elem) {
ZX_DEBUG_ASSERT(frame_ptr_ != nullptr);
frame_ptr_->{{ .Name }}_.set_data(std::move(elem));
max_ordinal_ = std::max(max_ordinal_, static_cast<uint64_t>({{ .Ordinal }}));
return *this;
}
{{- else }}
{{- /* TODO(https://fxbug.dev/42160282): The elem pointer should be const if it has no handles. */}}
{{ $.Name }}& set_{{ .Name }}(::fidl::ObjectView<{{ .Type }}> elem) {
ZX_DEBUG_ASSERT(frame_ptr_ != nullptr);
frame_ptr_->{{ .Name }}_.set_data(elem);
max_ordinal_ = std::max(max_ordinal_, static_cast<uint64_t>({{ .Ordinal }}));
return *this;
}
{{ $.Name }}& set_{{ .Name }}(std::nullptr_t) {
ZX_DEBUG_ASSERT(frame_ptr_ != nullptr);
frame_ptr_->{{ .Name }}_.set_data(nullptr);
return *this;
}
template <typename... Args>
{{ $.Name }}& set_{{ .Name }}(::fidl::AnyArena& allocator, Args&&... args) {
ZX_DEBUG_ASSERT(frame_ptr_ != nullptr);
frame_ptr_->{{ .Name }}_.set_data(
::fidl::ObjectView<{{ .Type }}>(allocator, std::forward<Args>(args)...));
max_ordinal_ = std::max(max_ordinal_, static_cast<uint64_t>({{ .Ordinal }}));
return *this;
}
{{- end }}
{{ $.Name }}& {{ .MethodClearName }}() {
ZX_DEBUG_ASSERT(frame_ptr_ != nullptr);
frame_ptr_->{{ .Name }}_.clear_data();
max_ordinal_ = frame_ptr_->ComputeMaxOrdinal();
return *this;
}
{{- end }}
explicit {{ .Name }}(::fidl::AnyArena& allocator)
: frame_ptr_(::fidl::ObjectView<{{ .WireTableFrame }}>(allocator)) {}
// This constructor allows a user controlled allocation (not using a Arena).
// It should only be used when performance is key.
// As soon as the frame is given to the table, it must not be used directly or for another table.
explicit {{ .Name }}(::fidl::ObjectView<{{ .WireTableFrame }}>&& frame)
: frame_ptr_(std::move(frame)) {}
void Allocate(::fidl::AnyArena& allocator) {
max_ordinal_ = 0;
frame_ptr_ = ::fidl::ObjectView<{{ .WireTableFrame }}>(allocator);
}
void Init(::fidl::ObjectView<{{ .WireTableFrame }}>&& frame_ptr) {
max_ordinal_ = 0;
frame_ptr_ = std::move(frame_ptr);
}
private:
friend ::fidl::internal::WireTableBaseBuilder<{{ . }}, {{ .WireTableBuilder }}>;
friend ::fidl::internal::WireTableBaseBuilder<{{ . }}, {{ .WireTableExternalBuilder }}>;
uint64_t max_ordinal_ = 0;
::fidl::ObjectView<{{ .WireTableFrame }}> frame_ptr_;
};
{{- EnsureNamespace "" }}
template<typename BuilderImpl>
class ::fidl::internal::WireTableBaseBuilder<{{ . }}, BuilderImpl> {
protected:
// |Wrapper_Ignore_Me_| wraps a |fidl::ObjectView<T>| and reduces its
// priority in overload resolution. When the user writes `{}` as the
// setter argument, that would default construct the field instead of
// constructing a NULL object view.
template <typename U>
struct Wrapper_Ignore_Me_ {
Wrapper_Ignore_Me_(U v) : value(v) {}
U value;
};
public:
// Build and return the table. The builder should not be used after this.
{{ . }} Build() {
ZX_DEBUG_ASSERT(table_.frame_ptr_ != nullptr);
{{ . }} t = std::move(table_);
// Poison this builder to prevent accidental reuse.
table_.frame_ptr_ = nullptr;
return t;
}
{{- range .Members }}
[[ nodiscard ]] bool {{ .MethodHasName }}() const {
return table_.{{ .MethodHasName }}();
}
// Clears the {{ .Name }} field.
//
// This method should be used sparingly, such as only during tests, as it has
// O(number_of_fields) complexity.
void {{ .MethodClearName }}() {
table_.{{ .MethodClearName }}();
}
// Getter for {{ .Name }}.
//
{{ .Docs }}
[[ nodiscard ]] {{ .Type }}& {{ .Name }}() const {
return table_.{{ .Name }}();
}
// Setter for {{ .Name }}.
//
{{ .Docs }}
{{- if .Type.InlineInEnvelope }}
BuilderImpl& {{ .Name }}({{ .Type }} elem) {
ZX_DEBUG_ASSERT(table_.frame_ptr_ != nullptr);
table_.frame_ptr_->{{ .Name }}_.set_data(std::move(elem));
table_.max_ordinal_ = std::max(table_.max_ordinal_, static_cast<uint64_t>({{ .Ordinal }}));
return *static_cast<BuilderImpl*>(this);
}
{{- else }}
{{- /* TODO(https://fxbug.dev/42160282): The elem pointer should be const if it has no handles. */}}
BuilderImpl& {{ .Name }}(Wrapper_Ignore_Me_<::fidl::ObjectView<{{ .Type }}>> elem) {
ZX_DEBUG_ASSERT(table_.frame_ptr_ != nullptr);
ZX_DEBUG_ASSERT(elem.value.get() != nullptr);
table_.frame_ptr_->{{ .Name }}_.set_data(elem.value);
table_.max_ordinal_ = std::max(table_.max_ordinal_, static_cast<uint64_t>({{ .Ordinal }}));
return *static_cast<BuilderImpl*>(this);
}
{{- end }}
{{- end }}
protected:
WireTableBaseBuilder(::fidl::ObjectView<{{ .WireTableFrame }}>&& frame)
: table_(std::move(frame)) {}
private:
{{ . }} table_;
};
template<>
class {{ .WireTableBuilder }} final : public ::fidl::internal::WireTableBaseBuilder<{{ . }}, {{ .WireTableBuilder }}> {
using Base = ::fidl::internal::WireTableBaseBuilder<{{ . }}, {{ .WireTableBuilder }}>;
public:
{{- range .Members }}
{{- if not .Type.InlineInEnvelope }}
using Base::{{ .Name }};
{{ .Docs }}
template <
typename First = {{ .Type }},
typename... Args,
std::enable_if_t<!std::is_same_v<cpp20::remove_cvref_t<First>, fidl::ObjectView<{{ .Type }}>>, int> = 0
>
{{ $.WireTableBuilder }}& {{ .Name }}(First&& first, Args&&... args_) {
fidl::ObjectView<{{ .Type }}> view_(arena_.get(), std::forward<First>(first), std::forward<Args>(args_)...);
{{ .Name }}(Base::Wrapper_Ignore_Me_<fidl::ObjectView<{{ .Type }}>>(view_));
return *this;
}
{{- end }}
{{- end }}
private:
friend class {{ . }};
{{ .WireTableBuilder.Self }}(::fidl::AnyArena& arena)
: Base(::fidl::ObjectView<{{ .WireTableFrame }}>(arena)),
arena_(arena) {}
[[maybe_unused]] std::reference_wrapper<::fidl::AnyArena> arena_;
};
template<>
class {{ .WireTableExternalBuilder }} final : public ::fidl::internal::WireTableBaseBuilder<{{ . }}, {{ .WireTableExternalBuilder }}> {
using Base = ::fidl::internal::WireTableBaseBuilder<{{ . }}, {{ .WireTableExternalBuilder }}>;
private:
friend class {{ . }};
using Base::Base;
{{ .WireTableExternalBuilder.Self }}({{ .WireTableFrame }}* frame)
: Base(::fidl::ObjectView<{{ .WireTableFrame }}>::FromExternal(frame)) {}
};
{{- EnsureNamespace . }}
inline {{ .WireTableBuilder }} {{ .Name }}::Builder(::fidl::AnyArena& arena) {
return {{ .WireTableBuilder }}(arena);
}
inline {{ .WireTableExternalBuilder }} {{ .Name }}::ExternalBuilder(::fidl::ObjectView<{{ .WireTableFrame }}> frame) {
return {{ .WireTableExternalBuilder }}(std::move(frame));
}
{{- if .IsResourceType }}
{{- EndifFuchsia -}}
{{ end }}
{{- end }}
{{- define "Table:WireTypesSource" }}
{{ if .IsResourceType }}
{{- IfdefFuchsia -}}
{{- end }}
{{ EnsureNamespace "" }}
bool {{ .WireTableFrame }}::HasUnknownData() const {
{{- range $index, $item := .FrameItems }}
{{- if not $item }}
if (!reserved_{{ $index }}_.IsZeroEnvelope()) {
return true;
}
{{- end }}
{{- end }}
return false;
}
uint64_t {{ .WireTableFrame.NoLeading }}::ComputeMaxOrdinal() const {
uint64_t max_ordinal = 0;
{{- range $index, $item := .FrameItems }}
{{- if not $item }}
if (!reserved_{{ $index }}_.IsZeroEnvelope()) {
max_ordinal = {{ $index }};
}
{{- else }}
if (!{{ $item }}_.has_data()) {
max_ordinal = {{ $item.Ordinal }};
}
{{- end }}
{{- end }}
return max_ordinal;
}
bool {{ . }}::HasUnknownData() const {
if (max_ordinal_ > {{ .BiggestOrdinal }}) {
return true;
}
if (frame_ptr_ == nullptr) {
return false;
}
return frame_ptr_->HasUnknownData();
}
{{ if .IsResourceType }}
void {{ . }}::_CloseHandles() {
{{- range .Members }}
{{- if .Type.IsResource }}
if (has_{{ .Name }}()) {
{{- CloseHandles . true }}
}
{{- end }}
{{- end }}
}
{{- end }}
{{ if .IsResourceType }}
{{- EndifFuchsia -}}
{{- end }}
{{- end }}
{{- define "Table: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 IsTable<{{ . }}> : public std::true_type {};
static_assert(std::is_standard_layout_v<{{ . }}>);
template <bool IsRecursive>
struct ::fidl::internal::WireCodingTraits<{{ . }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
: ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
using Base = ::fidl::internal::WireTableCodingTraitsBase<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) {
RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
if (!inner_depth.IsValid()) {
return;
}
::fidl::internal::WirePosition vector_position;
if (Base::PreworkResult::kEarlyExit ==
Base::PrepareForBodyEncode(encoder, value, position, &vector_position)) {
return;
}
fidl_vector_t* vec = reinterpret_cast<fidl_vector_t*>(value);
fidl_envelope_t* envelopes = static_cast<fidl_envelope_t*>(vec->data);
for (size_t i = 0; i < vec->count; i++) {
{{/* Two switches here, so they are translated to lookup tables. */}}
size_t encode_inline_size = 0;
switch (i) {
{{- range .Members }}
case {{ Sub .Ordinal 1 }}:
encode_inline_size = ::fidl::internal::WireCodingTraits<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>::inline_size;
break;
{{- end }}
}
::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
switch (i) {
{{- range .Members }}
case {{ Sub .Ordinal 1 }}:
encode_fn = ::fidl::internal::MakeEncodeFn<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>();
break;
{{- end }}
}
WirePosition envelope_position = vector_position + i * sizeof(fidl_envelope_t);
WireEncodeEnvelope(encode_inline_size, encode_fn, encoder, &envelopes[i], envelope_position, inner_depth);
}
}
static void Decode(internal::WireDecoder* decoder, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(decoder, 2);
if (!inner_depth.IsValid()) {
return;
}
::fidl::internal::WirePosition vector_position;
if (Base::PreworkResult::kEarlyExit == Base::DecodePrework(decoder, position, &vector_position)) {
return;
}
fidl_vector_t* vec = position.As<fidl_vector_t>();
for (size_t i = 0; i < vec->count; i++) {
{{/* Two switches here, so they are translated to lookup tables. */}}
size_t decode_inline_size = 0;
switch (i) {
{{- range .Members }}
case {{ Sub .Ordinal 1 }}:
decode_inline_size = ::fidl::internal::WireCodingTraits<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>::inline_size;
break;
{{- end }}
}
DecodeFn<IsRecursive> decode_fn = nullptr;
switch(i) {
{{- range .Members }}
case {{ Sub .Ordinal 1 }}:
decode_fn = ::fidl::internal::MakeDecodeFn<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>();
break;
{{- end }}
}
::fidl::internal::WireDecodeOptionalEnvelope(decode_inline_size, decode_fn, decoder, vector_position + i * sizeof(fidl_envelope_t), inner_depth);
}
}
};
{{- if .IsResourceType }}
{{- EndifFuchsia -}}
{{- end }}
{{- end }}