ledger-core
Future.hpp
1 /*
2  *
3  * Future
4  * ledger-core
5  *
6  * Created by Pierre Pollastri on 18/01/2017.
7  *
8  * The MIT License (MIT)
9  *
10  * Copyright (c) 2016 Ledger
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy
13  * of this software and associated documentation files (the "Software"), to deal
14  * in the Software without restriction, including without limitation the rights
15  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16  * copies of the Software, and to permit persons to whom the Software is
17  * furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in all
20  * copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28  * SOFTWARE.
29  *
30  */
31 #ifndef LEDGER_CORE_FUTURE_HPP
32 #define LEDGER_CORE_FUTURE_HPP
33 #undef foreach
34 #include <exception>
35 #include <memory>
36 #include <functional>
37 #include <list>
38 #include "Deffered.hpp"
39 #include "api/ExecutionContext.hpp"
40 #include "utils/Exception.hpp"
41 #include "utils/ImmediateExecutionContext.hpp"
42 #include "traits/callback_traits.hpp"
43 #include "api/Error.hpp"
44 #include "traits/shared_ptr_traits.hpp"
45 
46 namespace ledger {
47  namespace core {
48 
49  template <typename T>
50  class Future {
51  typedef std::shared_ptr<api::ExecutionContext> Context;
52  public:
53  Future(const std::shared_ptr<Deffered<T>> &_defer) : _defer(_defer) {}
54  Future(const Future<T>& future) {
55  _defer = future._defer;
56  }
57 
58  Future(Future<T>&& future) : _defer(future._defer) {}
59  Future<T>& operator=(const Future<T>& future) {
60  if (this != &future)
61  _defer = future._defer;
62  return *this;
63  }
64  Future<T>& operator=(Future<T>&& future) {
65  if (this != &future)
66  _defer = future._defer;
67  return *this;
68  }
69 
70  template <typename R>
71  Future<R> map(const Context& context, std::function<R (const T&)> map) {
72  auto defer = Future<R>::make_deffered();
73  _defer->addCallback([defer, map] (const Try<T>& result) {
74  Try<R> r;
75  if (result.isSuccess()) {
76  r = Try<R>::from([map, result] () -> R {
77  return map(result.getValue());
78  });
79  } else {
80  r.fail(result.getFailure());
81  }
82  defer->setResult(r);
83  }, context);
84  return Future<R>(defer);
85  }
86 
87  template <typename R>
88  Future<std::shared_ptr<R>> mapPtr(const Context& context, std::function<std::shared_ptr<R> (const T&)> map) {
89  return this->template map<std::shared_ptr<R>>(context, map);
90  }
91 
92  template <typename R>
93  Future<R> flatMap(const Context& context, std::function<Future<R> (const T&)> map) {
94  auto deffer = Future<R>::make_deffered();
95  _defer->addCallback([deffer, map, context] (const Try<T>& result) {
96  if (result.isSuccess()) {
97  Try<Future<R>> r;
98  r = Try<Future<R>>::from([deffer, map, result] () -> Future<R> {
99  return map(result.getValue());
100  });
101  if (r.isSuccess()) {
102  Future<R> future = r.getValue();
103  future.onComplete(context, [deffer] (const Try<R>& finalResult) {
104  deffer->setResult(finalResult);
105  });
106  } else {
107  Try<R> re;
108  re.fail(r.getFailure());
109  deffer->setResult(re);
110  }
111  } else {
112  Try<R> r;
113  r.fail(result.getFailure());
114  deffer->setResult(r);
115  }
116  }, context);
117  return Future<R>(deffer);
118  }
119 
120  template <typename R>
121  Future<std::shared_ptr<R>> flatMapPtr(const Context& context, std::function<Future<std::shared_ptr<R>> (const T&)> map) {
122  return this->flatMap<std::shared_ptr<R>>(context, map);
123  }
124 
125  Future<T> recover(const Context& context, std::function<T (const Exception&)> f) {
126  auto deffer = Future<T>::make_deffered();
127  _defer->addCallback([deffer, f] (const Try<T>& result) {
128  if (result.isFailure()) {
129  deffer->setResult(Try<T>::from([f, result] () {
130  return f(result.getFailure());
131  }));
132  } else {
133  deffer->setResult(result);
134  }
135  }, context);
136  return Future<T>(deffer);
137  }
138 
139  Future<T> recoverWith(const Context& context, std::function<Future<T> (const Exception&)> f) {
140  auto deffer = Future<T>::make_deffered();
141  _defer->addCallback([deffer, f, context] (const Try<T>& result) {
142  if (result.isFailure()) {
143  auto future = Try<Future<T>>::from([f, result] () {
144  return f(result.getFailure());
145  });
146  if (future.isFailure()) {
147  Try<T> r;
148  r.fail(future.getFailure());
149  deffer->setResult(r);
150  } else {
151  Future<T> fut = future.getValue();
152  fut.onComplete(context, [deffer] (const Try<T>& finalResult) {
153  deffer->setResult(finalResult);
154  });
155  }
156  } else {
157  deffer->setResult(result);
158  }
159  }, context);
160  return Future<T>(deffer);
161  }
162 
163 
164  Future<T> fallback(const T& fallback) {
165  return recover(ImmediateExecutionContext::INSTANCE, [fallback] (const Exception& ex) {
166  return fallback;
167  });
168  }
169  Future<T> fallbackWith(Future<T> fallback) {
170  return recoverWith(ImmediateExecutionContext::INSTANCE, [fallback] (const Exception& ex) {
171  return fallback;
172  });
173  }
174 
175  Future<T> filter(const Context& context, std::function<bool (const T&)> f) {
176  return map<T>(context, [f] (const T& v) {
177  if (f(v)) {
178  return v;
179  } else {
180  throw Exception(api::ErrorCode::NO_SUCH_ELEMENT, "Value didn't pass the filter function.");
181  }
182  });
183  }
184 
185  void foreach(const Context& context, std::function<void (T&)> f) {
186  _defer->addCallback([f] (const Try<T>& result) {
187  if (result.isSuccess()) {
188  T value = result.getValue();
189  f(value);
190  }
191  }, context);
192  }
193 
194  Option<Try<T>> getValue() const {
195  return _defer->getValue();
196  }
197 
198  bool isCompleted() const {
199  return getValue().hasValue();
200  }
201 
202  Future<Exception> failed() {
203  auto deffer = Future<Exception>::make_deffered();
204  _defer->addCallback([deffer] (const Try<T>& result) {
205  if (result.isFailure()) {
206  deffer->setResult(Try<Exception>(result.getFailure()));
207  } else {
208  Try<Exception> r;
209  r.fail(Exception(api::ErrorCode::FUTURE_WAS_SUCCESSFULL, "Future was successful but rejected cause of the failed projection."));
210  deffer->setResult(r);
211  }
212  }, ImmediateExecutionContext::INSTANCE);
213  return Future<Exception>(deffer);
214  };
215 
216  void onComplete(const Context& context, std::function<void (const Try<T>&)> f) {
217  _defer->addCallback(f, context);
218  };
219 
220  template<typename Callback>
221  typename std::enable_if<has_on_callback_method<Callback, void (T&)>::value, void>::type
222  callback(const Context& context, std::shared_ptr<Callback> cb) {
223  onComplete(context, [cb] (const Try<T>& result) {
224  cb->onCallback(result.getValue());
225  });
226  };
227 
228  template<typename Callback>
229  typename std::enable_if<has_on_callback_method<Callback, void (const std::experimental::optional<T>&, const std::experimental::optional<api::Error>&)>::value, void>::type
230  callback(const Context& context, std::shared_ptr<Callback> cb) {
231  onComplete(context, [cb] (const Try<T>& result) {
232  if (result.isSuccess()) {
233  cb->onCallback(result.toOption().toOptional(), Option<api::Error>().toOptional());
234  } else {
235  cb->onCallback(Option<T>().toOptional(), Option<api::Error>(result.getFailure().toApiError()).toOptional());
236  }
237 
238  });
239  };
240 
241  template<typename Callback>
242  typename std::enable_if<is_shared_ptr<T>::value && has_on_callback_method<Callback, void (const T&, const std::experimental::optional<api::Error>&)>::value, void>::type
243  callback(const Context& context, std::shared_ptr<Callback> cb) {
244  onComplete(context, [cb] (const Try<T>& result) {
245  if (result.isSuccess()) {
246  cb->onCallback(result.getValue(), Option<api::Error>().toOptional());
247  } else {
248  cb->onCallback(nullptr, Option<api::Error>(result.getFailure().toApiError()).toOptional());
249  }
250 
251  });
252  };
253 
254 
255 
256  static Future<T> successful(T value) {
257  Promise<T> p;
258  p.success(value);
259  return p.getFuture();
260  }
261 
262  static Future<T> failure(Exception&& exception) {
263  Promise<T> p;
264  p.failure(exception);
265  return p.getFuture();
266  }
267 
268  static Future<T> failure(const Exception& exception) {
269  Promise<T> p;
270  p.failure(exception);
271  return p.getFuture();
272  }
273 
274  static Future<T> async(const Context& context, std::function<T ()> f) {
275  if (!context) {
276  throw make_exception(api::ErrorCode::ILLEGAL_STATE, "Context has been released before async operation");
277  }
278  auto deffer = make_deffered();
279  context->execute(make_runnable([deffer, f] () {
280  auto result = Try<T>::from([&] () -> T {
281  return f();
282  });
283  deffer->setResult(result);
284  }));
285  return Future<T>(deffer);
286  }
287 
288  static Future<T> async(const Context& context, std::function<Future<T> ()> f) {
289  if (!context) {
290  throw make_exception(api::ErrorCode::ILLEGAL_STATE, "Context has been released before async operation");
291  }
292  auto deffer = make_deffered();
293  context->execute(make_runnable([context, deffer, f] () {
294  auto result = Try<Future<T>>::from([&] () -> Future<T> {
295  return f();
296  });
297  if (result.isFailure()) {
298  deffer->setError(result.getFailure());
299  } else {
300  Future<T> f = result.getValue();
301  f.onComplete(context, [deffer] (const Try<T>& r) {
302  deffer->setResult(r);
303  });
304  }
305  }));
306  return Future<T>(deffer);
307  }
308 
309  static std::shared_ptr<Deffered<T>> make_deffered() {
310  auto d = new Deffered<T>();
311  return std::shared_ptr<Deffered<T>>(d);
312  };
313 
314  private:
315  std::shared_ptr<Deffered<T>> _defer;
316  };
317  template <typename T>
318  using FuturePtr = Future<std::shared_ptr<T>>;
319  }
320 }
321 
322 
323 #endif //LEDGER_CORE_FUTURE_HPP
Definition: Account.cpp:8
Definition: optional.hpp:177