Skip to content

Commit 5b88b3e

Browse files
committed
Add support for custom type-erased await_async
1 parent da66d77 commit 5b88b3e

File tree

3 files changed

+118
-75
lines changed

3 files changed

+118
-75
lines changed

include/graphqlservice/GraphQLService.h

Lines changed: 96 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,87 @@ enum class ResolverContext
148148
NotifyUnsubscribe,
149149
};
150150

151+
// Resume coroutine execution on a worker thread.
152+
struct await_worker_thread : coro::suspend_always
153+
{
154+
void await_suspend(coro::coroutine_handle<> h) const
155+
{
156+
std::thread(
157+
[](coro::coroutine_handle<>&& h) noexcept {
158+
h.resume();
159+
},
160+
std::move(h))
161+
.detach();
162+
}
163+
};
164+
165+
// Type-erased awaitable, if you want finer grain control.
166+
class await_async : public coro::suspend_always
167+
{
168+
private:
169+
struct Concept
170+
{
171+
virtual ~Concept() = default;
172+
173+
virtual bool await_ready() const = 0;
174+
virtual void await_suspend(coro::coroutine_handle<> h) const = 0;
175+
};
176+
177+
template <class T>
178+
struct Model : Concept
179+
{
180+
Model(std::shared_ptr<T>&& pimpl)
181+
: _pimpl { std::move(pimpl) }
182+
{
183+
}
184+
185+
bool await_ready() const final
186+
{
187+
return _pimpl->await_ready();
188+
}
189+
190+
void await_suspend(coro::coroutine_handle<> h) const final
191+
{
192+
_pimpl->await_suspend(std::move(h));
193+
}
194+
195+
private:
196+
std::shared_ptr<T> _pimpl;
197+
};
198+
199+
const std::shared_ptr<Concept> _pimpl;
200+
201+
public:
202+
template <class T>
203+
await_async(std::shared_ptr<T> pimpl)
204+
: _pimpl { std::make_shared<Model<T>>(std::move(pimpl)) }
205+
{
206+
}
207+
208+
await_async(std::launch launch)
209+
: _pimpl { ((launch & std::launch::async) == std::launch::async)
210+
? std::static_pointer_cast<Concept>(std::make_shared<Model<await_worker_thread>>(
211+
std::make_shared<await_worker_thread>()))
212+
: std::static_pointer_cast<Concept>(std::make_shared<Model<coro::suspend_never>>(
213+
std::make_shared<coro::suspend_never>())) }
214+
{
215+
}
216+
217+
bool await_ready() const
218+
{
219+
return _pimpl->await_ready();
220+
}
221+
222+
void await_suspend(coro::coroutine_handle<> h) const
223+
{
224+
_pimpl->await_suspend(std::move(h));
225+
}
226+
227+
constexpr void await_resume() const noexcept
228+
{
229+
}
230+
};
231+
151232
// Pass a common bundle of parameters to all of the generated Object::getField accessors in a
152233
// SelectionSet
153234
struct SelectionSetParams
@@ -171,7 +252,7 @@ struct SelectionSetParams
171252
std::optional<field_path> errorPath;
172253

173254
// Async launch policy for sub-field resolvers.
174-
const std::launch launch = std::launch::deferred;
255+
const await_async launch { std::launch::deferred };
175256
};
176257

177258
// Pass a common bundle of parameters to all of the generated Object::getField accessors.
@@ -557,24 +638,6 @@ class Object : public std::enable_shared_from_this<Object>
557638
ResolverMap _resolvers;
558639
};
559640

560-
// Resume coroutine execution on a worker thread. This is used internally to implement the APIs
561-
// which can take std::launch::async as a parameter.
562-
class await_async
563-
{
564-
public:
565-
GRAPHQLSERVICE_EXPORT explicit await_async(std::launch launch) noexcept;
566-
567-
GRAPHQLSERVICE_EXPORT bool await_ready() const noexcept;
568-
GRAPHQLSERVICE_EXPORT void await_suspend(coro::coroutine_handle<> h) const;
569-
570-
constexpr void await_resume() const noexcept
571-
{
572-
}
573-
574-
private:
575-
const std::launch _launch;
576-
};
577-
578641
// Convert the result of a resolver function with chained type modifiers that add nullable or
579642
// list wrappers. This is the inverse of ModifiedArgument for output types instead of input types.
580643
template <typename Type>
@@ -622,7 +685,7 @@ struct ModifiedResult
622685
static_assert(std::is_same_v<std::shared_ptr<Type>, typename ResultTraits<Type>::type>,
623686
"this is the derived object type");
624687

625-
co_await await_async { params.launch };
688+
co_await params.launch;
626689

627690
auto awaitedResult = co_await ModifiedResult<Object>::convert(
628691
std::static_pointer_cast<Object>(co_await result),
@@ -650,7 +713,7 @@ struct ModifiedResult
650713
convert(
651714
typename ResultTraits<Type, Modifier, Other...>::future_type result, ResolverParams params)
652715
{
653-
co_await await_async { params.launch };
716+
co_await params.launch;
654717

655718
auto awaitedResult = co_await std::move(result);
656719

@@ -677,7 +740,7 @@ struct ModifiedResult
677740
typename ResultTraits<Type, Modifier, Other...>::type>,
678741
"this is the optional version");
679742

680-
co_await await_async { params.launch };
743+
co_await params.launch;
681744

682745
auto awaitedResult = co_await std::move(result);
683746

@@ -700,7 +763,7 @@ struct ModifiedResult
700763
std::vector<AwaitableResolver> children;
701764
const auto parentPath = params.errorPath;
702765

703-
co_await await_async { params.launch };
766+
co_await params.launch;
704767

705768
auto awaitedResult = co_await std::move(result);
706769

@@ -743,7 +806,7 @@ struct ModifiedResult
743806
{
744807
try
745808
{
746-
co_await await_async { params.launch };
809+
co_await params.launch;
747810

748811
auto value = co_await std::move(child);
749812

@@ -796,7 +859,7 @@ struct ModifiedResult
796859

797860
try
798861
{
799-
co_await await_async { params.launch };
862+
co_await params.launch;
800863
document.data = pendingResolver(co_await result, params);
801864
}
802865
catch (schema_exception& scx)
@@ -943,17 +1006,17 @@ class Request : public std::enable_shared_from_this<Request>
9431006

9441007
GRAPHQLSERVICE_EXPORT response::AwaitableValue resolve(std::shared_ptr<RequestState> state,
9451008
peg::ast& query, std::string_view operationName, response::Value variables) const;
946-
GRAPHQLSERVICE_EXPORT response::AwaitableValue resolve(std::launch launch,
1009+
GRAPHQLSERVICE_EXPORT response::AwaitableValue resolve(await_async launch,
9471010
std::shared_ptr<RequestState> state, peg::ast& query, std::string_view operationName,
9481011
response::Value variables) const;
9491012

9501013
GRAPHQLSERVICE_EXPORT SubscriptionKey subscribe(
9511014
SubscriptionParams&& params, SubscriptionCallback&& callback);
9521015
GRAPHQLSERVICE_EXPORT AwaitableSubscribe subscribe(
953-
std::launch launch, SubscriptionParams&& params, SubscriptionCallback&& callback);
1016+
await_async launch, SubscriptionParams&& params, SubscriptionCallback&& callback);
9541017

9551018
GRAPHQLSERVICE_EXPORT void unsubscribe(SubscriptionKey key);
956-
GRAPHQLSERVICE_EXPORT AwaitableUnsubscribe unsubscribe(std::launch launch, SubscriptionKey key);
1019+
GRAPHQLSERVICE_EXPORT AwaitableUnsubscribe unsubscribe(await_async launch, SubscriptionKey key);
9571020

9581021
GRAPHQLSERVICE_EXPORT void deliver(
9591022
const SubscriptionName& name, const std::shared_ptr<Object>& subscriptionObject) const;
@@ -970,17 +1033,17 @@ class Request : public std::enable_shared_from_this<Request>
9701033
const SubscriptionFilterCallback& applyDirectives,
9711034
std::shared_ptr<Object> subscriptionObject) const;
9721035

973-
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(std::launch launch, const SubscriptionName& name,
1036+
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(await_async launch, const SubscriptionName& name,
9741037
std::shared_ptr<Object> subscriptionObject) const;
975-
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(std::launch launch, const SubscriptionName& name,
1038+
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(await_async launch, const SubscriptionName& name,
9761039
const SubscriptionArguments& arguments, std::shared_ptr<Object> subscriptionObject) const;
977-
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(std::launch launch, const SubscriptionName& name,
1040+
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(await_async launch, const SubscriptionName& name,
9781041
const SubscriptionArguments& arguments, const SubscriptionArguments& directives,
9791042
std::shared_ptr<Object> subscriptionObject) const;
980-
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(std::launch launch, const SubscriptionName& name,
1043+
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(await_async launch, const SubscriptionName& name,
9811044
const SubscriptionFilterCallback& applyArguments,
9821045
std::shared_ptr<Object> subscriptionObject) const;
983-
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(std::launch launch, const SubscriptionName& name,
1046+
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(await_async launch, const SubscriptionName& name,
9841047
const SubscriptionFilterCallback& applyArguments,
9851048
const SubscriptionFilterCallback& applyDirectives,
9861049
std::shared_ptr<Object> subscriptionObject) const;

samples/today/TodayMock.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ Expensive::~Expensive()
547547
std::future<int> Expensive::getOrder(const service::FieldParams& params) const noexcept
548548
{
549549
return std::async(
550-
params.launch,
550+
params.launch.await_ready() ? std::launch::deferred : std::launch::async,
551551
[](bool blockAsync, int instanceOrder) noexcept {
552552
if (blockAsync)
553553
{
@@ -568,7 +568,7 @@ std::future<int> Expensive::getOrder(const service::FieldParams& params) const n
568568

569569
return instanceOrder;
570570
},
571-
params.launch == std::launch::async,
571+
!params.launch.await_ready(),
572572
static_cast<int>(order));
573573
}
574574

0 commit comments

Comments
 (0)