1// Copyright (c) 2023 Klemens D. Morgenstern
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5#ifndef BOOST_COBALT_RESULT_HPP
6#define BOOST_COBALT_RESULT_HPP
7
8#include <boost/cobalt/concepts.hpp>
9
10#include <boost/system/result.hpp>
11
12namespace boost::cobalt
13{
14
15
16namespace detail
17{
18
19template<typename T>
20concept result_error =
21 requires (const T & t, const source_location & loc)
22 {
23 system::throw_exception_from_error(t, loc);
24 }
25 || // ADL
26 requires (const T & t, const source_location & loc)
27 {
28 throw_exception_from_error(t, loc);
29 }
30;
31
32}
33
34inline constexpr auto interpret_as_result(std::tuple<> &&)
35{
36 return system::result<void>();
37}
38
39template<typename Arg>
40auto interpret_as_result(std::tuple<Arg> && args)
41{
42 if constexpr (detail::result_error<Arg>)
43 {
44 if (std::get<0>(args))
45 return system::result<void, Arg>(system::in_place_error, std::get<0>(args));
46 else
47 return system::result<void, Arg>(system::in_place_value);
48 }
49
50 else
51 return system::result<Arg>(std::move(std::get<0>(args)));
52}
53
54template<typename First, typename ... Args>
55 requires (!detail::result_error<First> && sizeof...(Args) > 0u)
56auto interpret_as_result(std::tuple<First, Args...> && args) -> system::result<std::tuple<First, Args...>>
57{
58 return std::move(args);
59}
60
61template<detail::result_error Error, typename ... Args>
62 requires (sizeof...(Args) > 1u)
63auto interpret_as_result(std::tuple<Error, Args...> && args) -> system::result<std::tuple<Args...>, Error>
64{
65 if (std::get<0>(args))
66 return {system::in_place_error, std::move(std::get<0>(args))};
67 return {
68 system::in_place_value,
69 std::apply([](auto, auto && ... rest) {return std::make_tuple(std::move(rest)...);})
70 };
71}
72
73template<detail::result_error Error, typename Arg>
74auto interpret_as_result(std::tuple<Error, Arg> && args) -> system::result<Arg, Error>
75{
76 if (std::get<0>(args))
77 return {system::in_place_error, std::get<0>(args)};
78
79 return {system::in_place_value, std::get<1>(std::move(args))};
80}
81
82struct as_result_tag {};
83struct as_tuple_tag {};
84
85template<awaitable Aw>
86struct as_result_t
87{
88 as_result_t(Aw && aw) : aw_(std::forward<Aw>(aw)) {}
89
90 bool await_ready() { return aw_.await_ready();}
91 template<typename T>
92 auto await_suspend(std::coroutine_handle<T> h) { return aw_.await_suspend(h);}
93
94 auto await_resume()
95 {
96 if constexpr (requires {aw_.await_resume(as_result_tag{});})
97 return aw_.await_resume(as_result_tag{});
98 else
99 {
100 using type = decltype(aw_.await_resume());
101 if constexpr (std::is_void_v<type>)
102 {
103 using res_t = system::result<type, std::exception_ptr>;
104 try
105 {
106 aw_.await_resume();
107 return res_t{system::in_place_value};
108 }
109 catch (...)
110 {
111 return res_t{system::in_place_error, std::current_exception()};
112 }
113 }
114 else
115 {
116 using res_t = system::result<type, std::exception_ptr>;
117 try
118 {
119 return res_t{system::in_place_value, aw_.await_resume()};
120 }
121 catch (...)
122 {
123 return res_t{system::in_place_error, std::current_exception()};
124 }
125 }
126 }
127 }
128 private:
129 Aw aw_;
130};
131
132
133template<awaitable Aw>
134as_result_t(Aw &&) -> as_result_t<Aw>;
135
136template<awaitable_type Aw>
137auto as_result(Aw && aw) -> as_result_t<Aw>
138{
139 return as_result_t<Aw>(std::forward<Aw>(aw));
140}
141
142template<typename Aw>
143 requires requires (Aw && aw)
144 {
145 {std::forward<Aw>(aw).operator co_await()} -> awaitable_type;
146 }
147auto as_result(Aw && aw)
148{
149 struct lazy_tuple
150 {
151 Aw aw;
152 auto operator co_await ()
153 {
154 return as_result(std::forward<Aw>(aw).operator co_await());
155 }
156 };
157 return lazy_tuple{std::forward<Aw>(aw)};
158}
159
160template<typename Aw>
161 requires requires (Aw && aw)
162 {
163 {operator co_await(std::forward<Aw>(aw))} -> awaitable_type;
164 }
165auto as_result(Aw && aw)
166{
167 struct lazy_tuple
168 {
169 Aw aw;
170 auto operator co_await ()
171 {
172 return as_result(operator co_await(std::forward<Aw>(aw)));
173 }
174 };
175 return lazy_tuple{std::forward<Aw>(aw)};
176}
177
178
179
180template<awaitable Aw>
181struct as_tuple_t
182{
183 as_tuple_t(Aw && aw) : aw_(std::forward<Aw>(aw)) {}
184
185 bool await_ready() { return aw_.await_ready();}
186 template<typename T>
187 auto await_suspend(std::coroutine_handle<T> h) { return aw_.await_suspend(h);}
188
189 auto await_resume()
190 {
191 if constexpr (requires {aw_.await_resume(as_tuple_tag{});})
192 return aw_.await_resume(as_tuple_tag{});
193 else
194 {
195 using type = decltype(aw_.await_resume());
196 if constexpr (std::is_void_v<type>)
197 {
198 try
199 {
200 aw_.await_resume();
201 return std::make_tuple(args: std::exception_ptr());
202 }
203 catch (...)
204 {
205 return make_tuple_(std::current_exception());
206 }
207 }
208 else
209 {
210 try
211 {
212 return make_tuple_(std::exception_ptr(), aw_.await_resume());
213 }
214 catch (...)
215 {
216 return make_tuple_(std::current_exception(), type());
217 }
218 }
219 }
220 }
221 private:
222 template<typename ... Args>
223 std::tuple<std::exception_ptr, Args...> make_tuple_(std::exception_ptr ep, std::tuple<Args...> && tup)
224 {
225 return std::apply(
226 [&](auto ... args)
227 {
228 return std::make_tuple(std::move(ep), std::move(args)...);
229 }, std::move(tup));
230 }
231
232 template<typename Arg>
233 std::tuple<std::exception_ptr, Arg> make_tuple_(std::exception_ptr ep, Arg && arg)
234 {
235 return std::make_tuple(std::move(ep), std::move(arg));
236 }
237
238private:
239
240 Aw aw_;
241};
242
243
244template<awaitable Aw>
245as_tuple_t(Aw &&) -> as_tuple_t<Aw>;
246
247
248template<awaitable_type Aw>
249auto as_tuple(Aw && aw) -> as_tuple_t<Aw>
250{
251 return as_tuple_t<Aw>(std::forward<Aw>(aw));
252}
253
254template<typename Aw>
255 requires requires (Aw && aw)
256 {
257 {std::forward<Aw>(aw).operator co_await()} -> awaitable_type;
258 }
259auto as_tuple(Aw && aw)
260{
261 struct lazy_tuple
262 {
263 Aw aw;
264 auto operator co_await ()
265 {
266 return as_tuple(std::forward<Aw>(aw).operator co_await());
267 }
268 };
269 return lazy_tuple{std::forward<Aw>(aw)};
270}
271
272template<typename Aw>
273 requires requires (Aw && aw)
274 {
275 {operator co_await(std::forward<Aw>(aw))} -> awaitable_type;
276 }
277auto as_tuple(Aw && aw)
278{
279 struct lazy_tuple
280 {
281 Aw aw;
282 auto operator co_await ()
283 {
284 return as_tuple(operator co_await(std::forward<Aw>(aw)));
285 }
286 };
287 return lazy_tuple{std::forward<Aw>(aw)};
288}
289
290
291}
292
293#endif //BOOST_COBALT_RESULT_HPP
294

source code of boost/libs/cobalt/include/boost/cobalt/result.hpp