Skip to content

Commit

Permalink
OpaqueTaskWrapperCrtp lets wrappers avoid defaulting to "awaitable"
Browse files Browse the repository at this point in the history
Summary:
Split `OpaqueTaskWrapperCrtp` out of `TaskWrapperCrtp` so that `Task` wrappers can avoid being automatically awaitable.

This is e.g. used by up-stack `ClosureTask`, which supposed to only be usable with `async_closure()` and similar APIs.

Reviewed By: yfeldblum

Differential Revision: D66121851

fbshipit-source-id: 58e470e0094783e92920a8d870d6625fa645e54a
  • Loading branch information
Alexey Spiridonov authored and facebook-github-bot committed Dec 9, 2024
1 parent 96c9739 commit 5620dfc
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 7 deletions.
27 changes: 20 additions & 7 deletions folly/coro/TaskWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,43 +169,56 @@ class TaskPromiseWrapper<void, SemiAwaitable, Promise>

} // namespace detail

// Inherit from this instead of `TaskWrapperCrtp` if you don't want your
// wrapped task to be awaitable without being `unwrap()`ped first.
template <typename Derived, typename T, typename SemiAwaitable>
class TaskWrapperCrtp {
class OpaqueTaskWrapperCrtp {
private:
static_assert(
detail::is_task_or_wrapper_v<SemiAwaitable, T>,
"TaskWrapperCrtp must wrap a sequence of wrappers ending in Task<T>");
"*TaskWrapperCrtp must wrap a sequence of wrappers ending in Task<T>");

SemiAwaitable task_;

protected:
template <typename, typename, typename>
friend class ::folly::coro::detail::TaskPromiseWrapperBase;

explicit TaskWrapperCrtp(SemiAwaitable t) : task_(std::move(t)) {}
explicit OpaqueTaskWrapperCrtp(SemiAwaitable t) : task_(std::move(t)) {}

SemiAwaitable unwrap() && { return std::move(task_); }

public:
using TaskWrapperUnderlyingSemiAwaitable = SemiAwaitable;
};

template <typename Derived, typename T, typename SemiAwaitable>
class TaskWrapperCrtp
: public OpaqueTaskWrapperCrtp<Derived, T, SemiAwaitable> {
protected:
template <typename, typename, typename>
friend class ::folly::coro::detail::TaskPromiseWrapperBase;

using OpaqueTaskWrapperCrtp<Derived, T, SemiAwaitable>::OpaqueTaskWrapperCrtp;

public:
// NB: In the future, this might ALSO produce a wrapped object.
FOLLY_NODISCARD
TaskWithExecutor<T> scheduleOn(Executor::KeepAlive<> executor) && noexcept {
return std::move(task_).scheduleOn(std::move(executor));
return std::move(*this).unwrap().scheduleOn(std::move(executor));
}

FOLLY_NOINLINE auto semi() && { return std::move(task_).semi(); }
FOLLY_NOINLINE auto semi() && { return std::move(*this).unwrap().semi(); }

friend Derived co_withCancellation(
folly::CancellationToken cancelToken, Derived&& tw) noexcept {
return Derived{
co_withCancellation(std::move(cancelToken), std::move(tw.task_))};
co_withCancellation(std::move(cancelToken), std::move(tw).unwrap())};
}

friend auto co_viaIfAsync(
folly::Executor::KeepAlive<> executor, Derived&& tw) noexcept {
return co_viaIfAsync(std::move(executor), std::move(tw.task_));
return co_viaIfAsync(std::move(executor), std::move(tw).unwrap());
}
// At least in Clang 15, the `static_assert` isn't enough to get a usable
// error message (it is instantiated too late), but the deprecation
Expand Down
25 changes: 25 additions & 0 deletions folly/coro/test/TaskWrapperTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,29 @@ CO_TEST(TaskWrapper, recursiveUnwrap) {
EXPECT_EQ(3, co_await t().unwrap().unwrap());
}

template <typename>
struct OpaqueTask;

namespace detail {
template <typename T>
class OpaqueTaskPromise final
: public TaskPromiseWrapper<T, OpaqueTask<T>, TaskPromise<T>> {};
} // namespace detail

template <typename T>
struct FOLLY_CORO_TASK_ATTRS OpaqueTask final
: public OpaqueTaskWrapperCrtp<OpaqueTask<T>, T, Task<T>> {
using promise_type = detail::OpaqueTaskPromise<T>;
using OpaqueTaskWrapperCrtp<OpaqueTask<T>, T, Task<T>>::OpaqueTaskWrapperCrtp;
using OpaqueTaskWrapperCrtp<OpaqueTask<T>, T, Task<T>>::unwrap;
};

static_assert(is_semi_awaitable_v<TinyTask<int>>);
static_assert(!is_semi_awaitable_v<OpaqueTask<int>>);

CO_TEST(TaskWrapper, opaque) {
auto ot = [](int x) -> OpaqueTask<int> { co_return 1300 + x; }(37);
EXPECT_EQ(1337, co_await std::move(ot).unwrap());
}

} // namespace folly::coro

0 comments on commit 5620dfc

Please sign in to comment.