#ifndef CLRSYNC_CORE_ERROR_HPP #define CLRSYNC_CORE_ERROR_HPP #include #include #include namespace clrsync::core { enum class error_code { unknown, file_not_found, file_open_failed, file_write_failed, file_read_failed, dir_create_failed, parse_failed, invalid_format, config_missing, config_invalid, template_not_found, template_load_failed, template_apply_failed, palette_not_found, palette_load_failed, init_failed, invalid_arg, resource_missing, }; inline const char *error_code_string(error_code code) { switch (code) { case error_code::unknown: return "Unknown error"; case error_code::file_not_found: return "File not found"; case error_code::file_open_failed: return "Failed to open file"; case error_code::file_write_failed: return "Failed to write file"; case error_code::file_read_failed: return "Failed to read file"; case error_code::dir_create_failed: return "Failed to create directory"; case error_code::parse_failed: return "Parse failed"; case error_code::invalid_format: return "Invalid format"; case error_code::config_missing: return "Configuration missing"; case error_code::config_invalid: return "Configuration invalid"; case error_code::template_not_found: return "Template not found"; case error_code::template_load_failed: return "Failed to load template"; case error_code::template_apply_failed: return "Failed to apply template"; case error_code::palette_not_found: return "Palette not found"; case error_code::palette_load_failed: return "Failed to load palette"; case error_code::init_failed: return "Initialization failed"; case error_code::invalid_arg: return "Invalid argument"; case error_code::resource_missing: return "Resource missing"; default: return "Unknown error code"; } } struct Error { error_code code; std::string message; std::string context; Error(error_code c) : code(c), message(error_code_string(c)) { } Error(error_code c, std::string msg) : code(c), message(std::move(msg)) { } Error(error_code c, std::string msg, std::string ctx) : code(c), message(std::move(msg)), context(std::move(ctx)) { } std::string description() const { if (context.empty()) return message; return message + " [" + context + "]"; } }; template class [[nodiscard]] Result { private: std::variant m_data; public: Result(T value) : m_data(std::move(value)) { } Result(Error error) : m_data(std::move(error)) { } bool is_ok() const { return std::holds_alternative(m_data); } bool is_error() const { return std::holds_alternative(m_data); } explicit operator bool() const { return is_ok(); } T &value() & { return std::get(m_data); } const T &value() const & { return std::get(m_data); } T &&value() && { return std::get(std::move(m_data)); } const Error &error() const { return std::get(m_data); } T value_or(T default_value) const { return is_ok() ? std::get(m_data) : std::move(default_value); } std::optional ok() const { if (is_ok()) return std::get(m_data); return std::nullopt; } std::optional err() const { if (is_error()) return std::get(m_data); return std::nullopt; } template auto map(F &&func) -> Result()))> { using U = decltype(func(std::declval())); if (is_ok()) return Result(func(std::get(m_data))); return Result(std::get(m_data)); } template auto and_then(F &&func) -> decltype(func(std::declval())) { if (is_ok()) return func(std::get(m_data)); using ResultType = decltype(func(std::declval())); return ResultType(std::get(m_data)); } }; template <> class [[nodiscard]] Result { private: std::optional m_error; public: Result() : m_error(std::nullopt) { } Result(Error error) : m_error(std::move(error)) { } bool is_ok() const { return !m_error.has_value(); } bool is_error() const { return m_error.has_value(); } explicit operator bool() const { return is_ok(); } const Error &error() const { return *m_error; } std::optional err() const { return m_error; } }; template Result Ok(T value) { return Result(std::move(value)); } inline Result Ok() { return Result(); } template Result Err(Error error) { return Result(std::move(error)); } template Result Err(error_code code) { return Result(Error(code)); } template Result Err(error_code code, std::string message) { return Result(Error(code, std::move(message))); } template Result Err(error_code code, std::string message, std::string context) { return Result(Error(code, std::move(message), std::move(context))); } } // namespace clrsync::core #endif // CLRSYNC_CORE_ERROR_HPP