blob: a22053c83150187a440b2688864cffcd40824191 [file] [log] [blame]
// Copyright 2022 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_CONTRIB_FPROMISE_CLIENT_H_
#define SRC_LIB_FIDL_CONTRIB_FPROMISE_CLIENT_H_
#include <lib/fidl/cpp/internal/thenable.h>
#include <lib/fpromise/bridge.h>
namespace fidl_fpromise {
namespace internal {
// |fpromise::result| uses |void| for when the result does not have a success type.
// On the other hand, |fit::result| simply leaves the |value_type| alias absent.
// This SFINAE converts one scheme to the other.
template <typename T, typename V = void>
struct ValueTypeOrVoid {
using type = V;
};
template <typename T>
struct ValueTypeOrVoid<T, std::void_t<typename T::value_type>> {
using type = typename T::value_type;
};
} // namespace internal
// |as_promise| converts a FIDL asynchronous call in the new C++ bindings
// into a promise. Example usage:
//
// // Let's say an async FIDL call originally uses a callback.
// fidl::Client<MyProtocol> client(...);
// client->Foo({ ... }).Then([] (fidl::Result<MyProtocol::Foo>& result) {
// assert(result.is_ok());
// });
//
// // It can be turned into a promise by wrapping the call with |as_promise|
// // as opposed to attaching a callback via |Then|:
// auto p1 = fidl_fpromise::as_promise(client->Foo({ ... }));
//
// // And used like any other regular promise:
// auto p2 = p1.then([] (auto& result) {
// assert(result.is_ok());
// });
// some_executor.schedule_task(std::move(p2));
//
// The signature of the resulting promise is akin to
//
// fpromise::promise<SuccessType, ErrorType>
//
// where |SuccessType| is the payload type for when the FIDL call succeeds, or
// |void| if the FIDL call has an empty/zero-argument payload.
// where |ErrorType| is |fidl::Error| if the FIDL call does not use application
// errors, and |fidl::ErrorsIn<MyProtocol::FidlMethod>| otherwise. |MyProtocol|
// and |FidlMethod| are all placeholders to be replaced by the actual protocol
// and method names.
template <typename FidlMethod>
auto as_promise(::fidl::internal::NaturalThenable<FidlMethod>&& thenable) {
using ResultType = typename FidlMethod::Protocol::Transport::template Result<FidlMethod>;
using E = typename ResultType::error_type;
using V = typename internal::ValueTypeOrVoid<ResultType>::type;
::fpromise::bridge<V, E> bridge;
std::move(thenable).ThenExactlyOnce(
[completer = std::move(bridge.completer)](auto&& result) mutable {
if (result.is_ok()) {
if constexpr (std::is_same_v<V, void>) {
completer.complete_ok();
} else {
completer.complete_ok(std::move(result.value()));
}
} else {
completer.complete_error(std::move(result.error_value()));
}
});
return bridge.consumer.promise();
}
} // namespace fidl_fpromise
#endif // SRC_LIB_FIDL_CONTRIB_FPROMISE_CLIENT_H_