blob: bb58677cfe5f3a2d72b23d6003a1c30117e6fd4a [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.
package codegen
const fragmentTableTmpl = `
{{- define "TableForwardDeclaration" }}
{{ EnsureNamespace . }}
class {{ .Name }};
{{- end }}
{{/* TODO(fxbug.dev/36441): Remove __Fuchsia__ ifdefs once we have non-Fuchsia
emulated handles for C++. */}}
{{- define "TableDeclaration" }}
{{ EnsureNamespace . }}
{{ if .IsResourceType }}
{{- IfdefFuchsia -}}
{{- end }}
extern "C" const fidl_type_t {{ .CodingTableType }};
{{ .Docs }}
class {{ .Name }} final {
public:
// Returns whether no field is set.
bool IsEmpty() const { return max_ordinal_ == 0; }
class Frame_;
{{- range .Members }}
{{ "" }}
{{- .Docs }}
const {{ .Type }}& {{ .Name }}() const {
ZX_ASSERT({{ .MethodHasName }}());
return *frame_ptr_->{{ .Name }}_.data;
}
{{ .Type }}& {{ .Name }}() {
ZX_ASSERT({{ .MethodHasName }}());
return *frame_ptr_->{{ .Name }}_.data;
}
bool {{ .MethodHasName }}() const {
return max_ordinal_ >= {{ .Ordinal }} && frame_ptr_->{{ .Name }}_.data != nullptr;
}
{{- /* TODO(fxbug.dev/7999): 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 }}_.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 }}_.data = nullptr;
return *this;
}
template <typename... Args>
{{ $.Name }}& set_{{ .Name }}(::fidl::AnyAllocator& allocator, Args&&... args) {
ZX_DEBUG_ASSERT(frame_ptr_ != nullptr);
frame_ptr_->{{ .Name }}_.data =
::fidl::ObjectView<{{ .Type }}>(allocator, std::forward<Args>(args)...);
max_ordinal_ = std::max(max_ordinal_, static_cast<uint64_t>({{ .Ordinal }}));
return *this;
}
{{- end }}
{{ .Name }}() = default;
explicit {{ .Name }}(::fidl::AnyAllocator& allocator)
: frame_ptr_(::fidl::ObjectView<Frame_>(allocator)) {}
// This constructor allows a user controlled allocation (not using a FidlAllocator).
// 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<Frame_>&& frame)
: frame_ptr_(std::move(frame)) {}
~{{ .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;
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 }};
void Allocate(::fidl::AnyAllocator& allocator) {
max_ordinal_ = 0;
frame_ptr_ = ::fidl::ObjectView<Frame_>(allocator);
}
void Init(::fidl::ObjectView<Frame_>&& frame_ptr) {
max_ordinal_ = 0;
frame_ptr_ = std::move(frame_ptr);
}
{{- if .IsResourceType }}
void _CloseHandles();
{{- end }}
class UnownedEncodedMessage final {
public:
UnownedEncodedMessage(uint8_t* backing_buffer, uint32_t backing_buffer_size, {{ .Name }}* value)
: message_(::fidl::OutgoingMessage::ConstructorArgs{
.iovecs = iovecs_,
.iovec_capacity = ::fidl::internal::IovecBufferSize,
{{- if gt .MaxHandles 0 }}
.handles = handles_,
.handle_capacity = std::min(ZX_CHANNEL_MAX_MSG_HANDLES, MaxNumHandles),
{{- end }}
.backing_buffer = backing_buffer,
.backing_buffer_capacity = backing_buffer_size,
}) {
if (backing_buffer_size < sizeof({{ .Name }})) {
::fidl::internal::OutgoingMessageResultSetter::SetResult(
message_, ZX_ERR_BUFFER_TOO_SMALL, nullptr);
return;
}
message_.Encode<{{ .Name }}>(value);
}
UnownedEncodedMessage(const UnownedEncodedMessage&) = delete;
UnownedEncodedMessage(UnownedEncodedMessage&&) = delete;
UnownedEncodedMessage* operator=(const UnownedEncodedMessage&) = delete;
UnownedEncodedMessage* operator=(UnownedEncodedMessage&&) = delete;
zx_status_t status() const { return message_.status(); }
{{- IfdefFuchsia -}}
const char* status_string() const { return message_.status_string(); }
{{- EndifFuchsia -}}
bool ok() const { return message_.status() == ZX_OK; }
const char* error() const { return message_.error(); }
::fidl::OutgoingMessage& GetOutgoingMessage() { return message_; }
private:
::fidl::internal::IovecBuffer iovecs_;
{{- if gt .MaxHandles 0 }}
zx_handle_disposition_t handles_[std::min(ZX_CHANNEL_MAX_MSG_HANDLES, MaxNumHandles)];
{{- end }}
::fidl::OutgoingMessage message_;
};
class OwnedEncodedMessage final {
public:
explicit OwnedEncodedMessage({{ .Name }}* value)
: message_(backing_buffer_.data(), backing_buffer_.size(), value) {}
OwnedEncodedMessage(const OwnedEncodedMessage&) = delete;
OwnedEncodedMessage(OwnedEncodedMessage&&) = delete;
OwnedEncodedMessage* operator=(const OwnedEncodedMessage&) = delete;
OwnedEncodedMessage* operator=(OwnedEncodedMessage&&) = delete;
zx_status_t status() const { return message_.status(); }
{{- IfdefFuchsia -}}
const char* status_string() const { return message_.status_string(); }
{{- EndifFuchsia -}}
bool ok() const { return message_.ok(); }
const char* error() const { return message_.error(); }
::fidl::OutgoingMessage& GetOutgoingMessage() { return message_.GetOutgoingMessage(); }
private:
{{ .BackingBufferType }} backing_buffer_;
UnownedEncodedMessage message_;
};
class DecodedMessage final : public ::fidl::internal::IncomingMessage {
public:
DecodedMessage(uint8_t* bytes, uint32_t byte_actual, zx_handle_info_t* handles = nullptr,
uint32_t handle_actual = 0)
: ::fidl::internal::IncomingMessage(bytes, byte_actual, handles, handle_actual) {
Decode<{{ .Name }}>();
}
DecodedMessage(fidl_incoming_msg_t* msg) : ::fidl::internal::IncomingMessage(msg) {
Decode<{{ .Name }}>();
}
DecodedMessage(const DecodedMessage&) = delete;
DecodedMessage(DecodedMessage&&) = delete;
DecodedMessage* operator=(const DecodedMessage&) = delete;
DecodedMessage* operator=(DecodedMessage&&) = delete;
{{- if .IsResourceType }}
~DecodedMessage() {
if (ok() && (PrimaryObject() != nullptr)) {
PrimaryObject()->_CloseHandles();
}
}
{{- end }}
{{ .Name }}* PrimaryObject() {
ZX_DEBUG_ASSERT(ok());
return reinterpret_cast<{{ .Name }}*>(bytes());
}
// Release the ownership of the decoded message. That means that the handles won't be closed
// When the object is destroyed.
// After calling this method, the DecodedMessage object should not be used anymore.
void ReleasePrimaryObject() { ResetBytes(); }
};
// Frame_s are managed automatically by the FidlAllocator class.
// The only direct usage is when performance is key and a frame needs to be allocated outside a
// FidlAllocator.
// Once created, a frame can only be used for one single table.
class Frame_ final {
public:
Frame_() = default;
// In its intended usage, Frame_ 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.
Frame_(const Frame_&) = delete;
Frame_& operator=(const Frame_&) = delete;
private:
Frame_(Frame_&&) noexcept = default;
Frame_& operator=(Frame_&&) noexcept = default;
{{- range $index, $item := .FrameItems }}
{{- if $item }}
::fidl::Envelope<{{ $item.Type }}> {{ $item.Name }}_;
{{- else }}
::fidl::Envelope<void> reserved_{{ $index }}_;
{{- end }}
{{- end }}
friend class {{ .Name }};
};
private:
uint64_t max_ordinal_ = 0;
::fidl::ObjectView<Frame_> frame_ptr_;
};
{{- if .IsResourceType }}
{{- EndifFuchsia -}}
{{ end }}
{{- end }}
{{/* TODO(fxbug.dev/36441): Remove __Fuchsia__ ifdefs once we have non-Fuchsia
emulated handles for C++. */}}
{{- define "TableDefinition" }}
{{ if .IsResourceType }}
{{ EnsureNamespace "::" }}
{{- IfdefFuchsia -}}
void {{ . }}::_CloseHandles() {
{{- range .Members }}
{{- if .Type.IsResource }}
if (has_{{ .Name }}()) {
{{- CloseHandles . true false }}
}
{{- end }}
{{- end }}
}
{{- EndifFuchsia -}}
{{- end }}
{{- end }}
{{/* TODO(fxbug.dev/36441): Remove __Fuchsia__ ifdefs once we have non-Fuchsia
emulated handles for C++. */}}
{{- define "TableTraits" }}
{{ if .IsResourceType }}
{{- IfdefFuchsia -}}
{{- end }}
template <>
struct IsFidlType<{{ . }}> : public std::true_type {};
template <>
struct IsTable<{{ . }}> : public std::true_type {};
static_assert(std::is_standard_layout_v<{{ . }}>);
{{- if .IsResourceType }}
{{- EndifFuchsia -}}
{{- end }}
{{- end }}
`