Make fbstring libgcc-safe
[folly.git] / folly / wangle / Later-inl.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 "folly/wangle/Executor.h"
20 #include "folly/wangle/Future.h"
21 #include "folly/Optional.h"
22
23 namespace folly { namespace wangle {
24
25 template <typename T>
26 struct isLater {
27   static const bool value = false;
28 };
29
30 template <typename T>
31 struct isLater<Later<T> > {
32   static const bool value = true;
33 };
34
35 template <typename T>
36 struct isLaterOrFuture {
37   static const bool value = false;
38 };
39
40 template <typename T>
41 struct isLaterOrFuture<Later<T>> {
42   static const bool value = true;
43 };
44
45 template <typename T>
46 struct isLaterOrFuture<Future<T>> {
47   static const bool value = true;
48 };
49
50 template <typename T>
51 template <class U, class Unused, class Unused2>
52 Later<T>::Later() {
53   future_ = starter_.getFuture();
54 }
55
56 template <typename T>
57 Later<T>::Later(Promise<void>&& starter)
58   : starter_(std::forward<Promise<void>>(starter)) { }
59
60 template <class T>
61 template <class U, class Unused, class Unused2>
62 Later<T>::Later(U&& input) {
63   folly::MoveWrapper<Promise<U>> promise;
64   folly::MoveWrapper<U> inputm(std::forward<U>(input));
65   future_ = promise->getFuture();
66   starter_.getFuture().then([=](Try<void>&& t) mutable {
67     promise->setValue(std::move(*inputm));
68   });
69 }
70
71 template <class T>
72 template <class U, class Unused, class Unused2>
73 Later<T>::Later(std::function<void(std::function<void(U&&)>&&)>&& fn) {
74   folly::MoveWrapper<Promise<U>> promise;
75   future_ = promise->getFuture();
76   starter_.getFuture().then([=](Try<void>&& t) mutable {
77     fn([=](U&& output) mutable {
78       promise->setValue(std::move(output));
79     });
80   });
81 }
82
83 template <class T>
84 template <class F>
85 typename std::enable_if<
86   !isLaterOrFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
87   Later<typename std::result_of<F(Try<T>&&)>::type> >::type
88 Later<T>::then(F&& fn) {
89   typedef typename std::result_of<F(Try<T>&&)>::type B;
90
91   Later<B> later(std::move(starter_));
92   later.future_ = future_->then(std::forward<F>(fn));
93   return later;
94 }
95
96 template <class T>
97 template <class F>
98 typename std::enable_if<
99   isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
100   Later<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
101 Later<T>::then(F&& fn) {
102   typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
103
104   Later<B> later(std::move(starter_));
105   later.future_ = future_->then(std::move(fn));
106   return later;
107 }
108
109 template <class T>
110 template <class F>
111 typename std::enable_if<
112   isLater<typename std::result_of<F(Try<T>&&)>::type>::value,
113   Later<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
114 Later<T>::then(F&& fn) {
115   typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
116
117   folly::MoveWrapper<Promise<B>> promise;
118   folly::MoveWrapper<F> fnm(std::move(fn));
119   Later<B> later(std::move(starter_));
120   later.future_ = promise->getFuture();
121   future_->then([=](Try<T>&& t) mutable {
122     (*fnm)(std::move(t))
123     .then([=](Try<B>&& t2) mutable {
124       promise->fulfilTry(std::move(t2));
125     })
126     .launch();
127   });
128   return later;
129 }
130
131 template <class T>
132 Later<T> Later<T>::via(Executor* executor) {
133   Promise<T> promise;
134   Later<T> later(std::move(starter_));
135   later.future_ = promise.getFuture();
136   future_->executeWith(executor, std::move(promise));
137   return later;
138 }
139
140 template <class T>
141 Future<T> Later<T>::launch() {
142   starter_.setValue();
143   return std::move(*future_);
144 }
145
146 }}