/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include /// For functions-of-coros, like `timeout()` or `collectAll()`, we want the /// outer coro to be able to pass through these attributes of the inner coro: /// - `must_await_immediately_v` /// - `noexcept_awaitable_v` /// - `safe_alias_of_v` /// /// Variation along these dimensions is currently implemented as a zoo of coro /// templates and wrappers -- `Task` aka `UnsafeMovableTask`, `NowTask`, /// `SafeTask`, `AsNoexcept`. The type function `PickTaskWrapper` /// provides common logic for picking a task type with the given attributes. #if FOLLY_HAS_COROUTINES namespace folly::coro { template class Task; template class TaskWithExecutor; template class SafeTask; template class SafeTaskWithExecutor; template class NowTask; template class NowTaskWithExecutor; template class AsNoexcept; namespace detail { struct identity_metafunction { template using apply = T; }; template struct PickTaskWrapperImpl; #if FOLLY_HAS_IMMOVABLE_COROUTINES template <> struct PickTaskWrapperImpl { template using Task = Task; template using TaskWithExecutor = TaskWithExecutor; }; template <> struct PickTaskWrapperImpl { template using Task = NowTask; template using TaskWithExecutor = NowTaskWithExecutor; }; // These `SafeTask` types are immovable, so "await now" doesn't matter. template requires(Safety < safe_alias::closure_min_arg_safety) struct PickTaskWrapperImpl { template using Task = SafeTask; template using TaskWithExecutor = SafeTaskWithExecutor; }; template requires(Safety >= safe_alias::closure_min_arg_safety) // Future: There is no principled reason we can't have must-await-immediately // `SafeTask`s with these higher safety levels, but supporting that cleanly // would require reorganizing the `folly/coro` task-wrapper implementations. Two // possible approaches are: // - `NowTask = AwaitNow>` // - Roll up `NowTask` and `SafeTask` into something like `BasicTask`, // where `Cfg` captures both safety & immediate-awaitability. struct PickTaskWrapperImpl { template using Task = SafeTask; template using TaskWithExecutor = SafeTaskWithExecutor; }; #else // no FOLLY_HAS_IMMOVABLE_COROUTINES // This fallback is required because `coro::Future` is safe and is // available on earlier build systems. We have no choice but to emit `Task`. template struct PickTaskWrapperImpl { template using Task = Task; template using TaskWithExecutor = TaskWithExecutor; }; #endif // FOLLY_HAS_IMMOVABLE_COROUTINES // Pass this as `AddWrapperMetaFn` to `PickTaskWrapper` to add `AsNoexcept`. template struct AsNoexceptWithCancelCfg { template using apply = AsNoexcept; }; template < typename T, safe_alias Safety, bool MustAwaitImmediately, typename AddWrapperMetaFn = identity_metafunction> using PickTaskWrapper = typename AddWrapperMetaFn::template apply< typename PickTaskWrapperImpl::template Task< T>>; template < typename T, safe_alias Safety, bool MustAwaitImmediately, typename AddWrapperMetaFn = identity_metafunction> using PickTaskWithExecutorWrapper = typename AddWrapperMetaFn::template apply< typename PickTaskWrapperImpl:: template TaskWithExecutor>; } // namespace detail } // namespace folly::coro #endif