exception_ptr -> exception_wrapper migration
[folly.git] / folly / wangle / futures / Try.h
1 /*
2  * Copyright 2014 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/wangle/futures/Deprecated.h>
26 #include <folly/wangle/futures/WangleException.h>
27
28 namespace folly { namespace wangle {
29
30 template <class T>
31 class Try {
32   static_assert(!std::is_reference<T>::value,
33                 "Try may not be used with reference types");
34
35   enum class Contains {
36     VALUE,
37     EXCEPTION,
38     NOTHING,
39   };
40
41  public:
42   typedef T element_type;
43
44   Try() : contains_(Contains::NOTHING) {}
45   explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
46   explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
47   explicit Try(exception_wrapper e)
48     : contains_(Contains::EXCEPTION),
49       e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
50   explicit Try(std::exception_ptr ep) DEPRECATED
51     : contains_(Contains::EXCEPTION) {
52     try {
53       std::rethrow_exception(ep);
54     } catch (const std::exception& e) {
55       e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
56     } catch (...) {
57       e_ = folly::make_unique<exception_wrapper>(std::current_exception());
58     }
59   }
60
61   // move
62   Try(Try<T>&& t);
63   Try& operator=(Try<T>&& t);
64
65   // no copy
66   Try(const Try<T>& t) = delete;
67   Try& operator=(const Try<T>& t) = delete;
68
69   ~Try();
70
71   T& value();
72   const T& value() const;
73
74   void throwIfFailed() const;
75
76   const T& operator*() const { return value(); }
77         T& operator*()       { return value(); }
78
79   const T* operator->() const { return &value(); }
80         T* operator->()       { return &value(); }
81
82   bool hasValue() const { return contains_ == Contains::VALUE; }
83   bool hasException() const { return contains_ == Contains::EXCEPTION; }
84
85   template <class Ex>
86   bool hasException() const {
87     return hasException() && e_->is_compatible_with<Ex>();
88   }
89
90   exception_wrapper& exception() {
91     if (UNLIKELY(!hasException())) {
92       throw WangleException("exception(): Try does not contain an exception");
93     }
94     return *e_;
95   }
96
97   template <class Ex, class F>
98   bool withException(F func) const {
99     if (!hasException()) {
100       return false;
101     }
102     return e_->with_exception<Ex>(std::move(func));
103   }
104
105  private:
106   Contains contains_;
107   union {
108     T value_;
109     std::unique_ptr<exception_wrapper> e_;
110   };
111 };
112
113 template <>
114 class Try<void> {
115  public:
116   Try() : hasValue_(true) {}
117   explicit Try(exception_wrapper e)
118     : hasValue_(false),
119       e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
120   explicit Try(std::exception_ptr ep) DEPRECATED : hasValue_(false) {
121     try {
122       std::rethrow_exception(ep);
123     } catch (const std::exception& e) {
124       e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
125     } catch (...) {
126       e_ = folly::make_unique<exception_wrapper>(std::current_exception());
127     }
128   }
129
130   Try& operator=(const Try<void>& t) {
131     hasValue_ = t.hasValue_;
132     if (t.e_) {
133       e_ = folly::make_unique<exception_wrapper>(*t.e_);
134     }
135     return *this;
136   }
137   Try(const Try<void>& t) {
138     *this = t;
139   }
140
141   void value() const { throwIfFailed(); }
142   void operator*() const { return value(); }
143
144   inline void throwIfFailed() const;
145
146   bool hasValue() const { return hasValue_; }
147   bool hasException() const { return !hasValue_; }
148
149   template <class Ex>
150   bool hasException() const {
151     return hasException() && e_->is_compatible_with<Ex>();
152   }
153
154   exception_wrapper& exception() {
155     if (UNLIKELY(!hasException())) {
156       throw WangleException("exception(): Try does not contain an exception");
157     }
158     return *e_;
159   }
160
161   template <class Ex, class F>
162   bool withException(F func) const {
163     if (!hasException()) {
164       return false;
165     }
166     return e_->with_exception<Ex>(std::move(func));
167   }
168
169  private:
170   bool hasValue_;
171   std::unique_ptr<exception_wrapper> e_{nullptr};
172 };
173
174 /**
175  * Extracts value from try and returns it. Throws if try contained an exception.
176  */
177 template <typename T>
178 T moveFromTry(wangle::Try<T>&& t);
179
180 /**
181  * Throws if try contained an exception.
182  */
183 void moveFromTry(wangle::Try<void>&& t);
184
185 /**
186  * Constructs Try based on the result of execution of function f (e.g. result
187  * or exception).
188  */
189 template <typename F>
190 typename std::enable_if<
191   !std::is_same<typename std::result_of<F()>::type, void>::value,
192   Try<typename std::result_of<F()>::type>>::type
193 makeTryFunction(F&& f);
194
195 /**
196  * makeTryFunction specialization for void functions.
197  */
198 template <typename F>
199 typename std::enable_if<
200   std::is_same<typename std::result_of<F()>::type, void>::value,
201   Try<void>>::type
202 makeTryFunction(F&& f);
203
204
205 }}
206
207 #include <folly/wangle/futures/Try-inl.h>