blob: 12b4a275a41957037ecd360b52b359697a609bdf [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" }}
class {{ .Name }};
{{- end }}
{{- define "TableMemberCloseHandles" }}
{{- if .Type.IsResource }}
if (has_{{ .Name }}()) {
{{- template "TypeCloseHandles" NewTypedArgument .Name .Type .Type.LLPointer true false }}
}
{{- end }}
{{- end }}
{{/* TODO(fxbug.dev/36441): Remove __Fuchsia__ ifdefs once we have non-Fuchsia
emulated handles for C++. */}}
{{- define "TableDeclaration" }}
{{ if .IsResourceType }}
#ifdef __Fuchsia__
{{- end }}
extern "C" const fidl_type_t {{ .TableType }};
{{ range .DocComments }}
//{{ . }}
{{- end}}
class {{ .Name }} final {
public:
// Returns whether no field is set.
bool IsEmpty() const { return max_ordinal_ == 0; }
{{- range .Members }}
{{ "" }}
{{- range .DocComments }}
//{{ . }}
{{- end }}
const {{ .Type.LLDecl }}& {{ .Name }}() const {
ZX_ASSERT({{ .MethodHasName }}());
return *frame_ptr_->{{ .Name }}_.data;
}
{{ .Type.LLDecl }}& {{ .Name }}() {
ZX_ASSERT({{ .MethodHasName }}());
return *frame_ptr_->{{ .Name }}_.data;
}
bool {{ .MethodHasName }}() const {
return max_ordinal_ >= {{ .Ordinal }} && frame_ptr_->{{ .Name }}_.data != nullptr;
}
{{- end }}
{{ .Name }}() = default;
~{{ .Name }}() = default;
{{ .Name }}({{ .Name }}&& other) noexcept = default;
{{ .Name }}& operator=({{ .Name }}&& other) noexcept = default;
static constexpr const fidl_type_t* Type = &{{ .TableType }};
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 }}
class UnownedEncodedMessage final {
public:
UnownedEncodedMessage(uint8_t* bytes, uint32_t byte_size, {{ .Name }}* value)
: message_(bytes, byte_size, sizeof({{ .Name }}),
{{- if gt .MaxHandles 0 }}
handles_, std::min(ZX_CHANNEL_MAX_MSG_HANDLES, MaxNumHandles), 0
{{- else }}
nullptr, 0, 0
{{- end }}
) {
message_.LinearizeAndEncode<{{ .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(); }
#ifdef __Fuchsia__
const char* status_string() const { return message_.status_string(); }
#endif
bool ok() const { return message_.status() == ZX_OK; }
const char* error() const { return message_.error(); }
::fidl::OutgoingMessage& GetOutgoingMessage() { return message_; }
private:
{{- 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)
{{- if gt .MaxSentSize 512 -}}
: bytes_(std::make_unique<::fidl::internal::AlignedBuffer<{{- template "SentSize" .}}>>()),
message_(bytes_->data(), {{- template "SentSize" .}}
{{- else }}
: message_(bytes_, sizeof(bytes_)
{{- end }}
, 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(); }
#ifdef __Fuchsia__
const char* status_string() const { return message_.status_string(); }
#endif
bool ok() const { return message_.ok(); }
const char* error() const { return message_.error(); }
::fidl::OutgoingMessage& GetOutgoingMessage() { return message_.GetOutgoingMessage(); }
private:
{{- if gt .MaxSentSize 512 }}
std::unique_ptr<::fidl::internal::AlignedBuffer<{{- template "SentSize" .}}>> bytes_;
{{- else }}
FIDL_ALIGNDECL
uint8_t bytes_[FIDL_ALIGN(PrimarySize + MaxOutOfLine)];
{{- end }}
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(); }
// These methods should only be used for testing purpose.
// They create an DecodedMessage using the bytes of an outgoing message and copying the
// handles.
static DecodedMessage FromOutgoingWithRawHandleCopy(UnownedEncodedMessage* encoded_message) {
return DecodedMessage(encoded_message->GetOutgoingMessage());
}
static DecodedMessage FromOutgoingWithRawHandleCopy(OwnedEncodedMessage* encoded_message) {
return DecodedMessage(encoded_message->GetOutgoingMessage());
}
private:
DecodedMessage(::fidl::OutgoingMessage& outgoing_message) {
{{- if gt .MaxHandles 0 }}
zx_handle_info_t handles[std::min(ZX_CHANNEL_MAX_MSG_HANDLES, MaxNumHandles)];
Init(outgoing_message, handles, std::min(ZX_CHANNEL_MAX_MSG_HANDLES, MaxNumHandles));
{{- else }}
Init(outgoing_message, nullptr, 0);
{{- end }}
if (ok()) {
Decode<{{ .Name }}>();
}
}
};
class Builder;
class UnownedBuilder;
class Frame final {
public:
Frame() = default;
// In its intended usage, Frame will be referenced by a tracking_ptr. If the tracking_ptr 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 .FrameItems }}
::fidl::Envelope<{{ .LLDecl }}> {{ .Name }}_;
{{- end }}
friend class {{ .Name }};
friend class {{ .Name }}::Builder;
friend class {{ .Name }}::UnownedBuilder;
};
private:
{{ .Name }}(uint64_t max_ordinal, ::fidl::tracking_ptr<Frame>&& frame_ptr) : max_ordinal_(max_ordinal), frame_ptr_(std::move(frame_ptr)) {}
uint64_t max_ordinal_ = 0;
::fidl::tracking_ptr<Frame> frame_ptr_;
};
// {{ .Name }}::Builder builds {{ .Name }}.
// Usage:
// {{ .Name }} val = {{ .Name }}::Builder(std::make_unique<{{ .Name }}::Frame>())
{{ if ne (len .Members) 0 }}// .set_{{(index .Members 0).Name}}(ptr){{end}}
// .build();
class {{ .Name }}::Builder final {
public:
~Builder() = default;
Builder() = delete;
Builder(::fidl::tracking_ptr<{{ .Name }}::Frame>&& frame_ptr) : max_ordinal_(0), frame_ptr_(std::move(frame_ptr)) {}
Builder(Builder&& other) noexcept = default;
Builder& operator=(Builder&& other) noexcept = default;
Builder(const Builder& other) = delete;
Builder& operator=(const Builder& other) = delete;
// Returns whether no field is set.
bool IsEmpty() const { return max_ordinal_ == 0; }
{{- range .Members }}
{{ "" }}
{{- range .DocComments }}
//{{ . }}
{{- end }}
{{- /* TODO(fxbug.dev/7999): The elem pointer should be const if it has no handles. */}}
Builder&& set_{{ .Name }}(::fidl::tracking_ptr<{{ .Type.LLDecl }}> elem) {
frame_ptr_->{{ .Name }}_.data = std::move(elem);
if (max_ordinal_ < {{ .Ordinal }}) {
// Note: the table size is not currently reduced if nullptr is set.
// This is possible to reconsider in the future.
max_ordinal_ = {{ .Ordinal }};
}
return std::move(*this);
}
const {{ .Type.LLDecl }}& {{ .Name }}() const {
ZX_ASSERT({{ .MethodHasName }}());
return *frame_ptr_->{{ .Name }}_.data;
}
{{ .Type.LLDecl }}& {{ .Name }}() {
ZX_ASSERT({{ .MethodHasName }}());
return *frame_ptr_->{{ .Name }}_.data;
}
bool {{ .MethodHasName }}() const {
return max_ordinal_ >= {{ .Ordinal }} && frame_ptr_->{{ .Name }}_.data != nullptr;
}
{{- if eq .Type.Kind TypeKinds.Table }}
{{ .Type.LLDecl }}::Builder& get_builder_{{ .Name }}() {
ZX_ASSERT({{ .MethodHasName }}());
return *reinterpret_cast<{{ .Type.LLDecl }}::Builder*>(&*frame_ptr_->{{ .Name }}_.data);
}
{{- end }}
{{- if eq .Type.Kind TypeKinds.Array }}
{{- if eq .Type.ElementType.Kind TypeKinds.Table }}
::fidl::Array<{{ .Type.ElementType.LLDecl }}::Builder, {{ .Type.ElementCount }}>& get_builders_{{ .Name }}() {
ZX_ASSERT({{ .MethodHasName }}());
return *reinterpret_cast<::fidl::Array<{{ .Type.ElementType.LLDecl }}::Builder, {{ .Type.ElementCount }}>*>(&*frame_ptr_->{{ .Name }}_.data);
}
{{- end }}
{{- end }}
{{- if eq .Type.Kind TypeKinds.Vector }}
{{- if eq .Type.ElementType.Kind TypeKinds.Table }}
::fidl::VectorView<{{ .Type.ElementType.LLDecl }}::Builder>& get_builders_{{ .Name }}() {
ZX_ASSERT({{ .MethodHasName }}());
return *reinterpret_cast<::fidl::VectorView<{{ .Type.ElementType.LLDecl }}::Builder>*>(&*frame_ptr_->{{ .Name }}_.data);
}
{{- end }}
{{- end }}
{{- end }}
{{ .Name }} build() {
return {{ .Name }}(max_ordinal_, std::move(frame_ptr_));
}
private:
uint64_t max_ordinal_ = 0;
::fidl::tracking_ptr<{{ .Name }}::Frame> frame_ptr_;
};
// UnownedBuilder acts like Builder but directly owns its Frame, simplifying working with unowned
// data.
class {{ .Name }}::UnownedBuilder final {
public:
~UnownedBuilder() = default;
UnownedBuilder() noexcept = default;
UnownedBuilder(UnownedBuilder&& other) noexcept = default;
UnownedBuilder& operator=(UnownedBuilder&& other) noexcept = default;
// Returns whether no field is set.
bool IsEmpty() const { return max_ordinal_ == 0; }
{{- range .Members }}
{{ "" }}
{{- range .DocComments }}
//{{ . }}
{{- end }}
{{- /* TODO(fxbug.dev/7999): The elem pointer should be const if it has no handles. */}}
UnownedBuilder&& set_{{ .Name }}(::fidl::tracking_ptr<{{ .Type.LLDecl }}> elem) {
ZX_ASSERT(elem);
frame_.{{ .Name }}_.data = std::move(elem);
if (max_ordinal_ < {{ .Ordinal }}) {
max_ordinal_ = {{ .Ordinal }};
}
return std::move(*this);
}
const {{ .Type.LLDecl }}& {{ .Name }}() const {
ZX_ASSERT({{ .MethodHasName }}());
return *frame_.{{ .Name }}_.data;
}
{{ .Type.LLDecl }}& {{ .Name }}() {
ZX_ASSERT({{ .MethodHasName }}());
return *frame_.{{ .Name }}_.data;
}
bool {{ .MethodHasName }}() const {
return max_ordinal_ >= {{ .Ordinal }} && frame_.{{ .Name }}_.data != nullptr;
}
{{- if eq .Type.Kind TypeKinds.Table }}
{{ .Type.LLDecl }}::Builder& get_builder_{{ .Name }}() {
ZX_ASSERT({{ .MethodHasName }}());
return *reinterpret_cast<{{ .Type.LLDecl }}::Builder*>(&*frame_.{{ .Name }}_.data);
}
{{- end }}
{{- if eq .Type.Kind TypeKinds.Array }}
{{- if eq .Type.ElementType.Kind TypeKinds.Table }}
::fidl::Array<{{ .Type.ElementType.LLDecl }}::Builder, {{ .Type.ElementCount }}>& get_builders_{{ .Name }}() {
ZX_ASSERT({{ .MethodHasName }}());
return *reinterpret_cast<::fidl::Array<{{ .Type.ElementType.LLDecl }}::Builder, {{ .Type.ElementCount }}>*>(&*frame_.{{ .Name }}_.data);
}
{{- end }}
{{- end }}
{{- if eq .Type.Kind TypeKinds.Vector }}
{{- if eq .Type.ElementType.Kind TypeKinds.Table }}
::fidl::VectorView<{{ .Type.ElementType.LLDecl }}::Builder>& get_builders_{{ .Name }}() {
ZX_ASSERT({{ .MethodHasName }}());
return *reinterpret_cast<::fidl::VectorView<{{ .Type.ElementType.LLDecl }}::Builder>*>(&*frame_.{{ .Name }}_.data);
}
{{- end }}
{{- end }}
{{- end }}
{{ .Name }} build() {
{{ if eq (len .Members) 0 -}}
return {{ .Name }}(max_ordinal_, nullptr);
{{- else -}}
return {{ .Name }}(max_ordinal_, ::fidl::unowned_ptr(&frame_));
{{- end }}
}
private:
uint64_t max_ordinal_ = 0;
{{ if ne (len .Members) 0 -}}
{{ .Name }}::Frame frame_;
{{- end }}
};
{{- if .IsResourceType }}
#endif // __Fuchsia__
{{ end }}
{{- end }}
{{/* TODO(fxbug.dev/36441): Remove __Fuchsia__ ifdefs once we have non-Fuchsia
emulated handles for C++. */}}
{{- define "TableDefinition" }}
{{ if .IsResourceType }}
#ifdef __Fuchsia__
void {{ .Name }}::_CloseHandles() {
{{- range .Members }}
{{- template "TableMemberCloseHandles" . }}
{{- end }}
}
#endif // __Fuchsia__
{{- end }}
{{- end }}
{{/* TODO(fxbug.dev/36441): Remove __Fuchsia__ ifdefs once we have non-Fuchsia
emulated handles for C++. */}}
{{- define "TableTraits" }}
{{ if .IsResourceType }}
#ifdef __Fuchsia__
{{- end }}
template <>
struct IsFidlType<{{ .Namespace }}::{{ .Name }}> : public std::true_type {};
template <>
struct IsTable<{{ .Namespace }}::{{ .Name }}> : public std::true_type {};
template <>
struct IsTableBuilder<{{ .Namespace }}::{{ .Name }}::Builder> : public std::true_type {};
static_assert(std::is_standard_layout_v<{{ .Namespace }}::{{ .Name }}>);
{{- if .IsResourceType }}
#endif // __Fuchsia__
{{- end }}
{{- end }}
`