Introduce generic 'Result' class
Useful to encapsulate the function result object (in case of having it) or, in case of failure, the failure reason.
This let us clean lot of boilerplate code, as now instead of returning a boolean and having to add a ref arg for the
return object and another ref for the error string. We can simply return a 'BResult<Obj>'.
Example of what we currently have:
```
bool doSomething(arg1, arg2, arg3, arg4, &result, &error_string) {
do something...
if (error) {
error_string = "something bad happened";
return false;
}
result = goodResult;
return true;
}
```
Example of what we will get with this commit:
```
BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
do something...
if (error) return {"something happened"};
// good
return {goodResult};
}
```
This allows a similar boilerplate cleanup on the function callers side as well. They don't have to add the extra
pre-function-call error string and result object declarations to pass the references to the function.
2022-04-08 16:24:46 -03:00
|
|
|
// Copyright (c) 2022 The Bitcoin Core developers
|
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or https://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
#ifndef BITCOIN_UTIL_RESULT_H
|
|
|
|
#define BITCOIN_UTIL_RESULT_H
|
|
|
|
|
2022-07-21 08:30:39 -04:00
|
|
|
#include <attributes.h>
|
Introduce generic 'Result' class
Useful to encapsulate the function result object (in case of having it) or, in case of failure, the failure reason.
This let us clean lot of boilerplate code, as now instead of returning a boolean and having to add a ref arg for the
return object and another ref for the error string. We can simply return a 'BResult<Obj>'.
Example of what we currently have:
```
bool doSomething(arg1, arg2, arg3, arg4, &result, &error_string) {
do something...
if (error) {
error_string = "something bad happened";
return false;
}
result = goodResult;
return true;
}
```
Example of what we will get with this commit:
```
BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
do something...
if (error) return {"something happened"};
// good
return {goodResult};
}
```
This allows a similar boilerplate cleanup on the function callers side as well. They don't have to add the extra
pre-function-call error string and result object declarations to pass the references to the function.
2022-04-08 16:24:46 -03:00
|
|
|
#include <util/translation.h>
|
2022-07-12 19:28:03 +02:00
|
|
|
|
Introduce generic 'Result' class
Useful to encapsulate the function result object (in case of having it) or, in case of failure, the failure reason.
This let us clean lot of boilerplate code, as now instead of returning a boolean and having to add a ref arg for the
return object and another ref for the error string. We can simply return a 'BResult<Obj>'.
Example of what we currently have:
```
bool doSomething(arg1, arg2, arg3, arg4, &result, &error_string) {
do something...
if (error) {
error_string = "something bad happened";
return false;
}
result = goodResult;
return true;
}
```
Example of what we will get with this commit:
```
BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
do something...
if (error) return {"something happened"};
// good
return {goodResult};
}
```
This allows a similar boilerplate cleanup on the function callers side as well. They don't have to add the extra
pre-function-call error string and result object declarations to pass the references to the function.
2022-04-08 16:24:46 -03:00
|
|
|
#include <variant>
|
|
|
|
|
2022-07-21 08:30:39 -04:00
|
|
|
namespace util {
|
|
|
|
|
|
|
|
struct Error {
|
|
|
|
bilingual_str message;
|
|
|
|
};
|
|
|
|
|
|
|
|
//! The util::Result class provides a standard way for functions to return
|
|
|
|
//! either error messages or result values.
|
|
|
|
//!
|
|
|
|
//! It is intended for high-level functions that need to report error strings to
|
|
|
|
//! end users. Lower-level functions that don't need this error-reporting and
|
|
|
|
//! only need error-handling should avoid util::Result and instead use standard
|
|
|
|
//! classes like std::optional, std::variant, and std::tuple, or custom structs
|
|
|
|
//! and enum types to return function results.
|
|
|
|
//!
|
|
|
|
//! Usage examples can be found in \example ../test/result_tests.cpp, but in
|
|
|
|
//! general code returning `util::Result<T>` values is very similar to code
|
|
|
|
//! returning `std::optional<T>` values. Existing functions returning
|
|
|
|
//! `std::optional<T>` can be updated to return `util::Result<T>` and return
|
|
|
|
//! error strings usually just replacing `return std::nullopt;` with `return
|
|
|
|
//! util::Error{error_string};`.
|
|
|
|
template <class T>
|
|
|
|
class Result
|
|
|
|
{
|
Introduce generic 'Result' class
Useful to encapsulate the function result object (in case of having it) or, in case of failure, the failure reason.
This let us clean lot of boilerplate code, as now instead of returning a boolean and having to add a ref arg for the
return object and another ref for the error string. We can simply return a 'BResult<Obj>'.
Example of what we currently have:
```
bool doSomething(arg1, arg2, arg3, arg4, &result, &error_string) {
do something...
if (error) {
error_string = "something bad happened";
return false;
}
result = goodResult;
return true;
}
```
Example of what we will get with this commit:
```
BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
do something...
if (error) return {"something happened"};
// good
return {goodResult};
}
```
This allows a similar boilerplate cleanup on the function callers side as well. They don't have to add the extra
pre-function-call error string and result object declarations to pass the references to the function.
2022-04-08 16:24:46 -03:00
|
|
|
private:
|
|
|
|
std::variant<bilingual_str, T> m_variant;
|
|
|
|
|
2022-07-21 08:30:39 -04:00
|
|
|
template <typename FT>
|
|
|
|
friend bilingual_str ErrorString(const Result<FT>& result);
|
Introduce generic 'Result' class
Useful to encapsulate the function result object (in case of having it) or, in case of failure, the failure reason.
This let us clean lot of boilerplate code, as now instead of returning a boolean and having to add a ref arg for the
return object and another ref for the error string. We can simply return a 'BResult<Obj>'.
Example of what we currently have:
```
bool doSomething(arg1, arg2, arg3, arg4, &result, &error_string) {
do something...
if (error) {
error_string = "something bad happened";
return false;
}
result = goodResult;
return true;
}
```
Example of what we will get with this commit:
```
BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
do something...
if (error) return {"something happened"};
// good
return {goodResult};
}
```
This allows a similar boilerplate cleanup on the function callers side as well. They don't have to add the extra
pre-function-call error string and result object declarations to pass the references to the function.
2022-04-08 16:24:46 -03:00
|
|
|
|
2022-07-21 08:30:39 -04:00
|
|
|
public:
|
|
|
|
Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {}
|
|
|
|
Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error.message)} {}
|
Introduce generic 'Result' class
Useful to encapsulate the function result object (in case of having it) or, in case of failure, the failure reason.
This let us clean lot of boilerplate code, as now instead of returning a boolean and having to add a ref arg for the
return object and another ref for the error string. We can simply return a 'BResult<Obj>'.
Example of what we currently have:
```
bool doSomething(arg1, arg2, arg3, arg4, &result, &error_string) {
do something...
if (error) {
error_string = "something bad happened";
return false;
}
result = goodResult;
return true;
}
```
Example of what we will get with this commit:
```
BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
do something...
if (error) return {"something happened"};
// good
return {goodResult};
}
```
This allows a similar boilerplate cleanup on the function callers side as well. They don't have to add the extra
pre-function-call error string and result object declarations to pass the references to the function.
2022-04-08 16:24:46 -03:00
|
|
|
|
2022-07-21 08:30:39 -04:00
|
|
|
//! std::optional methods, so functions returning optional<T> can change to
|
|
|
|
//! return Result<T> with minimal changes to existing code, and vice versa.
|
|
|
|
bool has_value() const noexcept { return m_variant.index() == 1; }
|
|
|
|
const T& value() const LIFETIMEBOUND
|
|
|
|
{
|
|
|
|
assert(has_value());
|
|
|
|
return std::get<1>(m_variant);
|
Introduce generic 'Result' class
Useful to encapsulate the function result object (in case of having it) or, in case of failure, the failure reason.
This let us clean lot of boilerplate code, as now instead of returning a boolean and having to add a ref arg for the
return object and another ref for the error string. We can simply return a 'BResult<Obj>'.
Example of what we currently have:
```
bool doSomething(arg1, arg2, arg3, arg4, &result, &error_string) {
do something...
if (error) {
error_string = "something bad happened";
return false;
}
result = goodResult;
return true;
}
```
Example of what we will get with this commit:
```
BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
do something...
if (error) return {"something happened"};
// good
return {goodResult};
}
```
This allows a similar boilerplate cleanup on the function callers side as well. They don't have to add the extra
pre-function-call error string and result object declarations to pass the references to the function.
2022-04-08 16:24:46 -03:00
|
|
|
}
|
2022-07-21 08:30:39 -04:00
|
|
|
T& value() LIFETIMEBOUND
|
2022-07-12 19:28:03 +02:00
|
|
|
{
|
2022-07-21 08:30:39 -04:00
|
|
|
assert(has_value());
|
|
|
|
return std::get<1>(m_variant);
|
2022-07-12 19:28:03 +02:00
|
|
|
}
|
2022-07-21 08:30:39 -04:00
|
|
|
template <class U>
|
|
|
|
T value_or(U&& default_value) const&
|
|
|
|
{
|
|
|
|
return has_value() ? value() : std::forward<U>(default_value);
|
Introduce generic 'Result' class
Useful to encapsulate the function result object (in case of having it) or, in case of failure, the failure reason.
This let us clean lot of boilerplate code, as now instead of returning a boolean and having to add a ref arg for the
return object and another ref for the error string. We can simply return a 'BResult<Obj>'.
Example of what we currently have:
```
bool doSomething(arg1, arg2, arg3, arg4, &result, &error_string) {
do something...
if (error) {
error_string = "something bad happened";
return false;
}
result = goodResult;
return true;
}
```
Example of what we will get with this commit:
```
BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
do something...
if (error) return {"something happened"};
// good
return {goodResult};
}
```
This allows a similar boilerplate cleanup on the function callers side as well. They don't have to add the extra
pre-function-call error string and result object declarations to pass the references to the function.
2022-04-08 16:24:46 -03:00
|
|
|
}
|
2022-07-21 08:30:39 -04:00
|
|
|
template <class U>
|
|
|
|
T value_or(U&& default_value) &&
|
|
|
|
{
|
|
|
|
return has_value() ? std::move(value()) : std::forward<U>(default_value);
|
|
|
|
}
|
|
|
|
explicit operator bool() const noexcept { return has_value(); }
|
|
|
|
const T* operator->() const LIFETIMEBOUND { return &value(); }
|
|
|
|
const T& operator*() const LIFETIMEBOUND { return value(); }
|
|
|
|
T* operator->() LIFETIMEBOUND { return &value(); }
|
|
|
|
T& operator*() LIFETIMEBOUND { return value(); }
|
Introduce generic 'Result' class
Useful to encapsulate the function result object (in case of having it) or, in case of failure, the failure reason.
This let us clean lot of boilerplate code, as now instead of returning a boolean and having to add a ref arg for the
return object and another ref for the error string. We can simply return a 'BResult<Obj>'.
Example of what we currently have:
```
bool doSomething(arg1, arg2, arg3, arg4, &result, &error_string) {
do something...
if (error) {
error_string = "something bad happened";
return false;
}
result = goodResult;
return true;
}
```
Example of what we will get with this commit:
```
BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
do something...
if (error) return {"something happened"};
// good
return {goodResult};
}
```
This allows a similar boilerplate cleanup on the function callers side as well. They don't have to add the extra
pre-function-call error string and result object declarations to pass the references to the function.
2022-04-08 16:24:46 -03:00
|
|
|
};
|
|
|
|
|
2022-07-21 08:30:39 -04:00
|
|
|
template <typename T>
|
|
|
|
bilingual_str ErrorString(const Result<T>& result)
|
|
|
|
{
|
|
|
|
return result ? bilingual_str{} : std::get<0>(result.m_variant);
|
|
|
|
}
|
|
|
|
} // namespace util
|
|
|
|
|
Introduce generic 'Result' class
Useful to encapsulate the function result object (in case of having it) or, in case of failure, the failure reason.
This let us clean lot of boilerplate code, as now instead of returning a boolean and having to add a ref arg for the
return object and another ref for the error string. We can simply return a 'BResult<Obj>'.
Example of what we currently have:
```
bool doSomething(arg1, arg2, arg3, arg4, &result, &error_string) {
do something...
if (error) {
error_string = "something bad happened";
return false;
}
result = goodResult;
return true;
}
```
Example of what we will get with this commit:
```
BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
do something...
if (error) return {"something happened"};
// good
return {goodResult};
}
```
This allows a similar boilerplate cleanup on the function callers side as well. They don't have to add the extra
pre-function-call error string and result object declarations to pass the references to the function.
2022-04-08 16:24:46 -03:00
|
|
|
#endif // BITCOIN_UTIL_RESULT_H
|