2 * Copyright 2014 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/WangleException.h>
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.
37 * There is a specialization, Try<void>, which represents either success
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)) {}
77 * Construct a Try with an exception_wrapper
79 * @param e The exception_wrapper
81 explicit Try(exception_wrapper e)
82 : contains_(Contains::EXCEPTION),
83 e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
87 * Construct a Try with an exception_pointer
89 * @param ep The exception_pointer. Will be rethrown.
91 explicit Try(std::exception_ptr ep) DEPRECATED
92 : contains_(Contains::EXCEPTION) {
94 std::rethrow_exception(ep);
95 } catch (const std::exception& e) {
96 e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
98 e_ = folly::make_unique<exception_wrapper>(std::current_exception());
105 Try& operator=(Try<T>&& t);
108 Try(const Try<T>& t) = delete;
110 Try& operator=(const Try<T>& t) = delete;
115 * Get a mutable reference to the contained value. If the Try contains an
116 * exception it will be rethrown.
118 * @returns mutable reference to the contained value
122 * Get a const reference to the contained value. If the Try contains an
123 * exception it will be rethrown.
125 * @returns const reference to the contained value
127 const T& value() const;
130 * If the Try contains an exception, rethrow it. Otherwise do nothing.
132 void throwIfFailed() const;
135 * Const dereference operator. If the Try contains an exception it will be
138 * @returns const reference to the contained value
140 const T& operator*() const { return value(); }
142 * Dereference operator. If the Try contains an exception it will be rethrown.
144 * @returns mutable reference to the contained value
146 T& operator*() { return value(); }
149 * Const arrow 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 * Arrow 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 * @returns True if the Try contains a value, false otherwise
165 bool hasValue() const { return contains_ == Contains::VALUE; }
167 * @returns True if the Try contains an exception, false otherwise
169 bool hasException() const { return contains_ == Contains::EXCEPTION; }
172 * @returns True if the Try contains an exception of type Ex, false otherwise
175 bool hasException() const {
176 return hasException() && e_->is_compatible_with<Ex>();
179 exception_wrapper& exception() {
180 if (UNLIKELY(!hasException())) {
181 throw WangleException("exception(): Try does not contain an exception");
187 * If the Try contains an exception and it is of type Ex, execute func(Ex)
189 * @param func a function that takes a single parameter of type const Ex&
191 * @returns True if the Try held an Ex and func was executed, false otherwise
193 template <class Ex, class F>
194 bool withException(F func) const {
195 if (!hasException()) {
198 return e_->with_exception<Ex>(std::move(func));
205 std::unique_ptr<exception_wrapper> e_;
210 * Specialization of Try for void value type. Encapsulates either success or an
216 // Construct a Try holding a successful and void result
217 Try() : hasValue_(true) {}
220 * Construct a Try with an exception_wrapper
222 * @param e The exception_wrapper
224 explicit Try(exception_wrapper e)
226 e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
230 * Construct a Try with an exception_pointer
232 * @param ep The exception_pointer. Will be rethrown.
234 explicit Try(std::exception_ptr ep) DEPRECATED : hasValue_(false) {
236 std::rethrow_exception(ep);
237 } catch (const std::exception& e) {
238 e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
240 e_ = folly::make_unique<exception_wrapper>(std::current_exception());
245 Try& operator=(const Try<void>& t) {
246 hasValue_ = t.hasValue_;
248 e_ = folly::make_unique<exception_wrapper>(*t.e_);
253 Try(const Try<void>& t) {
257 // If the Try contains an exception, throws it
258 void value() const { throwIfFailed(); }
259 // Dereference operator. If the Try contains an exception, throws it
260 void operator*() const { return value(); }
262 // If the Try contains an exception, throws it
263 inline void throwIfFailed() const;
265 // @returns False if the Try contains an exception, true otherwise
266 bool hasValue() const { return hasValue_; }
267 // @returns True if the Try contains an exception, false otherwise
268 bool hasException() const { return !hasValue_; }
270 // @returns True if the Try contains an exception of type Ex, false otherwise
272 bool hasException() const {
273 return hasException() && e_->is_compatible_with<Ex>();
277 * @throws WangleException if the Try doesn't contain an exception
279 * @returns mutable reference to the exception contained by this Try
281 exception_wrapper& exception() {
282 if (UNLIKELY(!hasException())) {
283 throw WangleException("exception(): Try does not contain an exception");
289 * If the Try contains an exception and it is of type Ex, execute func(Ex)
291 * @param func a function that takes a single parameter of type const Ex&
293 * @returns True if the Try held an Ex and func was executed, false otherwise
295 template <class Ex, class F>
296 bool withException(F func) const {
297 if (!hasException()) {
300 return e_->with_exception<Ex>(std::move(func));
305 std::unique_ptr<exception_wrapper> e_{nullptr};
309 * Extracts value from try and returns it. Throws if try contained an exception.
311 * @param t Try to extract value from
313 * @returns value contained in t
315 template <typename T>
316 T moveFromTry(Try<T>&& t);
319 * Throws if try contained an exception.
321 * @param t Try to move from
323 void moveFromTry(Try<void>&& t);
326 * @param f a function to execute and capture the result of (value or exception)
328 * @returns Try holding the result of f
330 template <typename F>
331 typename std::enable_if<
332 !std::is_same<typename std::result_of<F()>::type, void>::value,
333 Try<typename std::result_of<F()>::type>>::type
334 makeTryFunction(F&& f);
337 * Specialization of makeTryFunction for void
339 * @param f a function to execute and capture the result of
341 * @returns Try<void> holding the result of f
343 template <typename F>
344 typename std::enable_if<
345 std::is_same<typename std::result_of<F()>::type, void>::value,
347 makeTryFunction(F&& f);
351 #include <folly/futures/Try-inl.h>