Move futures helper types into folly::futures::detail
[folly.git] / folly / futures / Future-pre.h
1 /*
2  * Copyright 2017 Facebook, Inc.
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 #pragma once
18
19 // included by Future.h, do not include directly.
20
21 namespace folly {
22
23 template <class> class Promise;
24
25 template <typename T>
26 struct isFuture : std::false_type {
27   using Inner = typename Unit::Lift<T>::type;
28 };
29
30 template <typename T>
31 struct isFuture<Future<T>> : std::true_type {
32   typedef T Inner;
33 };
34
35 template <typename T>
36 struct isTry : std::false_type {};
37
38 template <typename T>
39 struct isTry<Try<T>> : std::true_type {};
40
41 namespace futures {
42 namespace detail {
43
44 template <class> class Core;
45 template <class...> struct CollectAllVariadicContext;
46 template <class...> struct CollectVariadicContext;
47 template <class> struct CollectContext;
48
49 template<typename F, typename... Args>
50 using resultOf = decltype(std::declval<F>()(std::declval<Args>()...));
51
52 template <typename...>
53 struct ArgType;
54
55 template <typename Arg, typename... Args>
56 struct ArgType<Arg, Args...> {
57   typedef Arg FirstArg;
58 };
59
60 template <>
61 struct ArgType<> {
62   typedef void FirstArg;
63 };
64
65 template <bool isTry, typename F, typename... Args>
66 struct argResult {
67   using Result = resultOf<F, Args...>;
68 };
69
70 template<typename F, typename... Args>
71 struct callableWith {
72     template<typename T,
73              typename = detail::resultOf<T, Args...>>
74     static constexpr std::true_type
75     check(std::nullptr_t) { return std::true_type{}; }
76
77     template<typename>
78     static constexpr std::false_type
79     check(...) { return std::false_type{}; }
80
81     typedef decltype(check<F>(nullptr)) type;
82     static constexpr bool value = type::value;
83 };
84
85 template<typename T, typename F>
86 struct callableResult {
87   typedef typename std::conditional<
88     callableWith<F>::value,
89     detail::argResult<false, F>,
90     typename std::conditional<
91       callableWith<F, T&&>::value,
92       detail::argResult<false, F, T&&>,
93       typename std::conditional<
94         callableWith<F, T&>::value,
95         detail::argResult<false, F, T&>,
96         typename std::conditional<
97           callableWith<F, Try<T>&&>::value,
98           detail::argResult<true, F, Try<T>&&>,
99           detail::argResult<true, F, Try<T>&>>::type>::type>::type>::type Arg;
100   typedef isFuture<typename Arg::Result> ReturnsFuture;
101   typedef Future<typename ReturnsFuture::Inner> Return;
102 };
103
104 template <typename L>
105 struct Extract : Extract<decltype(&L::operator())> { };
106
107 template <typename Class, typename R, typename... Args>
108 struct Extract<R(Class::*)(Args...) const> {
109   typedef isFuture<R> ReturnsFuture;
110   typedef Future<typename ReturnsFuture::Inner> Return;
111   typedef typename ReturnsFuture::Inner RawReturn;
112   typedef typename ArgType<Args...>::FirstArg FirstArg;
113 };
114
115 template <typename Class, typename R, typename... Args>
116 struct Extract<R(Class::*)(Args...)> {
117   typedef isFuture<R> ReturnsFuture;
118   typedef Future<typename ReturnsFuture::Inner> Return;
119   typedef typename ReturnsFuture::Inner RawReturn;
120   typedef typename ArgType<Args...>::FirstArg FirstArg;
121 };
122
123 template <typename R, typename... Args>
124 struct Extract<R (*)(Args...)> {
125   typedef isFuture<R> ReturnsFuture;
126   typedef Future<typename ReturnsFuture::Inner> Return;
127   typedef typename ReturnsFuture::Inner RawReturn;
128   typedef typename ArgType<Args...>::FirstArg FirstArg;
129 };
130
131 template <typename R, typename... Args>
132 struct Extract<R (&)(Args...)> {
133   typedef isFuture<R> ReturnsFuture;
134   typedef Future<typename ReturnsFuture::Inner> Return;
135   typedef typename ReturnsFuture::Inner RawReturn;
136   typedef typename ArgType<Args...>::FirstArg FirstArg;
137 };
138
139 // gcc-4.8 refuses to capture a function reference in a lambda. This can be
140 // mitigated by casting them to function pointer types first. The following
141 // helper is used in Future.h to achieve that where necessary.
142 // When compiling with gcc versions 4.9 and up, as well as clang, we do not
143 // need to apply FunctionReferenceToPointer (i.e. T can be used instead of
144 // FunctionReferenceToPointer<T>).
145 // Applying FunctionReferenceToPointer first, the code works on all tested
146 // compiler versions: gcc 4.8 and above, cland 3.5 and above.
147
148 template <typename T>
149 struct FunctionReferenceToPointer {
150   using type = T;
151 };
152
153 template <typename R, typename... Args>
154 struct FunctionReferenceToPointer<R (&)(Args...)> {
155   using type = R (*)(Args...);
156 };
157
158 } // namespace detail
159 } // namespace futures
160
161 class Timekeeper;
162
163 } // namespace