6 #ifndef IROHA_RESULT_HPP 7 #define IROHA_RESULT_HPP 12 #include <type_traits> 14 #include <boost/optional.hpp> 15 #include <boost/variant.hpp> 41 struct Value : ValueBase {
45 typename = std::enable_if_t<std::is_constructible<T, Args...>::value>>
46 Value(Args &&... args) : value(
std::forward<Args>(args)...) {}
55 struct Value<void> {};
60 struct Error : ErrorBase {
64 typename = std::enable_if_t<std::is_constructible<E, Args...>::value>>
65 Error(Args &&... args) : error(
std::forward<Args>(args)...) {}
74 struct Error<void> {};
76 class ResultException :
public std::runtime_error {
77 using std::runtime_error::runtime_error;
88 template <
typename V,
typename E>
89 class Result : ResultBase,
public boost::variant<Value<V>, Error<E>> {
90 template <
typename OV,
typename OE>
93 using variant_type = boost::variant<Value<V>, Error<E>>;
94 using variant_type::variant_type;
97 using ValueType = Value<V>;
98 using ErrorType = Error<E>;
100 using ValueInnerType = V;
101 using ErrorInnerType = E;
105 template <
typename OV,
typename OE>
106 Result(Result<OV, OE> r)
107 : Result(visit_in_place(
std::move(r),
108 [](Value<OV> &v) -> Result<V, E> {
109 return ValueType{std::move(v.value)};
111 [](Value<OV> &&v) -> Result<V, E> {
112 return ValueType{std::move(v.value)};
114 [](Error<OE> &e) -> Result<V, E> {
115 return ErrorType{std::move(e.error)};
117 [](Error<OE> &&e) -> Result<V, E> {
118 return ErrorType{std::move(e.error)};
130 template <
typename ValueMatch,
typename ErrorMatch>
131 constexpr
auto match(ValueMatch &&value_func, ErrorMatch &&error_func) & {
132 return visit_in_place(*
this,
133 [f = std::forward<ValueMatch>(value_func)](
134 ValueType &v) {
return f(v); },
135 [f = std::forward<ErrorMatch>(error_func)](
136 ErrorType &e) {
return f(e); });
142 template <
typename ValueMatch,
typename ErrorMatch>
143 constexpr
auto match(ValueMatch &&value_func,
144 ErrorMatch &&error_func) && {
145 return visit_in_place(*
this,
146 [f = std::forward<ValueMatch>(value_func)](
147 ValueType &v) {
return f(std::move(v)); },
148 [f = std::forward<ErrorMatch>(error_func)](
149 ErrorType &e) {
return f(std::move(e)); });
155 template <
typename ValueMatch,
typename ErrorMatch>
156 constexpr
auto match(ValueMatch &&value_func,
157 ErrorMatch &&error_func)
const & {
158 return visit_in_place(*
this,
159 [f = std::forward<ValueMatch>(value_func)](
160 const ValueType &v) {
return f(v); },
161 [f = std::forward<ErrorMatch>(error_func)](
162 const ErrorType &e) {
return f(e); });
176 template <
typename Value>
177 constexpr Result<Value, E> and_res(
const Result<Value, E> &new_res)
const 179 return visit_in_place(
181 [res = new_res](ValueType) {
return res; },
182 [](ErrorType err) -> Result<Value, E> {
return err; });
196 template <
typename Value>
197 constexpr Result<Value, E> or_res(
const Result<Value, E> &new_res)
const 199 return visit_in_place(
201 [](ValueType val) -> Result<Value, E> {
return val; },
202 [res = new_res](ErrorType) {
return res; });
205 using AssumeValueHelper =
206 std::conditional_t<std::is_void<ValueInnerType>::value,
211 template <
typename ReturnType = const AssumeValueHelper &>
212 std::enable_if_t<not std::is_void<ValueInnerType>::value, ReturnType>
213 assumeValue() const & {
214 const auto *val = boost::get<ValueType>(
this);
215 if (val !=
nullptr) {
218 throw ResultException(
"Value expected, but got an Error.");
222 template <
typename ReturnType = AssumeValueHelper &>
223 std::enable_if_t<not std::is_void<ValueInnerType>::value, ReturnType>
225 auto val = boost::get<ValueType>(
this);
226 if (val !=
nullptr) {
229 throw ResultException(
"Value expected, but got an Error.");
233 template <
typename ReturnType = AssumeValueHelper &&>
234 std::enable_if_t<not std::is_void<ValueInnerType>::value, ReturnType>
236 auto val = boost::get<ValueType>(
this);
237 if (val !=
nullptr) {
238 return std::move(val->value);
240 throw ResultException(
"Value expected, but got an Error.");
243 using AssumeErrorHelper =
244 std::conditional_t<std::is_void<ErrorInnerType>::value,
249 template <
typename ReturnType = const AssumeErrorHelper &>
250 std::enable_if_t<not std::is_void<ErrorInnerType>::value, ReturnType>
251 assumeError() const & {
252 const auto *err = boost::get<ErrorType>(
this);
253 if (err !=
nullptr) {
256 throw ResultException(
"Error expected, but got a Value.");
260 template <
typename ReturnType = AssumeErrorHelper &>
261 std::enable_if_t<not std::is_void<ErrorInnerType>::value, ReturnType>
263 auto err = boost::get<ErrorType>(
this);
264 if (err !=
nullptr) {
267 throw ResultException(
"Error expected, but got a Value.");
271 template <
typename ReturnType = AssumeErrorHelper &&>
272 std::enable_if_t<not std::is_void<ErrorInnerType>::value, ReturnType>
274 auto err = boost::get<ErrorType>(
this);
275 if (err !=
nullptr) {
276 return std::move(err->error);
278 throw ResultException(
"Error expected, but got a Value.");
282 template <
typename ResultType>
283 using ValueOf =
typename std::decay_t<ResultType>::ValueType;
284 template <
typename ResultType>
285 using ErrorOf =
typename std::decay_t<ResultType>::ErrorType;
293 template <
typename Err1,
typename Err2,
typename V,
typename Fn>
294 Result<V, Err1> map_error(
const Result<V, Err2> &res, Fn &&map) noexcept {
295 return visit_in_place(res,
296 [](Value<V> val) -> Result<V, Err1> {
return val; },
297 [map](Error<Err2> err) -> Result<V, Err1> {
298 return Error<Err1>{map(err.error)};
303 inline Value<void> makeValue() {
304 return Value<void>{};
307 template <
typename T>
308 Value<T> makeValue(T &&value) {
309 return Value<T>{std::forward<T>(value)};
312 inline Error<void> makeError() {
313 return Error<void>{};
316 template <
typename E>
317 Error<E> makeError(E &&error) {
318 return Error<E>{std::forward<E>(error)};
321 template <
typename T>
322 constexpr
bool isResult =
323 std::is_base_of<ResultBase, std::decay_t<T>>::value;
324 template <
typename T>
325 constexpr
bool isValue = std::is_base_of<ValueBase, std::decay_t<T>>::value;
326 template <
typename T>
327 constexpr
bool isError = std::is_base_of<ErrorBase, std::decay_t<T>>::value;
337 template <
typename Transformed,
typename ErrorType,
typename =
void>
338 struct BindReturnType;
341 template <
typename Transformed,
typename ErrorType>
342 struct BindReturnType<
345 typename
std::enable_if_t<
346 not isResult<Transformed> and not isValue<Transformed>>> {
347 using ReturnType = Result<Transformed, ErrorType>;
348 static ReturnType makeValue(Transformed &&result) {
349 return iroha::expected::makeValue(std::move(result));
354 template <
typename Transformed,
typename ErrorType>
355 struct BindReturnType<Transformed,
357 std::enable_if_t<isResult<Transformed>>> {
358 using ReturnType = Transformed;
359 static ReturnType makeValue(Transformed &&result) {
360 return std::move(result);
365 template <
typename Transformed,
typename ErrorType>
366 struct BindReturnType<Transformed,
368 std::enable_if_t<isValue<Transformed>>> {
369 using ReturnType = Result<typename Transformed::type, ErrorType>;
370 static ReturnType makeValue(Transformed &&result) {
371 return std::move(result);
376 template <
typename ErrorType>
377 struct BindReturnType<void, ErrorType> {
378 using ReturnType = Result<void, ErrorType>;
381 template <
typename ValueTransformer,
typename Value,
typename Error>
382 using BindReturnTypeHelper =
typename std::enable_if_t<
383 not std::is_same<Value, void>::value,
384 BindReturnType<decltype(std::declval<ValueTransformer>()(
385 std::declval<Value>())),
396 template <
typename V,
400 typename TypeHelper = BindReturnTypeHelper<Transform, V, E>,
401 typename ReturnType =
typename TypeHelper::ReturnType>
402 constexpr
auto operator|(
const Result<V, E> &r, Transform &&f)
405 [&f](
const auto &v) {
return TypeHelper::makeValue(f(v.value)); },
406 [](
const auto &e) {
return ReturnType(makeError(e.error)); });
410 template <
typename V,
413 typename TypeHelper = BindReturnTypeHelper<Transform, V, E>,
414 typename ReturnType =
typename TypeHelper::ReturnType>
415 constexpr
auto operator|(Result<V, E> &&r, Transform &&f) -> ReturnType {
416 static_assert(isResult<ReturnType>,
"wrong return_type");
417 return std::move(r).match(
419 return TypeHelper::makeValue(f(std::move(v.value)));
421 [](
auto &&e) {
return ReturnType(makeError(std::move(e.error))); });
431 template <
typename T,
435 typename TypeHelper =
436 BindReturnType<decltype(std::declval<Procedure>()()), E>,
437 typename ReturnType =
typename TypeHelper::ReturnType>
438 constexpr
auto operator|(
const Result<T, E> &r, Procedure f) ->
439 typename std::enable_if<not std::is_same<decltype(f()), void>::value,
442 [&f](
const Value<T> &v) {
return TypeHelper::makeValue(f()); },
443 [](
const Error<E> &e) {
return ReturnType(makeError(e.error)); });
447 template <
typename V,
450 typename TypeHelper =
451 BindReturnType<decltype(std::declval<Procedure>()()), E>,
452 typename ReturnType =
typename TypeHelper::ReturnType>
453 constexpr
auto operator|(Result<V, E> &&r, Procedure f) ->
454 typename std::enable_if<not std::is_same<decltype(f()), void>::value,
456 return std::move(r).match(
457 [&f](
const auto &) {
return TypeHelper::makeValue(f()); },
458 [](
auto &&e) {
return ReturnType(makeError(std::move(e.error))); });
462 template <
typename R,
typename F>
463 constexpr
auto operator|=(R &r, F &&f) -> decltype(r = r | f) {
464 return r = r | std::forward<F>(f);
471 template <
typename ResultType,
472 typename = std::enable_if_t<isResult<ResultType>>>
473 bool hasValue(
const ResultType &result) {
474 return boost::get<ValueOf<ResultType>>(&result);
477 template <
typename ResultType,
478 typename = std::enable_if_t<isResult<ResultType>>>
479 bool hasError(
const ResultType &result) {
480 return boost::get<ErrorOf<ResultType>>(&result);
489 template <
typename ResultType,
491 typename = std::enable_if_t<isResult<ResultType>>>
492 boost::optional<typename std::decay_t<ResultType>::ValueInnerType>
493 resultToOptionalValue(ResultType &&res) noexcept {
495 return boost::get<ValueOf<ResultType>>(std::forward<ResultType>(res))
502 template <
typename ResultType,
503 typename = std::enable_if_t<isResult<ResultType>>>
504 boost::optional<typename std::decay_t<ResultType>::ErrorInnerType>
505 resultToOptionalError(ResultType &&res) noexcept {
507 return boost::get<ErrorOf<ResultType>>(std::forward<ResultType>(res))
513 template <
typename E,
typename V>
514 Result<typename V::value_type, std::decay_t<E>> optionalValueToResult(
515 V &&value, E &&error) {
517 return makeValue(std::move(value).value());
519 return makeError(std::move(error));
522 template <
typename V,
typename E>
523 Result<std::decay_t<V>,
typename E::value_type> optionalErrorToResult(
524 E &&error, V &&value) {
526 return makeError(std::move(error).value());
528 return makeValue(std::move(value));
532 #endif // IROHA_RESULT_HPP
auto operator|(T &&t, Transform &&f) -> std::enable_if_t< not std::is_same< decltype(std::forward< Transform >(f)(*std::forward< T >(t))), void >::value, decltype(std::forward< Transform >(f)(*std::forward< T >(t)))>
Definition: bind.hpp:42
Definition: block_query.hpp:15