Program Listing for File ErrorOr.hpp

Return to documentation for file (gui/ErrorOr.hpp)

#pragma once

#include <string>
#include <utility>
#include <variant>

#include "logging/Logger.hpp"

class [[nodiscard]] Error {
public:
  explicit Error(char const *msg, char const *file, int line)
  {
    Log::log(LogLevel::CRIT, file, line) << msg;
    message = std::string(msg);
  }

  explicit Error(std::string msg, char const *file, int line)
    : message(std::move(msg))
  {
    Log::log(LogLevel::CRIT, file, line) << message;
  }

#define Error(msg) Error(msg, __FILE__, __LINE__)

  [[nodiscard]] auto what() const -> const std::string &
  {
    return message;
  }

  [[nodiscard]] auto c_str() const -> const char *
  {
    return message.c_str();
  }

private:
  std::string message;
};

template <typename T> class [[nodiscard]] ErrorOr {
public:
  ErrorOr() = default;

  ErrorOr(const T &value) : result(value) {}

  ErrorOr(T &&value) : result(std::move(value)) {}

  ErrorOr(const Error &error) : result(error) {}

  ErrorOr(Error &&error) : result(std::move(error)) {}

  [[nodiscard]]
  auto has_value() const -> bool
  {
    return std::holds_alternative<T>(result);
  }

  auto value() -> T &
  {
    return std::get<T>(result);
  }

  [[nodiscard]]
  auto value() const -> const T &
  {
    return std::get<T>(result);
  }

  auto error() -> Error &
  {
    return std::get<Error>(result);
  }

  [[nodiscard]]
  auto error() const -> const Error &
  {
    return std::get<Error>(result);
  }

  [[nodiscard]]
  auto is_error() const -> bool
  {
    return std::holds_alternative<Error>(result);
  }

  [[nodiscard]]
  auto operator!() const -> bool
  {
    return is_error();
  }

private:
  std::variant<T, Error> result;
};

struct Nil {};

using MaybeError = ErrorOr<Nil>;

#define TRY(expr)                                                             \
    ({                                                                        \
        _Pragma("GCC diagnostic push");                                       \
        _Pragma("GCC diagnostic ignored \"-Wshadow\"");                       \
        auto&& try_tmp = (expr);                                              \
        if (try_tmp.is_error())                                               \
            return try_tmp.error();                                           \
        _Pragma("GCC diagnostic pop");                                        \
        std::move(try_tmp.value());                                           \
    })

#define MUST(expr, err) if (!((expr))) return Error(err)

#define NotYetImplemented Error("not yet implmented")