LCOV - code coverage report
Current view: top level - src/util - result.h (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 13 17 76.5 %
Date: 2023-09-26 12:08:55 Functions: 17 88 19.3 %

          Line data    Source code
       1             : // Copyright (c) 2022 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or https://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #ifndef BITCOIN_UTIL_RESULT_H
       6             : #define BITCOIN_UTIL_RESULT_H
       7             : 
       8             : #include <attributes.h>
       9             : #include <util/translation.h>
      10             : 
      11             : #include <variant>
      12             : 
      13             : namespace util {
      14             : 
      15             : struct Error {
      16             :     bilingual_str message;
      17             : };
      18             : 
      19             : //! The util::Result class provides a standard way for functions to return
      20             : //! either error messages or result values.
      21             : //!
      22             : //! It is intended for high-level functions that need to report error strings to
      23             : //! end users. Lower-level functions that don't need this error-reporting and
      24             : //! only need error-handling should avoid util::Result and instead use standard
      25             : //! classes like std::optional, std::variant, and std::tuple, or custom structs
      26             : //! and enum types to return function results.
      27             : //!
      28             : //! Usage examples can be found in \example ../test/result_tests.cpp, but in
      29             : //! general code returning `util::Result<T>` values is very similar to code
      30             : //! returning `std::optional<T>` values. Existing functions returning
      31             : //! `std::optional<T>` can be updated to return `util::Result<T>` and return
      32             : //! error strings usually just replacing `return std::nullopt;` with `return
      33             : //! util::Error{error_string};`.
      34             : template <class M>
      35             : class Result
      36             : {
      37             : private:
      38             :     using T = std::conditional_t<std::is_same_v<M, void>, std::monostate, M>;
      39             : 
      40             :     std::variant<bilingual_str, T> m_variant;
      41             : 
      42             :     template <typename FT>
      43             :     friend bilingual_str ErrorString(const Result<FT>& result);
      44             : 
      45             : public:
      46       10010 :     Result() : m_variant{std::in_place_index_t<1>{}, std::monostate{}} {}  // constructor for void
      47        8888 :     Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {}
      48        1200 :     Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error.message)} {}
      49             : 
      50             :     //! std::optional methods, so functions returning optional<T> can change to
      51             :     //! return Result<T> with minimal changes to existing code, and vice versa.
      52       34665 :     bool has_value() const noexcept { return m_variant.index() == 1; }
      53           0 :     const T& value() const LIFETIMEBOUND
      54             :     {
      55           0 :         assert(has_value());
      56           0 :         return std::get<1>(m_variant);
      57             :     }
      58        8884 :     T& value() LIFETIMEBOUND
      59             :     {
      60        8884 :         assert(has_value());
      61        8884 :         return std::get<1>(m_variant);
      62             :     }
      63             :     template <class U>
      64             :     T value_or(U&& default_value) const&
      65             :     {
      66             :         return has_value() ? value() : std::forward<U>(default_value);
      67             :     }
      68             :     template <class U>
      69        5064 :     T value_or(U&& default_value) &&
      70             :     {
      71        5064 :         return has_value() ? std::move(value()) : std::forward<U>(default_value);
      72             :     }
      73       20709 :     explicit operator bool() const noexcept { return has_value(); }
      74             :     const T* operator->() const LIFETIMEBOUND { return &value(); }
      75             :     const T& operator*() const LIFETIMEBOUND { return value(); }
      76           0 :     T* operator->() LIFETIMEBOUND { return &value(); }
      77        3820 :     T& operator*() LIFETIMEBOUND { return value(); }
      78             : };
      79             : 
      80             : template <typename T>
      81         705 : bilingual_str ErrorString(const Result<T>& result)
      82             : {
      83         705 :     return result ? bilingual_str{} : std::get<0>(result.m_variant);
      84             : }
      85             : } // namespace util
      86             : 
      87             : #endif // BITCOIN_UTIL_RESULT_H

Generated by: LCOV version 1.14