blob: 0f34ff72b3f3232e73d411373f35331e698e8ae9 [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_INTERNAL_MAKE_RESPONSE_CONTEXT_H_
#define SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_INTERNAL_MAKE_RESPONSE_CONTEXT_H_
#include <lib/fidl/cpp/any_error_in.h>
#include <lib/fidl/cpp/unified_messaging.h>
#include <lib/fidl/llcpp/client_base.h>
namespace fidl {
namespace internal {
// |MakeResponseContext| is a helper to create an adaptor from a |ResponseContext|
// to a response/result callback. It returns a raw pointer which deletes itself
// upon the receipt of a response or an error.
template <typename FidlMethod>
ResponseContext* MakeResponseContext(uint64_t ordinal,
::fidl::ClientCallback<FidlMethod> callback) {
using ResultType = typename FidlMethod::Protocol::Transport::template Result<FidlMethod>;
using CallbackType = ::fidl::ClientCallback<FidlMethod>;
class ResponseContext final : public ::fidl::internal::ResponseContext {
public:
explicit ResponseContext(uint64_t ordinal, CallbackType&& callback)
: ::fidl::internal::ResponseContext(ordinal), callback_(std::move(callback)) {}
private:
::cpp17::optional<::fidl::UnbindInfo> OnRawResult(
::fidl::IncomingMessage&& result,
::fidl::internal::IncomingTransportContext transport_context) override {
using NaturalResponse = ::fidl::Response<FidlMethod>;
constexpr bool HasApplicationError =
::fidl::internal::NaturalMethodTypes<FidlMethod>::HasApplicationError;
constexpr bool IsAbsentBody = ::fidl::internal::NaturalMethodTypes<FidlMethod>::IsAbsentBody;
struct DeleteSelf {
ResponseContext* c;
~DeleteSelf() { delete c; }
} delete_self{this};
// Check transport error.
if (!result.ok()) {
ResultType error = ::fitx::error(result.error());
callback_(error);
return cpp17::nullopt;
}
::fitx::result decoded = [&] {
if constexpr (IsAbsentBody) {
return DecodeTransactionalMessage(std::move(result));
} else {
using Body = typename MessageTraits<NaturalResponse>::Payload;
return DecodeTransactionalMessage<Body>(std::move(result));
}
}();
// Check decoding error.
if (decoded.is_error()) {
::fidl::UnbindInfo unbind_info = ::fidl::UnbindInfo(decoded.error_value());
ResultType error = ::fitx::error(decoded.error_value());
callback_(error);
return unbind_info;
}
if constexpr (IsAbsentBody) {
// Absent body.
ResultType value = ::fitx::success();
callback_(value);
} else {
NaturalResponse response =
NaturalMessageConverter<NaturalResponse>::FromDomainObject(std::move(decoded.value()));
if constexpr (HasApplicationError) {
// Fold application error.
if (response.is_error()) {
ResultType error = response.take_error();
callback_(error);
} else {
ZX_DEBUG_ASSERT(response.is_ok());
if constexpr (::fidl::internal::NaturalMethodTypes<FidlMethod>::IsEmptyStructPayload) {
// Omit empty structs.
ResultType value = ::fitx::success();
callback_(value);
} else {
ResultType value = response.take_value();
callback_(value);
}
}
} else {
ResultType value = ::fitx::ok(std::move(response));
callback_(value);
}
}
return cpp17::nullopt;
}
::fidl::ClientCallback<FidlMethod> callback_;
};
return new ResponseContext(ordinal, std::forward<CallbackType>(callback));
}
} // namespace internal
} // namespace fidl
#endif // SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_INTERNAL_MAKE_RESPONSE_CONTEXT_H_