2 * Copyright 2015 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/futures/Deprecated.h>
26 #include <folly/futures/FutureException.h>
27 #include <folly/futures/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 * There is a specialization, Try<void>, which represents either success
43 static_assert(!std::is_reference<T>::value,
44 "Try may not be used with reference types");
54 * The value type for the Try
56 typedef T element_type;
59 * Construct an empty Try
61 Try() : contains_(Contains::NOTHING) {}
64 * Construct a Try with a value by copy
66 * @param v The value to copy in
68 explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
71 * Construct a Try with a value by move
73 * @param v The value to move in
75 explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
78 * Construct a Try with an exception_wrapper
80 * @param e The exception_wrapper
82 explicit Try(exception_wrapper e)
83 : contains_(Contains::EXCEPTION),
84 e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
88 * Construct a Try with an exception_pointer
90 * @param ep The exception_pointer. Will be rethrown.
92 explicit Try(std::exception_ptr ep) DEPRECATED
93 : contains_(Contains::EXCEPTION) {
95 std::rethrow_exception(ep);
96 } catch (const std::exception& e) {
97 e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
99 e_ = folly::make_unique<exception_wrapper>(std::current_exception());
106 Try& operator=(Try<T>&& t);
109 Try(const Try<T>& t) = delete;
111 Try& operator=(const Try<T>& t) = delete;
116 * Get a mutable reference to the contained value. If the Try contains an
117 * exception it will be rethrown.
119 * @returns mutable reference to the contained value
123 * Get a const reference to the contained value. If the Try contains an
124 * exception it will be rethrown.
126 * @returns const reference to the contained value
128 const T& value() const;
131 * If the Try contains an exception, rethrow it. Otherwise do nothing.
133 void throwIfFailed() const;
136 * Const dereference operator. If the Try contains an exception it will be
139 * @returns const reference to the contained value
141 const T& operator*() const { return value(); }
143 * Dereference operator. If the Try contains an exception it will be rethrown.
145 * @returns mutable reference to the contained value
147 T& operator*() { return value(); }
150 * Const arrow operator. If the Try contains an exception it will be
153 * @returns const reference to the contained value
155 const T* operator->() const { return &value(); }
157 * Arrow operator. If the Try contains an exception it will be rethrown.
159 * @returns mutable reference to the contained value
161 T* operator->() { return &value(); }
164 * @returns True if the Try contains a value, false otherwise
166 bool hasValue() const { return contains_ == Contains::VALUE; }
168 * @returns True if the Try contains an exception, false otherwise
170 bool hasException() const { return contains_ == Contains::EXCEPTION; }
173 * @returns True if the Try contains an exception of type Ex, false otherwise
176 bool hasException() const {
177 return hasException() && e_->is_compatible_with<Ex>();
180 exception_wrapper& exception() {
181 if (UNLIKELY(!hasException())) {
182 throw FutureException("exception(): Try does not contain an exception");
187 const exception_wrapper& exception() const {
188 if (UNLIKELY(!hasException())) {
189 throw FutureException("exception(): Try does not contain an exception");
195 * If the Try contains an exception and it is of type Ex, execute func(Ex)
197 * @param func a function that takes a single parameter of type const Ex&
199 * @returns True if the Try held an Ex and func was executed, false otherwise
201 template <class Ex, class F>
202 bool withException(F func) const {
203 if (!hasException()) {
206 return e_->with_exception<Ex>(std::move(func));
209 template <bool isTry, typename R>
210 typename std::enable_if<isTry, R>::type get() {
211 return std::forward<R>(*this);
214 template <bool isTry, typename R>
215 typename std::enable_if<!isTry, R>::type get() {
216 return std::forward<R>(value());
223 std::unique_ptr<exception_wrapper> e_;
228 * Specialization of Try for void value type. Encapsulates either success or an
234 // Construct a Try holding a successful and void result
235 Try() : hasValue_(true) {}
238 * Construct a Try with an exception_wrapper
240 * @param e The exception_wrapper
242 explicit Try(exception_wrapper e)
244 e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
248 * Construct a Try with an exception_pointer
250 * @param ep The exception_pointer. Will be rethrown.
252 explicit Try(std::exception_ptr ep) DEPRECATED : hasValue_(false) {
254 std::rethrow_exception(ep);
255 } catch (const std::exception& e) {
256 e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
258 e_ = folly::make_unique<exception_wrapper>(std::current_exception());
263 Try& operator=(const Try<void>& t) {
264 hasValue_ = t.hasValue_;
266 e_ = folly::make_unique<exception_wrapper>(*t.e_);
271 Try(const Try<void>& t) {
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(); }
280 // If the Try contains an exception, throws it
281 inline void throwIfFailed() const;
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_; }
288 // @returns True if the Try contains an exception of type Ex, false otherwise
290 bool hasException() const {
291 return hasException() && e_->is_compatible_with<Ex>();
295 * @throws FutureException if the Try doesn't contain an exception
297 * @returns mutable reference to the exception contained by this Try
299 exception_wrapper& exception() {
300 if (UNLIKELY(!hasException())) {
301 throw FutureException("exception(): Try does not contain an exception");
306 const exception_wrapper& exception() const {
307 if (UNLIKELY(!hasException())) {
308 throw FutureException("exception(): Try does not contain an exception");
314 * If the Try contains an exception and it is of type Ex, execute func(Ex)
316 * @param func a function that takes a single parameter of type const Ex&
318 * @returns True if the Try held an Ex and func was executed, false otherwise
320 template <class Ex, class F>
321 bool withException(F func) const {
322 if (!hasException()) {
325 return e_->with_exception<Ex>(std::move(func));
328 template <bool, typename R>
330 return std::forward<R>(*this);
335 std::unique_ptr<exception_wrapper> e_{nullptr};
339 * Extracts value from try and returns it. Throws if try contained an exception.
341 * @param t Try to extract value from
343 * @returns value contained in t
345 template <typename T>
346 T moveFromTry(Try<T>&& t);
349 * Throws if try contained an exception.
351 * @param t Try to move from
353 void moveFromTry(Try<void>&& t);
356 * @param f a function to execute and capture the result of (value or exception)
358 * @returns Try holding the result of f
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 makeTryFunction(F&& f);
367 * Specialization of makeTryFunction for void
369 * @param f a function to execute and capture the result of
371 * @returns Try<void> holding the result of f
373 template <typename F>
374 typename std::enable_if<
375 std::is_same<typename std::result_of<F()>::type, void>::value,
377 makeTryFunction(F&& f);
381 #include <folly/futures/Try-inl.h>