blob: cb89ab8a9dc45ab4fe84f1ba4b5666c978a35d25 [file] [log] [blame]
// Copyright 2020 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_DEVELOPER_FORENSICS_UTILS_FIT_PROMISE_H_
#define SRC_DEVELOPER_FORENSICS_UTILS_FIT_PROMISE_H_
#include <lib/fpromise/promise.h>
#include <memory>
#include <tuple>
#include <type_traits>
namespace forensics {
namespace fit {
namespace internal {
template <typename T>
struct is_unique_ptr : std::false_type {};
template <typename T>
struct is_unique_ptr<std::unique_ptr<T>> : std::true_type {};
template <typename T>
struct is_shared_ptr : std::false_type {};
template <typename T>
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
template <typename T>
struct is_managed_ptr {
static constexpr bool value = is_unique_ptr<T>::value || is_shared_ptr<T>::value;
};
// To statically assert that all of the parameter pack of ExtendArgsLifetimeBeyondPromise contains
// only managed pointers, we recursively iterate over the elements of the pack, checking that the
// first element of the pack is a manager pointer and storing the logical and of that with the
// result of the rest of the pack. When no elements are left in the pack, and thus we have hit the
// base case of the recursion, we return true.
template <typename... Head>
struct only_managed_ptrs {
static constexpr bool value = true;
};
// In this specialization of |only_manager_ptrs|, Head is the type of the first element of the
// parameter pack and Tail is the rest of the pack with Head removed.
template <typename Head, typename... Tail>
struct only_managed_ptrs<Head, Tail...> {
static constexpr bool value = is_managed_ptr<Head>::value && only_managed_ptrs<Tail...>::value;
};
} // namespace internal
// ExtendArgsLifetimeBeyondPromise takes a promise and the objects it needs to be alive to complete
// properly and guarantees that those objects are not destroyed unitl after the promise
// executes. Fot the sake of simplicity we only allow managed pointers to be used.
template <typename Promise, typename Arg, typename... Args>
Promise ExtendArgsLifetimeBeyondPromise(Promise promise, Arg&& head, Args&&... tail) {
static_assert(internal::only_managed_ptrs<Arg, Args...>::value,
"Only managed pointers (std::unique_ptr/std::shared_ptr) can be be kept alive by "
"ExtendArgsLifetimeBeyondPromise");
return promise.then([head = std::make_tuple(std::forward<Arg>(head)),
tail = std::make_tuple(std::forward<Args>(tail)...)](
typename Promise::result_type& result) ->
typename Promise::result_type { return std::move(result); });
}
} // namespace fit
} // namespace forensics
#endif // SRC_DEVELOPER_FORENSICS_UTILS_FIT_PROMISE_H_