blob: d9de099025f89fa7e618a33d0c84e91ef42d2dd3 [file] [log] [blame]
{{/*
// Copyright 2021 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 "Protocol:EventHandler:WireMessagingHeader" }}
{{- EnsureNamespace "" }}
{{- IfdefFuchsia }}
template<>
class {{ .WireEventHandlerInterface }} {
public:
{{ .WireEventHandlerInterface.Self }}() = default;
virtual ~{{ .WireEventHandlerInterface.Self }}() = default;
{{- range .Events -}}
{{- .Docs }}
virtual void {{ .Name }}({{ .WireEvent }}* event) = 0;
{{- end }}
};
template<>
class {{ .WireAsyncEventHandler }}
: public {{ .WireEventHandlerInterface }}, public ::fidl::internal::AsyncEventHandler {
public:
{{ .WireAsyncEventHandler.Self }}() = default;
{{- range .Events -}}
{{- .Docs }}
void {{ .Name }}({{ .WireEvent }}* event) override {}
{{- end }}
};
template<>
class {{ .WireSyncEventHandler }} : public {{ .WireEventHandlerInterface }} {
public:
{{ .WireSyncEventHandler.Self }}() = default;
{{- range .Events }}
{{- if .Transitional }}
void {{ .Name }}({{ .WireEvent }}* event) override { got_transitional_ = true; }
{{- end }}
{{- end }}
// Handle all possible events defined in this protocol.
// Blocks to consume exactly one message from the channel, then call the corresponding virtual
// method.
::fidl::Status HandleOneEvent(
::{{ .Transport.Namespace }}::UnownedClientEnd<{{ . }}> client_end);
private:
[[maybe_unused]]
bool got_transitional_ = false;
};
template <>
class {{ .WireEventDispatcher }} final :
public ::fidl::internal::IncomingEventDispatcher<{{ .WireAsyncEventHandler }}> {
public:
explicit {{ .WireEventDispatcher.Self }}({{ .WireAsyncEventHandler }}* event_handler)
: IncomingEventDispatcher(event_handler) {}
private:
std::optional<::fidl::UnbindInfo> DispatchEvent(
::fidl::IncomingMessage& msg,
::fidl::internal::IncomingTransportContext transport_context) override;
};
{{- EndifFuchsia }}
{{- end }}
{{- define "Protocol:EventHandler:WireMessagingSource" }}
{{ EnsureNamespace "" }}
{{- IfdefFuchsia }}
{{ if .Transport.HasEvents }}
::fidl::Status {{ .WireSyncEventHandler.NoLeading }}::HandleOneEvent(
::{{ .Transport.Namespace }}::UnownedClientEnd<{{ . }}> client_end) {
zx_status_t status = client_end.channel()->wait_one(ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED,
::zx::time::infinite(),
nullptr);
if (status != ZX_OK) {
return ::fidl::Status::TransportError(status, ::fidl::internal::kErrorWaitOneFailed);
}
constexpr uint32_t kHandleAllocSize = ([]() constexpr {
uint32_t x = 0;
{{- range .Events }}
if (::fidl::TypeTraits<{{ .WireTransactionalEvent }}>::kMaxNumHandles >= x) {
x = ::fidl::TypeTraits<{{ .WireTransactionalEvent }}>::kMaxNumHandles;
}
{{- end }}
if (x > ZX_CHANNEL_MAX_MSG_HANDLES) {
x = ZX_CHANNEL_MAX_MSG_HANDLES;
}
return x;
})();
static_assert(kHandleAllocSize <= ZX_CHANNEL_MAX_MSG_HANDLES);
{{ .SyncEventAllocationV1.BackingBufferType }} read_storage;
std::array<zx_handle_t, kHandleAllocSize> read_handles;
// TODO(fxbug.dev/85734) Remove this channel-specific allocation.
std::array<fidl_channel_handle_metadata_t, kHandleAllocSize> read_handle_metadata;
::fidl::IncomingMessage msg = ::fidl::MessageRead(
zx::unowned_channel(client_end.handle()),
read_storage.view(),
read_handles.data(),
read_handle_metadata.data(),
kHandleAllocSize,
ReadOptions{.discardable = true}
);
if (msg.status() == ZX_ERR_BUFFER_TOO_SMALL) {
// Message size is unexpectedly larger than calculated.
// This can only be due to a newer version of the protocol defining a new event,
// whose size exceeds the maximum of known events in the current protocol.
return ::fidl::Status::UnexpectedMessage(
ZX_ERR_BUFFER_TOO_SMALL, ::fidl::internal::kErrorSyncEventBufferTooSmall);
}
if (!msg.ok()) {
return msg;
}
fidl_message_header_t* hdr = msg.header();
switch (hdr->ordinal) {
{{- range .Events }}
case {{ .OrdinalName }}: {
::fidl::unstable::DecodedMessage<{{ .WireTransactionalEvent }}> decoded{::std::move(msg)};
if (!decoded.ok()) {
return ::fidl::Status(decoded);
}
{{- if .ResponseArgs }}
auto* primary = &decoded.PrimaryObject()->body;
{{- else }}
{{ .WireEvent }} empty_event;
auto* primary = &empty_event;
{{- end }}
got_transitional_ = false;
{{ .Name }}(primary);
if (got_transitional_) {
return ::fidl::Status::UnexpectedMessage(
ZX_ERR_NOT_SUPPORTED, ::fidl::internal::kErrorSyncEventUnhandledTransitionalEvent);
}
return ::fidl::Status::Ok();
}
{{- end }}
default: {
return ::fidl::Status::UnknownOrdinal();
}
}
}
std::optional<::fidl::UnbindInfo>
{{ .WireEventDispatcher.NoLeading }}::DispatchEvent(
::fidl::IncomingMessage& msg,
::fidl::internal::IncomingTransportContext transport_context) {
switch (msg.header()->ordinal) {
{{- range .Events }}
case {{ .OrdinalName }}:
{
::fidl::unstable::DecodedMessage<{{ .WireTransactionalEvent }}> decoded{std::move(msg)};
if (!decoded.ok()) {
return ::fidl::UnbindInfo{decoded};
}
if (event_handler()) {
{{- if .ResponseArgs }}
auto* primary = &decoded.PrimaryObject()->body;
{{- else }}
{{ .WireEvent }} empty_event;
auto* primary = &empty_event;
{{- end }}
event_handler()->{{ .Name }}(primary);
}
return std::nullopt;
}
{{- end }}
default:
break;
}
return ::fidl::UnbindInfo::UnknownOrdinal();
}
{{- else }}{{/* not .Transport.HasEvents */}}
::fidl::Status {{ .WireSyncEventHandler.NoLeading }}::HandleOneEvent(
::{{ .Transport.Namespace }}::UnownedClientEnd<{{ . }}> client_end) {
ZX_PANIC("events not supported for transport '{{ .Transport.Name }}'");
}
std::optional<::fidl::UnbindInfo>
{{ .WireEventDispatcher.NoLeading }}::DispatchEvent(
fidl::IncomingMessage& msg,
internal::IncomingTransportContext transport_context) {
ZX_PANIC("events not supported for transport '{{ .Transport.Name }}'");
}
{{- end }}
{{- EndifFuchsia }}
{{- end }}
{{- define "Protocol:EventHandler:NaturalMessagingHeader" }}
{{- EnsureNamespace "" }}
{{- IfdefFuchsia }}
template<>
class {{ .NaturalEventHandlerInterface }} {
public:
{{ .NaturalEventHandlerInterface.Self }}() = default;
virtual ~{{ .NaturalEventHandlerInterface.Self }}() = default;
{{- range .Events -}}
{{- .Docs }}
virtual void {{ .Name }}({{ .NaturalEvent }}&) = 0;
{{- end }}
};
template<>
class {{ .NaturalAsyncEventHandler }}
: public {{ .NaturalEventHandlerInterface }}, public ::fidl::internal::AsyncEventHandler {
public:
{{ .NaturalAsyncEventHandler.Self }}() = default;
{{- range .Events -}}
{{- .Docs }}
void {{ .Name }}({{ .NaturalEvent }}&) override {}
{{- end }}
};
template <>
class {{ .NaturalEventDispatcher }} final :
public ::fidl::internal::IncomingEventDispatcher<{{ .NaturalAsyncEventHandler }}> {
public:
explicit {{ .NaturalEventDispatcher.Self }}({{ .NaturalAsyncEventHandler }}* event_handler)
: IncomingEventDispatcher(event_handler) {}
private:
std::optional<::fidl::UnbindInfo> DispatchEvent(
::fidl::IncomingMessage& msg,
internal::IncomingTransportContext transport_context) override;
};
{{- EndifFuchsia }}
{{- end }}
{{- define "Protocol:EventHandler:NaturalMessagingSource" }}
{{- EnsureNamespace "" }}
{{- IfdefFuchsia }}
std::optional<::fidl::UnbindInfo>
{{ .NaturalEventDispatcher.NoLeading }}::DispatchEvent(
::fidl::IncomingMessage& msg,
::fidl::internal::IncomingTransportContext transport_context) {
{{- if .Events }}
switch (msg.header()->ordinal) {
{{- range .Events }}
case {{ .OrdinalName }}:
{
::fitx::result decoded = ::fidl::internal::DecodeTransactionalMessage
{{- if .HasResponsePayload }}<{{ .ResponsePayload }}>{{ end -}}(std::move(msg));
if (decoded.is_error()) {
return ::fidl::UnbindInfo(decoded.error_value());
}
if (event_handler()) {
{{ .NaturalEvent }} event
{{- if .HasResponsePayload }}
= {{ .NaturalEventConverter }}::FromDomainObject(std::move(decoded.value()))
{{- end }};
event_handler()->{{ .Name }}(event);
}
return std::nullopt;
}
{{- end }}
default:
break;
}
{{- end }}
return ::fidl::UnbindInfo::UnknownOrdinal();
}
{{- EndifFuchsia }}
{{- end }}