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