6 #ifndef IROHA_RESULT_HPP 7 #define IROHA_RESULT_HPP 13 #include <type_traits> 15 #include <boost/optional.hpp> 16 #include <boost/variant.hpp> 42 struct Value : ValueBase {
46 typename = std::enable_if_t<std::is_constructible<T, Args...>::value>>
47 Value(Args &&... args) : value(
std::forward<Args>(args)...) {}
56 struct Value<void> {};
61 struct Error : ErrorBase {
65 typename = std::enable_if_t<std::is_constructible<E, Args...>::value>>
66 Error(Args &&... args) : error(
std::forward<Args>(args)...) {}
75 struct Error<void> {};
77 class ResultException :
public std::runtime_error {
78 using std::runtime_error::runtime_error;
89 template <
typename V,
typename E = std::
string>
90 class Result : ResultBase,
public boost::variant<Value<V>, Error<E>> {
91 template <
typename OV,
typename OE>
94 using variant_type = boost::variant<Value<V>, Error<E>>;
95 using variant_type::variant_type;
98 using ValueType = Value<V>;
99 using ErrorType = Error<E>;
101 using ValueInnerType = V;
102 using ErrorInnerType = E;
106 template <
typename OV,
typename OE>
107 Result(Result<OV, OE> r)
108 : Result(visit_in_place(
std::move(r),
109 [](Value<OV> &v) -> Result<V, E> {
110 return ValueType{std::move(v.value)};
112 [](Value<OV> &&v) -> Result<V, E> {
113 return ValueType{std::move(v.value)};
115 [](Error<OE> &e) -> Result<V, E> {
116 return ErrorType{std::move(e.error)};
118 [](Error<OE> &&e) -> Result<V, E> {
119 return ErrorType{std::move(e.error)};
131 template <
typename ValueMatch,
typename ErrorMatch>
132 constexpr
auto match(ValueMatch &&value_func, ErrorMatch &&error_func) & {
133 return visit_in_place(*
this,
134 [f = std::forward<ValueMatch>(value_func)](
135 ValueType &v) {
return f(v); },
136 [f = std::forward<ErrorMatch>(error_func)](
137 ErrorType &e) {
return f(e); });
143 template <
typename ValueMatch,
typename ErrorMatch>
144 constexpr
auto match(ValueMatch &&value_func,
145 ErrorMatch &&error_func) && {
146 return visit_in_place(*
this,
147 [f = std::forward<ValueMatch>(value_func)](
148 ValueType &v) {
return f(std::move(v)); },
149 [f = std::forward<ErrorMatch>(error_func)](
150 ErrorType &e) {
return f(std::move(e)); });
156 template <
typename ValueMatch,
typename ErrorMatch>
157 constexpr
auto match(ValueMatch &&value_func,
158 ErrorMatch &&error_func)
const & {
159 return visit_in_place(*
this,
160 [f = std::forward<ValueMatch>(value_func)](
161 const ValueType &v) {
return f(v); },
162 [f = std::forward<ErrorMatch>(error_func)](
163 const ErrorType &e) {
return f(e); });
177 template <
typename Value>
178 constexpr Result<Value, E> and_res(
const Result<Value, E> &new_res)
const 180 return visit_in_place(
182 [res = new_res](ValueType) {
return res; },
183 [](ErrorType err) -> Result<Value, E> {
return err; });
197 template <
typename Value>
198 constexpr Result<Value, E> or_res(
const Result<Value, E> &new_res)
const 200 return visit_in_place(
202 [](ValueType val) -> Result<Value, E> {
return val; },
203 [res = new_res](ErrorType) {
return res; });
206 using AssumeValueHelper =
207 std::conditional_t<std::is_void<ValueInnerType>::value,
212 template <
typename ReturnType = const AssumeValueHelper &>
213 std::enable_if_t<not std::is_void<ValueInnerType>::value, ReturnType>
214 assumeValue() const & {
215 const auto *val = boost::get<ValueType>(
this);
216 if (val !=
nullptr) {
219 throw ResultException(
"Value expected, but got an Error.");
223 template <
typename ReturnType = AssumeValueHelper &>
224 std::enable_if_t<not std::is_void<ValueInnerType>::value, ReturnType>
226 auto val = boost::get<ValueType>(
this);
227 if (val !=
nullptr) {
230 throw ResultException(
"Value expected, but got an Error.");
234 template <
typename ReturnType = AssumeValueHelper &&>
235 std::enable_if_t<not std::is_void<ValueInnerType>::value, ReturnType>
237 auto val = boost::get<ValueType>(
this);
238 if (val !=
nullptr) {
239 return std::move(val->value);
241 throw ResultException(
"Value expected, but got an Error.");
244 using AssumeErrorHelper =
245 std::conditional_t<std::is_void<ErrorInnerType>::value,
250 template <
typename ReturnType = const AssumeErrorHelper &>
251 std::enable_if_t<not std::is_void<ErrorInnerType>::value, ReturnType>
252 assumeError() const & {
253 const auto *err = boost::get<ErrorType>(
this);
254 if (err !=
nullptr) {
257 throw ResultException(
"Error expected, but got a Value.");
261 template <
typename ReturnType = AssumeErrorHelper &>
262 std::enable_if_t<not std::is_void<ErrorInnerType>::value, ReturnType>
264 auto err = boost::get<ErrorType>(
this);
265 if (err !=
nullptr) {
268 throw ResultException(
"Error expected, but got a Value.");
272 template <
typename ReturnType = AssumeErrorHelper &&>
273 std::enable_if_t<not std::is_void<ErrorInnerType>::value, ReturnType>
275 auto err = boost::get<ErrorType>(
this);
276 if (err !=
nullptr) {
277 return std::move(err->error);
279 throw ResultException(
"Error expected, but got a Value.");
283 template <
typename ResultType>
284 using ValueOf =
typename std::decay_t<ResultType>::ValueType;
285 template <
typename ResultType>
286 using ErrorOf =
typename std::decay_t<ResultType>::ErrorType;
288 template <
typename ResultType>
289 using InnerValueOf =
typename std::decay_t<ResultType>::ValueInnerType;
290 template <
typename ResultType>
291 using InnerErrorOf =
typename std::decay_t<ResultType>::ErrorInnerType;
299 template <
typename Err1,
typename Err2,
typename V,
typename Fn>
300 Result<V, Err1> map_error(
const Result<V, Err2> &res, Fn &&map) noexcept {
301 return visit_in_place(res,
302 [](Value<V> val) -> Result<V, Err1> {
return val; },
303 [map](Error<Err2> err) -> Result<V, Err1> {
304 return Error<Err1>{map(err.error)};
309 inline Value<void> makeValue() {
310 return Value<void>{};
313 template <
typename T>
314 Value<T> makeValue(T &&value) {
315 return Value<T>{std::forward<T>(value)};
319 return Error<void>{};
322 template <
typename E>
324 return Error<E>{std::forward<E>(error)};
327 template <
typename T>
328 constexpr
bool isResult =
329 std::is_base_of<ResultBase, std::decay_t<T>>::value;
330 template <
typename T>
331 constexpr
bool isValue = std::is_base_of<ValueBase, std::decay_t<T>>::value;
332 template <
typename T>
333 constexpr
bool isError = std::is_base_of<ErrorBase, std::decay_t<T>>::value;
343 template <
typename Transformed,
typename ErrorType,
typename =
void>
344 struct BindReturnType;
347 template <
typename Transformed,
typename ErrorType>
348 struct BindReturnType<
351 typename
std::enable_if_t<
352 not isResult<Transformed> and not isValue<Transformed>>> {
353 using ReturnType = Result<Transformed, ErrorType>;
354 static ReturnType makeValue(Transformed &&result) {
355 return iroha::expected::makeValue(std::move(result));
360 template <
typename Transformed,
typename ErrorType>
361 struct BindReturnType<Transformed,
363 std::enable_if_t<isResult<Transformed>>> {
364 using ReturnType = Transformed;
365 static ReturnType makeValue(Transformed &&result) {
366 return std::move(result);
371 template <
typename Transformed,
typename ErrorType>
372 struct BindReturnType<Transformed,
374 std::enable_if_t<isValue<Transformed>>> {
375 using ReturnType = Result<typename Transformed::type, ErrorType>;
376 static ReturnType makeValue(Transformed &&result) {
377 return std::move(result);
382 template <
typename ErrorType>
383 struct BindReturnType<void, ErrorType> {
384 using ReturnType = Result<void, ErrorType>;
387 template <
typename ValueTransformer,
typename Value,
typename Error>
388 using BindReturnTypeHelper =
typename std::enable_if_t<
389 not std::is_same<Value, void>::value,
390 BindReturnType<decltype(std::declval<ValueTransformer>()(
391 std::declval<Value>())),
402 template <
typename V,
406 typename TypeHelper = BindReturnTypeHelper<Transform, V, E>,
407 typename ReturnType =
typename TypeHelper::ReturnType>
408 constexpr
auto operator|(
const Result<V, E> &r, Transform &&f)
411 [&f](
const auto &v) {
return TypeHelper::makeValue(f(v.value)); },
412 [](
const auto &e) {
return ReturnType(
makeError(e.error)); });
416 template <
typename V,
419 typename TypeHelper = BindReturnTypeHelper<Transform, V, E>,
420 typename ReturnType =
typename TypeHelper::ReturnType>
421 constexpr
auto operator|(Result<V, E> &&r, Transform &&f) -> ReturnType {
422 static_assert(isResult<ReturnType>,
"wrong return_type");
423 return std::move(r).match(
425 return TypeHelper::makeValue(f(std::move(v.value)));
427 [](
auto &&e) {
return ReturnType(
makeError(std::move(e.error))); });
437 template <
typename T,
441 typename TypeHelper =
442 BindReturnType<decltype(std::declval<Procedure>()()), E>,
443 typename ReturnType =
typename TypeHelper::ReturnType>
444 constexpr
auto operator|(
const Result<T, E> &r, Procedure f) ->
445 typename std::enable_if<not std::is_same<decltype(f()), void>::value,
448 [&f](
const Value<T> &v) {
return TypeHelper::makeValue(f()); },
449 [](
const Error<E> &e) {
return ReturnType(
makeError(e.error)); });
453 template <
typename V,
456 typename TypeHelper =
457 BindReturnType<decltype(std::declval<Procedure>()()), E>,
458 typename ReturnType =
typename TypeHelper::ReturnType>
459 constexpr
auto operator|(Result<V, E> &&r, Procedure f) ->
460 typename std::enable_if<not std::is_same<decltype(f()), void>::value,
462 return std::move(r).match(
463 [&f](
const auto &) {
return TypeHelper::makeValue(f()); },
464 [](
auto &&e) {
return ReturnType(
makeError(std::move(e.error))); });
468 template <
typename R,
typename F>
469 constexpr
auto operator|=(R &r, F &&f) -> decltype(r = r | f) {
470 return r = r | std::forward<F>(f);
477 template <
typename ResultType,
478 typename = std::enable_if_t<isResult<ResultType>>>
479 bool hasValue(
const ResultType &result) {
480 return boost::get<ValueOf<ResultType>>(&result);
483 template <
typename ResultType,
484 typename = std::enable_if_t<isResult<ResultType>>>
485 bool hasError(
const ResultType &result) {
486 return boost::get<ErrorOf<ResultType>>(&result);
495 template <
typename ResultType,
497 typename = std::enable_if_t<isResult<ResultType>>>
498 boost::optional<InnerValueOf<ResultType>> resultToOptionalValue(
499 ResultType &&res) noexcept {
501 return boost::get<ValueOf<ResultType>>(std::forward<ResultType>(res))
508 template <
typename ResultType,
509 typename = std::enable_if_t<isResult<ResultType>>>
510 boost::optional<InnerErrorOf<ResultType>> resultToOptionalError(
511 ResultType &&res) noexcept {
513 return boost::get<ErrorOf<ResultType>>(std::forward<ResultType>(res))
519 template <
typename E,
typename V>
520 Result<typename V::value_type, std::decay_t<E>> optionalValueToResult(
521 V &&value, E &&error) {
523 return makeValue(std::move(value).value());
528 template <
typename V,
typename E>
529 Result<std::decay_t<V>,
typename E::value_type> optionalErrorToResult(
530 E &&error, V &&value) {
532 return makeError(std::move(error).value());
534 return makeValue(std::move(value));
538 #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
expected::Result< T, DbError > makeError(uint32_t code, char const *format, Args &&... args)
Definition: rocksdb_common.hpp:471