Program Listing for File expected.hpp

Return to documentation for file (include/utils/expected.hpp)

#pragma once

#include <stdexcept>
#include <string>
#include <tl/expected.hpp>

template <typename Expected> typename Expected::value_type handle_expected(Expected&& result) {
  if (result.has_value()) {
    if constexpr (std::is_void_v<typename Expected::value_type>) {
      return;  // Return nothing since it's a void type
    } else {
      return result.value();
    }
  } else {
    // TODO: Consider wrapping with a streamable option.
    if constexpr (std::is_convertible_v<typename Expected::error_type, std::string>) {
      throw std::runtime_error(std::string(result.error()));
    } else {
      throw std::runtime_error("Unknown error occurred.");
    }
  }
};

template <typename Class, typename Ret, typename Err, typename... Args>
auto unwrap_expected(tl::expected<Ret, Err> (Class::*method)(Args...)) {
  return [method](Class& self, Args... args) -> Ret {
    return handle_expected((self.*method)(args...));
  };
}

template <typename Class, typename Ret, typename Err, typename... Args>
auto unwrap_expected(tl::expected<Ret, Err> (Class::*method)(Args...) const) {
  return [method](const Class& self, Args... args) -> Ret {
    return handle_expected((self.*method)(args...));
  };
}

template <typename Ret, typename Err, typename... Args>
auto unwrap_expected(tl::expected<Ret, Err> (*method)(Args...)) {
  return [method](Args... args) -> Ret { return handle_expected((*method)(args...)); };
}