makeTryFunction -> makeTryWith codemod
[folly.git] / folly / futures / Try.h
1 /*
2  * Copyright 2015 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 #include <type_traits>
20 #include <exception>
21 #include <algorithm>
22 #include <folly/ExceptionWrapper.h>
23 #include <folly/Likely.h>
24 #include <folly/Memory.h>
25 #include <folly/futures/Deprecated.h>
26 #include <folly/futures/FutureException.h>
27 #include <folly/futures/Unit.h>
28
29 namespace folly {
30
31 /*
32  * Try<T> is a wrapper that contains either an instance of T, an exception, or
33  * nothing. Its primary use case is as a representation of a Promise or Future's
34  * result and so it provides a number of methods that are useful in that
35  * context. Exceptions are stored as exception_wrappers so that the user can
36  * minimize rethrows if so desired.
37  *
38  * There is a specialization, Try<void>, which represents either success
39  * or an exception.
40  */
41 template <class T>
42 class Try {
43   static_assert(!std::is_reference<T>::value,
44                 "Try may not be used with reference types");
45
46   enum class Contains {
47     VALUE,
48     EXCEPTION,
49     NOTHING,
50   };
51
52  public:
53   /*
54    * The value type for the Try
55    */
56   typedef T element_type;
57
58   /*
59    * Construct an empty Try
60    */
61   Try() : contains_(Contains::NOTHING) {}
62
63   /*
64    * Construct a Try with a value by copy
65    *
66    * @param v The value to copy in
67    */
68   explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
69
70   /*
71    * Construct a Try with a value by move
72    *
73    * @param v The value to move in
74    */
75   explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
76
77   /*
78    * Construct a Try with an exception_wrapper
79    *
80    * @param e The exception_wrapper
81    */
82   explicit Try(exception_wrapper e)
83     : contains_(Contains::EXCEPTION),
84       e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
85
86   /*
87    * DEPRECATED
88    * Construct a Try with an exception_pointer
89    *
90    * @param ep The exception_pointer. Will be rethrown.
91    */
92   explicit Try(std::exception_ptr ep) DEPRECATED
93     : contains_(Contains::EXCEPTION) {
94     try {
95       std::rethrow_exception(ep);
96     } catch (const std::exception& e) {
97       e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
98     } catch (...) {
99       e_ = folly::make_unique<exception_wrapper>(std::current_exception());
100     }
101   }
102
103   // Move constructor
104   Try(Try<T>&& t) noexcept;
105   // Move assigner
106   Try& operator=(Try<T>&& t) noexcept;
107
108   // Copy constructor
109   Try(const Try& t);
110   // Copy assigner
111   Try& operator=(const Try& t);
112
113   ~Try();
114
115   /*
116    * Get a mutable reference to the contained value. If the Try contains an
117    * exception it will be rethrown.
118    *
119    * @returns mutable reference to the contained value
120    */
121   T& value();
122   /*
123    * Get a const reference to the contained value. If the Try contains an
124    * exception it will be rethrown.
125    *
126    * @returns const reference to the contained value
127    */
128   const T& value() const;
129
130   /*
131    * If the Try contains an exception, rethrow it. Otherwise do nothing.
132    */
133   void throwIfFailed() const;
134
135   /*
136    * Const dereference operator. If the Try contains an exception it will be
137    * rethrown.
138    *
139    * @returns const reference to the contained value
140    */
141   const T& operator*() const { return value(); }
142   /*
143    * Dereference operator. If the Try contains an exception it will be rethrown.
144    *
145    * @returns mutable reference to the contained value
146    */
147   T& operator*() { return value(); }
148
149   /*
150    * Const arrow operator. If the Try contains an exception it will be
151    * rethrown.
152    *
153    * @returns const reference to the contained value
154    */
155   const T* operator->() const { return &value(); }
156   /*
157    * Arrow operator. If the Try contains an exception it will be rethrown.
158    *
159    * @returns mutable reference to the contained value
160    */
161   T* operator->() { return &value(); }
162
163   /*
164    * @returns True if the Try contains a value, false otherwise
165    */
166   bool hasValue() const { return contains_ == Contains::VALUE; }
167   /*
168    * @returns True if the Try contains an exception, false otherwise
169    */
170   bool hasException() const { return contains_ == Contains::EXCEPTION; }
171
172   /*
173    * @returns True if the Try contains an exception of type Ex, false otherwise
174    */
175   template <class Ex>
176   bool hasException() const {
177     return hasException() && e_->is_compatible_with<Ex>();
178   }
179
180   exception_wrapper& exception() {
181     if (UNLIKELY(!hasException())) {
182       throw FutureException("exception(): Try does not contain an exception");
183     }
184     return *e_;
185   }
186
187   const exception_wrapper& exception() const {
188     if (UNLIKELY(!hasException())) {
189       throw FutureException("exception(): Try does not contain an exception");
190     }
191     return *e_;
192   }
193
194   /*
195    * If the Try contains an exception and it is of type Ex, execute func(Ex)
196    *
197    * @param func a function that takes a single parameter of type const Ex&
198    *
199    * @returns True if the Try held an Ex and func was executed, false otherwise
200    */
201   template <class Ex, class F>
202   bool withException(F func) const {
203     if (!hasException()) {
204       return false;
205     }
206     return e_->with_exception<Ex>(std::move(func));
207   }
208
209   template <bool isTry, typename R>
210   typename std::enable_if<isTry, R>::type get() {
211     return std::forward<R>(*this);
212   }
213
214   template <bool isTry, typename R>
215   typename std::enable_if<!isTry, R>::type get() {
216     return std::forward<R>(value());
217   }
218
219  private:
220   Contains contains_;
221   union {
222     T value_;
223     std::unique_ptr<exception_wrapper> e_;
224   };
225 };
226
227 /*
228  * Specialization of Try for void value type. Encapsulates either success or an
229  * exception.
230  */
231 template <>
232 class Try<void> {
233  public:
234   // Construct a Try holding a successful and void result
235   Try() : hasValue_(true) {}
236
237   /*
238    * Construct a Try with an exception_wrapper
239    *
240    * @param e The exception_wrapper
241    */
242   explicit Try(exception_wrapper e)
243     : hasValue_(false),
244       e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
245
246   /*
247    * DEPRECATED
248    * Construct a Try with an exception_pointer
249    *
250    * @param ep The exception_pointer. Will be rethrown.
251    */
252   explicit Try(std::exception_ptr ep) DEPRECATED : hasValue_(false) {
253     try {
254       std::rethrow_exception(ep);
255     } catch (const std::exception& e) {
256       e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
257     } catch (...) {
258       e_ = folly::make_unique<exception_wrapper>(std::current_exception());
259     }
260   }
261
262   // Copy assigner
263   Try& operator=(const Try<void>& t) {
264     hasValue_ = t.hasValue_;
265     if (t.e_) {
266       e_ = folly::make_unique<exception_wrapper>(*t.e_);
267     }
268     return *this;
269   }
270   // Copy constructor
271   Try(const Try<void>& t) {
272     *this = t;
273   }
274
275   // If the Try contains an exception, throws it
276   void value() const { throwIfFailed(); }
277   // Dereference operator. If the Try contains an exception, throws it
278   void operator*() const { return value(); }
279
280   // If the Try contains an exception, throws it
281   inline void throwIfFailed() const;
282
283   // @returns False if the Try contains an exception, true otherwise
284   bool hasValue() const { return hasValue_; }
285   // @returns True if the Try contains an exception, false otherwise
286   bool hasException() const { return !hasValue_; }
287
288   // @returns True if the Try contains an exception of type Ex, false otherwise
289   template <class Ex>
290   bool hasException() const {
291     return hasException() && e_->is_compatible_with<Ex>();
292   }
293
294   /*
295    * @throws FutureException if the Try doesn't contain an exception
296    *
297    * @returns mutable reference to the exception contained by this Try
298    */
299   exception_wrapper& exception() {
300     if (UNLIKELY(!hasException())) {
301       throw FutureException("exception(): Try does not contain an exception");
302     }
303     return *e_;
304   }
305
306   const exception_wrapper& exception() const {
307     if (UNLIKELY(!hasException())) {
308       throw FutureException("exception(): Try does not contain an exception");
309     }
310     return *e_;
311   }
312
313   /*
314    * If the Try contains an exception and it is of type Ex, execute func(Ex)
315    *
316    * @param func a function that takes a single parameter of type const Ex&
317    *
318    * @returns True if the Try held an Ex and func was executed, false otherwise
319    */
320   template <class Ex, class F>
321   bool withException(F func) const {
322     if (!hasException()) {
323       return false;
324     }
325     return e_->with_exception<Ex>(std::move(func));
326   }
327
328   template <bool, typename R>
329   R get() {
330     return std::forward<R>(*this);
331   }
332
333  private:
334   bool hasValue_;
335   std::unique_ptr<exception_wrapper> e_{nullptr};
336 };
337
338 /*
339  * Extracts value from try and returns it. Throws if try contained an exception.
340  *
341  * @param t Try to extract value from
342  *
343  * @returns value contained in t
344  */
345 template <typename T>
346 T moveFromTry(Try<T>&& t);
347
348 /*
349  * Throws if try contained an exception.
350  *
351  * @param t Try to move from
352  */
353 void moveFromTry(Try<void>&& t);
354
355 /*
356  * @param f a function to execute and capture the result of (value or exception)
357  *
358  * @returns Try holding the result of f
359  */
360 template <typename F>
361 typename std::enable_if<
362   !std::is_same<typename std::result_of<F()>::type, void>::value,
363   Try<typename std::result_of<F()>::type>>::type
364 makeTryWith(F&& f);
365
366 /*
367  * Specialization of makeTryWith for void
368  *
369  * @param f a function to execute and capture the result of
370  *
371  * @returns Try<void> holding the result of f
372  */
373 template <typename F>
374 typename std::enable_if<
375   std::is_same<typename std::result_of<F()>::type, void>::value,
376   Try<void>>::type
377 makeTryWith(F&& f);
378
379 } // folly
380
381 #include <folly/futures/Try-inl.h>