2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <type_traits>
22 #include <folly/ExceptionWrapper.h>
23 #include <folly/Likely.h>
24 #include <folly/Memory.h>
25 #include <folly/Portability.h>
26 #include <folly/futures/FutureException.h>
27 #include <folly/Unit.h>
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.
38 * To represent success or a captured exception, use Try<Unit>
42 static_assert(!std::is_reference<T>::value,
43 "Try may not be used with reference types");
53 * The value type for the Try
55 typedef T element_type;
58 * Construct an empty Try
60 Try() : contains_(Contains::NOTHING) {}
63 * Construct a Try with a value by copy
65 * @param v The value to copy in
67 explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
70 * Construct a Try with a value by move
72 * @param v The value to move in
74 explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
76 /// Implicit conversion from Try<void> to Try<Unit>
77 template <class T2 = T>
79 Try(typename std::enable_if<std::is_same<Unit, T2>::value,
80 Try<void> const&>::type t);
83 * Construct a Try with an exception_wrapper
85 * @param e The exception_wrapper
87 explicit Try(exception_wrapper e)
88 : contains_(Contains::EXCEPTION),
89 e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
93 * Construct a Try with an exception_pointer
95 * @param ep The exception_pointer. Will be rethrown.
97 FOLLY_DEPRECATED("use Try(exception_wrapper)")
98 explicit Try(std::exception_ptr ep)
99 : contains_(Contains::EXCEPTION) {
101 std::rethrow_exception(ep);
102 } catch (const std::exception& e) {
103 e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
105 e_ = folly::make_unique<exception_wrapper>(std::current_exception());
110 Try(Try<T>&& t) noexcept;
112 Try& operator=(Try<T>&& t) noexcept;
117 Try& operator=(const Try& t);
122 * Get a mutable reference to the contained value. If the Try contains an
123 * exception it will be rethrown.
125 * @returns mutable reference to the contained value
129 * Get a rvalue reference to the contained value. If the Try contains an
130 * exception it will be rethrown.
132 * @returns rvalue reference to the contained value
136 * Get a const reference to the contained value. If the Try contains an
137 * exception it will be rethrown.
139 * @returns const reference to the contained value
141 const T& value() const&;
144 * If the Try contains an exception, rethrow it. Otherwise do nothing.
146 void throwIfFailed() const;
149 * Const dereference operator. If the Try contains an exception it will be
152 * @returns const reference to the contained value
154 const T& operator*() const { return value(); }
156 * Dereference operator. If the Try contains an exception it will be rethrown.
158 * @returns mutable reference to the contained value
160 T& operator*() { return value(); }
163 * Const arrow operator. If the Try contains an exception it will be
166 * @returns const reference to the contained value
168 const T* operator->() const { return &value(); }
170 * Arrow operator. If the Try contains an exception it will be rethrown.
172 * @returns mutable reference to the contained value
174 T* operator->() { return &value(); }
177 * @returns True if the Try contains a value, false otherwise
179 bool hasValue() const { return contains_ == Contains::VALUE; }
181 * @returns True if the Try contains an exception, false otherwise
183 bool hasException() const { return contains_ == Contains::EXCEPTION; }
186 * @returns True if the Try contains an exception of type Ex, false otherwise
189 bool hasException() const {
190 return hasException() && e_->is_compatible_with<Ex>();
193 exception_wrapper& exception() {
194 if (UNLIKELY(!hasException())) {
195 throw FutureException("exception(): Try does not contain an exception");
200 const exception_wrapper& exception() const {
201 if (UNLIKELY(!hasException())) {
202 throw FutureException("exception(): Try does not contain an exception");
208 * If the Try contains an exception and it is of type Ex, execute func(Ex)
210 * @param func a function that takes a single parameter of type const Ex&
212 * @returns True if the Try held an Ex and func was executed, false otherwise
214 template <class Ex, class F>
215 bool withException(F func) const {
216 if (!hasException()) {
219 return e_->with_exception(std::move(func));
222 template <bool isTry, typename R>
223 typename std::enable_if<isTry, R>::type get() {
224 return std::forward<R>(*this);
227 template <bool isTry, typename R>
228 typename std::enable_if<!isTry, R>::type get() {
229 return std::forward<R>(value());
236 std::unique_ptr<exception_wrapper> e_;
241 * Specialization of Try for void value type. Encapsulates either success or an
248 * The value type for the Try
250 typedef void element_type;
252 // Construct a Try holding a successful and void result
253 Try() : hasValue_(true) {}
256 * Construct a Try with an exception_wrapper
258 * @param e The exception_wrapper
260 explicit Try(exception_wrapper e)
262 e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
266 * Construct a Try with an exception_pointer
268 * @param ep The exception_pointer. Will be rethrown.
270 FOLLY_DEPRECATED("use Try(exception_wrapper)")
271 explicit Try(std::exception_ptr ep) : hasValue_(false) {
273 std::rethrow_exception(ep);
274 } catch (const std::exception& e) {
275 e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
277 e_ = folly::make_unique<exception_wrapper>(std::current_exception());
282 Try& operator=(const Try<void>& t) {
283 hasValue_ = t.hasValue_;
285 e_ = folly::make_unique<exception_wrapper>(*t.e_);
290 Try(const Try<void>& t) {
294 // If the Try contains an exception, throws it
295 void value() const { throwIfFailed(); }
296 // Dereference operator. If the Try contains an exception, throws it
297 void operator*() const { return value(); }
299 // If the Try contains an exception, throws it
300 inline void throwIfFailed() const;
302 // @returns False if the Try contains an exception, true otherwise
303 bool hasValue() const { return hasValue_; }
304 // @returns True if the Try contains an exception, false otherwise
305 bool hasException() const { return !hasValue_; }
307 // @returns True if the Try contains an exception of type Ex, false otherwise
309 bool hasException() const {
310 return hasException() && e_->is_compatible_with<Ex>();
314 * @throws FutureException if the Try doesn't contain an exception
316 * @returns mutable reference to the exception contained by this Try
318 exception_wrapper& exception() {
319 if (UNLIKELY(!hasException())) {
320 throw FutureException("exception(): Try does not contain an exception");
325 const exception_wrapper& exception() const {
326 if (UNLIKELY(!hasException())) {
327 throw FutureException("exception(): Try does not contain an exception");
333 * If the Try contains an exception and it is of type Ex, execute func(Ex)
335 * @param func a function that takes a single parameter of type const Ex&
337 * @returns True if the Try held an Ex and func was executed, false otherwise
339 template <class Ex, class F>
340 bool withException(F func) const {
341 if (!hasException()) {
344 return e_->with_exception(std::move(func));
347 template <bool, typename R>
349 return std::forward<R>(*this);
354 std::unique_ptr<exception_wrapper> e_{nullptr};
358 * Extracts value from try and returns it. Throws if try contained an exception.
360 * @param t Try to extract value from
362 * @returns value contained in t
364 template <typename T>
365 T moveFromTry(Try<T>& t);
368 * Throws if try contained an exception.
370 * @param t Try to move from
372 void moveFromTry(Try<void>& t);
375 * @param f a function to execute and capture the result of (value or exception)
377 * @returns Try holding the result of f
379 template <typename F>
380 typename std::enable_if<
381 !std::is_same<typename std::result_of<F()>::type, void>::value,
382 Try<typename std::result_of<F()>::type>>::type
386 * Specialization of makeTryWith for void return
388 * @param f a function to execute and capture the result of
390 * @returns Try<void> holding the result of f
392 template <typename F>
393 typename std::enable_if<
394 std::is_same<typename std::result_of<F()>::type, void>::value,
400 #include <folly/futures/Try-inl.h>