blob: fa5da3bf2034b91faf9782fca1614e6a51f3bf70 [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.
#ifndef SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_UNIFIED_MESSAGING_H_
#define SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_UNIFIED_MESSAGING_H_
#include <lib/fidl/cpp/internal/natural_client_base.h>
#include <lib/fidl/cpp/internal/natural_message_encoder.h>
#include <lib/fidl/cpp/internal/natural_types.h>
#include <lib/fidl/cpp/natural_types.h>
#include <lib/fidl/cpp/unified_messaging_declarations.h>
#include <lib/fidl/llcpp/message.h>
#include <lib/fidl/llcpp/traits.h>
#include <lib/fidl/llcpp/transaction.h>
#include <lib/fidl/llcpp/wire_messaging.h>
#include <lib/fitx/result.h>
#include <cstdint>
namespace fidl {
namespace internal {
template <typename FidlMethod>
struct NaturalMethodTypes {
using Completer = ::fidl::Completer<>;
};
template <typename FidlMethod>
using NaturalCompleter = typename fidl::internal::NaturalMethodTypes<FidlMethod>::Completer;
// Note: application error types used in the error syntax are limited to int32,
// uint32, and enums thereof. Thus the same application error types are shared
// between wire and natural domain objects.
template <typename FidlMethod>
using NaturalApplicationError =
typename fidl::internal::WireMethodTypes<FidlMethod>::ApplicationError;
// |NaturalMessageConverter| extends transactional message wrappers with the
// ability to convert to and from domain object types. In particular, result
// unions in methods using the error syntax will be converted to
// |fitx::result<ApplicationError, Payload>| when receiving, and vice versa
// when sending.
//
// |Message| is either a |fidl::Request<Foo>|, |fidl::Response<Foo>|, or
// |fidl::Event<Foo>|.
//
// It should only be used when |Message| has a body.
//
// The default implementation passes through the domain object without any
// transformation.
template <typename Message>
class NaturalMessageConverter {
using DomainObject = typename MessageTraits<Message>::Payload;
public:
static Message FromDomainObject(DomainObject&& o) { return static_cast<Message>(std::move(o)); }
static DomainObject IntoDomainObject(Message&& m) { return DomainObject{std::move(m)}; }
};
// |DecodeTransactionalMessage| decodes a transactional incoming message to an
// instance of |Payload| containing natural types.
//
// To reducing branching in generated code, |payload| may be |std::nullopt|, in
// which case the message will be decoded without a payload (header-only
// messages).
//
// |message| is always consumed.
template <typename Payload = cpp17::nullopt_t>
static auto DecodeTransactionalMessage(::fidl::IncomingMessage&& message)
-> std::conditional_t<std::is_same_v<Payload, cpp17::nullopt_t>, ::fitx::result<::fidl::Error>,
::fitx::result<::fidl::Error, Payload>> {
ZX_DEBUG_ASSERT(message.is_transactional());
constexpr bool kHasPayload = !std::is_same_v<Payload, cpp17::nullopt_t>;
const fidl_message_header& header = *message.header();
auto metadata = ::fidl::WireFormatMetadata::FromTransactionalHeader(header);
fidl::IncomingMessage body_message = message.SkipTransactionHeader();
if constexpr (kHasPayload) {
// Delegate into the decode logic of the payload.
::fitx::result decode_result = Decode<Payload>(std::move(body_message), metadata);
if (decode_result.is_error()) {
return ::fitx::result<::fidl::Error, Payload>(decode_result.take_error());
}
return ::fitx::result<::fidl::Error, Payload>(::fitx::ok(std::move(decode_result.value())));
} else {
if (body_message.byte_actual() > 0) {
return ::fitx::result<::fidl::Error>(::fitx::error(
::fidl::Status::DecodeError(ZX_ERR_INVALID_ARGS, kCodingErrorNotAllBytesConsumed)));
}
if (body_message.handle_actual() > 0) {
return ::fitx::result<::fidl::Error>(::fitx::error(
::fidl::Status::DecodeError(ZX_ERR_INVALID_ARGS, kCodingErrorNotAllHandlesConsumed)));
}
return ::fitx::result<::fidl::Error>(::fitx::ok());
}
}
inline ::fitx::result<::fidl::Error> ToFitxResult(::fidl::Status result) {
if (result.ok()) {
return ::fitx::ok();
}
return ::fitx::error<::fidl::Error>(result);
}
} // namespace internal
// |ClientCallback| is the async callback type used in the |fidl::Client| for
// the FIDL method |Method| that propagates errors, that works with natural
// domain objects.
//
// It is of the form:
//
// void Callback(Result<Method>&);
//
// where |Result| is a result type of the protocol's transport
// (e.g. |fidl::Result| in Zircon channel messaging).
//
template <typename Method>
using ClientCallback = typename internal::NaturalMethodTypes<Method>::ResultCallback;
} // namespace fidl
#endif // SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_UNIFIED_MESSAGING_H_