1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * This file serves as a helper for bridging folly::coro::Task and python
19 * asyncio.future.
20 */
21
22 #pragma once
23
24 #include <Python.h>
25 #include <folly/Executor.h>
26 #include <folly/Portability.h>
27
28 #include <folly/CancellationToken.h>
29 #include <folly/experimental/coro/Task.h>
30 #include <folly/python/AsyncioExecutor.h>
31 #include <folly/python/executor.h>
32
33 #if FOLLY_HAS_COROUTINES
34
35 namespace folly {
36 namespace python {
37
38 template <typename T>
bridgeCoroTask(folly::Executor * executor,folly::coro::Task<T> && coroFrom,folly::Function<void (folly::Try<T> &&,PyObject *)> callback,PyObject * userData,folly::CancellationToken && cancellationToken)39 void bridgeCoroTask(
40 folly::Executor* executor,
41 folly::coro::Task<T>&& coroFrom,
42 folly::Function<void(folly::Try<T>&&, PyObject*)> callback,
43 PyObject* userData,
44 folly::CancellationToken&& cancellationToken) {
45 // We are handing over a pointer to a python object to c++ and need
46 // to make sure it isn't removed by python in that time.
47 Py_INCREF(userData);
48 auto guard = folly::makeGuard([=] { Py_DECREF(userData); });
49 std::move(coroFrom).scheduleOn(executor).start(
50 [callback = std::move(callback), userData, guard = std::move(guard)](
51 folly::Try<T>&& result) mutable {
52 callback(std::move(result), userData);
53 },
54 std::move(cancellationToken));
55 }
56
57 template <typename T>
bridgeCoroTask(folly::Executor * executor,folly::coro::Task<T> && coroFrom,folly::Function<void (folly::Try<T> &&,PyObject *)> callback,PyObject * userData)58 void bridgeCoroTask(
59 folly::Executor* executor,
60 folly::coro::Task<T>&& coroFrom,
61 folly::Function<void(folly::Try<T>&&, PyObject*)> callback,
62 PyObject* userData) {
63 bridgeCoroTask(
64 executor,
65 std::move(coroFrom),
66 std::move(callback),
67 userData,
68 folly::CancellationToken());
69 }
70
71 template <typename T>
bridgeCoroTask(folly::coro::Task<T> && coroFrom,folly::Function<void (folly::Try<T> &&,PyObject *)> callback,PyObject * userData)72 void bridgeCoroTask(
73 folly::coro::Task<T>&& coroFrom,
74 folly::Function<void(folly::Try<T>&&, PyObject*)> callback,
75 PyObject* userData) {
76 bridgeCoroTask(
77 getExecutor(), std::move(coroFrom), std::move(callback), userData);
78 }
79
80 } // namespace python
81 } // namespace folly
82
83 #endif
84