just in case
This commit is contained in:
parent
b534cbddb0
commit
24b6a72614
9 changed files with 268 additions and 233 deletions
|
@ -1,10 +1,9 @@
|
|||
// ReSharper disable CppDFAConstantParameter
|
||||
#pragma once
|
||||
|
||||
// Fixes conflict in Windows with <windows.h>
|
||||
#ifdef _WIN32
|
||||
#undef ERROR
|
||||
#endif
|
||||
#undef ERROR
|
||||
#endif // _WIN32
|
||||
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
|
@ -117,9 +116,11 @@ namespace term {
|
|||
* @param fgColor The foreground color to apply.
|
||||
* @return The combined style.
|
||||
*/
|
||||
// ReSharper disable CppDFAConstantParameter
|
||||
constexpr fn operator|(const Emphasis emph, const Color fgColor)->Style {
|
||||
return { .emph = emph, .fg_col = fgColor };
|
||||
}
|
||||
// ReSharper restore CppDFAConstantParameter
|
||||
|
||||
/**
|
||||
* @brief Combines a foreground color and an emphasis style into a Style.
|
||||
|
@ -181,7 +182,7 @@ namespace term {
|
|||
// Directly use std::print for unstyled output
|
||||
std::print(fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
} // namespace term
|
||||
|
||||
/**
|
||||
* @enum LogLevel
|
||||
|
@ -201,11 +202,12 @@ template <typename... Args>
|
|||
fn LogImpl(const LogLevel level, const std::source_location& loc, std::format_string<Args...> fmt, Args&&... args) {
|
||||
using namespace std::chrono;
|
||||
using namespace term;
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifdef _MSC_VER
|
||||
using enum term::Color;
|
||||
#else
|
||||
using enum Color;
|
||||
#endif
|
||||
#endif // _MSC_VER
|
||||
|
||||
const auto [color, levelStr] = [&] {
|
||||
switch (level) {
|
||||
|
@ -229,29 +231,82 @@ fn LogImpl(const LogLevel level, const std::source_location& loc, std::format_st
|
|||
std::filesystem::path(loc.file_name()).lexically_normal().string(),
|
||||
loc.line()
|
||||
);
|
||||
#endif
|
||||
#endif // !NDEBUG
|
||||
|
||||
Print("\n");
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename ErrorType>
|
||||
fn LogAppError(const LogLevel level, const ErrorType& error_obj) {
|
||||
using DecayedErrorType = std::decay_t<ErrorType>;
|
||||
|
||||
std::source_location log_location = std::source_location::current();
|
||||
String error_message_part;
|
||||
LogLevel final_log_level = level;
|
||||
|
||||
if constexpr (std::is_same_v<DecayedErrorType, OsError>) {
|
||||
log_location = error_obj.location;
|
||||
error_message_part = error_obj.message;
|
||||
|
||||
} else if constexpr (std::is_same_v<DecayedErrorType, NowPlayingError>) {
|
||||
if (std::holds_alternative<OsError>(error_obj)) {
|
||||
const OsError& osErr = std::get<OsError>(error_obj);
|
||||
log_location = osErr.location;
|
||||
error_message_part = osErr.message;
|
||||
} else if (std::holds_alternative<NowPlayingCode>(error_obj)) {
|
||||
const NowPlayingCode npCode = std::get<NowPlayingCode>(error_obj);
|
||||
log_location = std::source_location::current();
|
||||
final_log_level = LogLevel::DEBUG;
|
||||
switch (npCode) {
|
||||
case NowPlayingCode::NoPlayers: error_message_part = "No media players found"; break;
|
||||
case NowPlayingCode::NoActivePlayer: error_message_part = "No active media player found"; break;
|
||||
default: error_message_part = "Unknown NowPlayingCode"; break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_location = std::source_location::current();
|
||||
if constexpr (std::is_base_of_v<std::exception, DecayedErrorType>)
|
||||
error_message_part = error_obj.what();
|
||||
else if constexpr (requires { error_obj.message; })
|
||||
error_message_part = error_obj.message;
|
||||
else
|
||||
error_message_part = "Unknown error type logged";
|
||||
}
|
||||
|
||||
LogImpl(final_log_level, log_location, "{}", error_message_part);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
// Suppress unused macro warnings in Clang
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-macros"
|
||||
#endif
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-macros"
|
||||
#endif // __clang__
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define DEBUG_LOG(...) static_cast<void>(0)
|
||||
#define DEBUG_LOG(...) static_cast<void>(0)
|
||||
#define DEBUG_LOG_LOC(...) static_cast<void>(0)
|
||||
#else
|
||||
/**
|
||||
* @def DEBUG_LOG
|
||||
* @brief Logs a message at the DEBUG level.
|
||||
* @details Only active in non-release builds (when NDEBUG is not defined).
|
||||
* Includes timestamp, level, message, and source location.
|
||||
* @param ... Format string and arguments for the log message.
|
||||
*/
|
||||
#define DEBUG_LOG(...) LogImpl(LogLevel::DEBUG, std::source_location::current(), __VA_ARGS__)
|
||||
#endif
|
||||
/**
|
||||
* @def DEBUG_LOG
|
||||
* @brief Logs a message at the DEBUG level.
|
||||
* @details Only active in non-release builds (when NDEBUG is not defined).
|
||||
* Includes timestamp, level, message, and source location.
|
||||
* @param ... Format string and arguments for the log message.
|
||||
*/
|
||||
#define DEBUG_LOG(...) LogImpl(LogLevel::DEBUG, std::source_location::current(), __VA_ARGS__)
|
||||
/**
|
||||
* @def DEBUG_LOG_LOC(error_obj)
|
||||
* @brief Logs an application-specific error at the DEBUG level, using its stored location if available.
|
||||
* @details Only active in non-release builds (when NDEBUG is not defined).
|
||||
* @param error_obj The error object (e.g., OsError, NowPlayingError).
|
||||
*/
|
||||
#define DEBUG_LOG_LOC(error_obj) \
|
||||
do { \
|
||||
[&](const auto& err) { detail::LogAppError(LogLevel::DEBUG, err); }(error_obj); \
|
||||
} while (0)
|
||||
#endif // NDEBUG
|
||||
|
||||
/**
|
||||
* @def INFO_LOG(...)
|
||||
|
@ -278,17 +333,15 @@ fn LogImpl(const LogLevel level, const std::source_location& loc, std::format_st
|
|||
#define ERROR_LOG(...) LogImpl(LogLevel::ERROR, std::source_location::current(), __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @def RETURN_ERR(...)
|
||||
* @brief Logs an error message and returns a value.
|
||||
* @details Logs the error message with the ERROR log level and returns the specified value.
|
||||
* @param ... Format string and arguments for the error message.
|
||||
* @def ERROR_LOG_LOC(error_obj)
|
||||
* @brief Logs an application-specific error at the ERROR level, using its stored location if available.
|
||||
* @param error_obj The error object (e.g., OsError, NowPlayingError).
|
||||
*/
|
||||
#define RETURN_ERR(...) \
|
||||
do { \
|
||||
ERROR_LOG(__VA_ARGS__); \
|
||||
return None; \
|
||||
#define ERROR_LOG_LOC(error_obj) \
|
||||
do { \
|
||||
[&](const auto& err) { detail::LogAppError(LogLevel::ERROR, err); }(error_obj); \
|
||||
} while (0)
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
#pragma clang diagnostic pop
|
||||
#endif // __clang__
|
||||
|
|
113
src/util/types.h
113
src/util/types.h
|
@ -1,20 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <array> // std::array alias (Array)
|
||||
#include <cstdlib> // std::getenv, std::free
|
||||
#include <expected> // std::expected alias (Result)
|
||||
#include <format> // std::format
|
||||
#include <map> // std::map alias (Map)
|
||||
#include <memory> // std::shared_ptr and std::unique_ptr aliases (SharedPointer, UniquePointer)
|
||||
#include <optional> // std::optional alias (Option)
|
||||
#include <string> // std::string and std::string_view aliases (String, StringView)
|
||||
#include <system_error> // std::error_code and std::system_error
|
||||
#include <utility> // std::pair alias (Pair)
|
||||
#include <variant> // std::variant alias (NowPlayingError)
|
||||
#include <vector> // std::vector alias (Vec)
|
||||
#include <array> // std::array alias (Array)
|
||||
#include <cstdlib> // std::getenv, std::free
|
||||
#include <expected> // std::expected alias (Result)
|
||||
#include <format> // std::format
|
||||
#include <map> // std::map alias (Map)
|
||||
#include <memory> // std::shared_ptr and std::unique_ptr aliases (SharedPointer, UniquePointer)
|
||||
#include <optional> // std::optional alias (Option)
|
||||
#include <source_location> // std::source_location
|
||||
#include <string> // std::string and std::string_view aliases (String, StringView)
|
||||
#include <system_error> // std::error_code and std::system_error
|
||||
#include <utility> // std::pair alias (Pair)
|
||||
#include <variant> // std::variant alias (NowPlayingError)
|
||||
#include <vector> // std::vector alias (Vec)
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winrt/base.h> // winrt::hresult_error (WindowsError)
|
||||
#include <winrt/base.h> // winrt::hresult_error
|
||||
#elifdef __linux__
|
||||
#include <dbus-cxx.h> // DBus::Error
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------//
|
||||
|
@ -182,14 +185,20 @@ enum class OsErrorCode : u8 {
|
|||
* Used as the error type in Result for many os:: functions.
|
||||
*/
|
||||
struct OsError {
|
||||
String message = "Unknown Error"; ///< A descriptive error message, potentially including platform details.
|
||||
OsErrorCode code = OsErrorCode::Other; ///< The general category of the error.
|
||||
// ReSharper disable CppDFANotInitializedField
|
||||
String message; ///< A descriptive error message, potentially including platform details.
|
||||
OsErrorCode code; ///< The general category of the error.
|
||||
std::source_location location; ///< The source location where the error occurred (file, line, function).
|
||||
// ReSharper restore CppDFANotInitializedField
|
||||
|
||||
OsError(const OsErrorCode errc, String msg) : message(std::move(msg)), code(errc) {}
|
||||
OsError(const OsErrorCode errc, String msg, const std::source_location& loc = std::source_location::current())
|
||||
: message(std::move(msg)), code(errc), location(loc) {}
|
||||
|
||||
explicit OsError(const Exception& exc) : message(exc.what()) {}
|
||||
explicit OsError(const Exception& exc, const std::source_location& loc = std::source_location::current())
|
||||
: message(exc.what()), code(OsErrorCode::InternalError), location(loc) {}
|
||||
|
||||
explicit OsError(const std::error_code& errc) : message(errc.message()) {
|
||||
explicit OsError(const std::error_code& errc, const std::source_location& loc = std::source_location::current())
|
||||
: message(errc.message()), location(loc) {
|
||||
using enum OsErrorCode;
|
||||
using enum std::errc;
|
||||
|
||||
|
@ -205,10 +214,8 @@ struct OsError {
|
|||
default: code = errc.category() == std::generic_category() ? InternalError : PlatformSpecific; break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
explicit OsError(const winrt::hresult_error& e)
|
||||
: message(winrt::to_string(e.message())) /*, original_code(e.code()) */ {
|
||||
explicit OsError(const winrt::hresult_error& e) : message(winrt::to_string(e.message())) {
|
||||
switch (e.code()) {
|
||||
case E_ACCESSDENIED: code = OsErrorCode::PermissionDenied; break;
|
||||
case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
|
||||
|
@ -221,7 +228,8 @@ struct OsError {
|
|||
}
|
||||
}
|
||||
#else
|
||||
OsError(OsErrorCode code_hint, int errno_val) : message(std::system_category().message(errno_val)), code(code_hint) {
|
||||
OsError(const OsErrorCode code_hint, const int errno_val)
|
||||
: message(std::system_category().message(errno_val)), code(code_hint) {
|
||||
using enum OsErrorCode;
|
||||
|
||||
switch (errno_val) {
|
||||
|
@ -233,42 +241,56 @@ struct OsError {
|
|||
}
|
||||
}
|
||||
|
||||
static auto withErrno(const String& context) -> OsError {
|
||||
static auto withErrno(const String& context, const std::source_location& loc = std::source_location::current())
|
||||
-> OsError {
|
||||
const i32 errNo = errno;
|
||||
const String msg = std::system_category().message(errNo);
|
||||
const String fullMsg = std::format("{}: {}", context, msg);
|
||||
|
||||
OsErrorCode code;
|
||||
switch (errNo) {
|
||||
case EACCES:
|
||||
case EPERM: return OsError { OsErrorCode::PermissionDenied, fullMsg };
|
||||
case ENOENT: return OsError { OsErrorCode::NotFound, fullMsg };
|
||||
case ETIMEDOUT: return OsError { OsErrorCode::Timeout, fullMsg };
|
||||
case ENOTSUP: return OsError { OsErrorCode::NotSupported, fullMsg };
|
||||
case EIO: return OsError { OsErrorCode::IoError, fullMsg };
|
||||
case EPERM: code = OsErrorCode::PermissionDenied; break;
|
||||
case ENOENT: code = OsErrorCode::NotFound; break;
|
||||
case ETIMEDOUT: code = OsErrorCode::Timeout; break;
|
||||
case ENOTSUP: code = OsErrorCode::NotSupported; break;
|
||||
case EIO: code = OsErrorCode::IoError; break;
|
||||
case ECONNREFUSED:
|
||||
case ENETDOWN:
|
||||
case ENETUNREACH: return OsError { OsErrorCode::NetworkError, fullMsg };
|
||||
default: return OsError { OsErrorCode::PlatformSpecific, fullMsg };
|
||||
case ENETUNREACH: code = OsErrorCode::NetworkError; break;
|
||||
default: code = OsErrorCode::PlatformSpecific; break;
|
||||
}
|
||||
|
||||
return OsError { code, fullMsg, loc };
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static auto fromDBus(const DBus::Error& err) -> OsError {
|
||||
String name = err.name();
|
||||
#ifdef __linux__
|
||||
static auto fromDBus(const DBus::Error& err, const std::source_location& loc = std::source_location::current())
|
||||
-> OsError {
|
||||
String name = err.name();
|
||||
OsErrorCode codeHint = OsErrorCode::PlatformSpecific;
|
||||
String message;
|
||||
|
||||
if (name == "org.freedesktop.DBus.Error.ServiceUnknown" || name == "org.freedesktop.DBus.Error.NameHasNoOwner")
|
||||
return OsError { OsErrorCode::NotFound, std::format("DBus service/name not found: {}", err.message()) };
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
if (name == "org.freedesktop.DBus.Error.NoReply" || name == "org.freedesktop.DBus.Error.Timeout")
|
||||
return OsError { OsErrorCode::Timeout, std::format("DBus timeout/no reply: {}", err.message()) };
|
||||
if (name == "org.freedesktop.DBus.Error.ServiceUnknown"sv ||
|
||||
name == "org.freedesktop.DBus.Error.NameHasNoOwner"sv) {
|
||||
codeHint = OsErrorCode::NotFound;
|
||||
message = std::format("DBus service/name not found: {}", err.message());
|
||||
} else if (name == "org.freedesktop.DBus.Error.NoReply"sv || name == "org.freedesktop.DBus.Error.Timeout"sv) {
|
||||
codeHint = OsErrorCode::Timeout;
|
||||
message = std::format("DBus timeout/no reply: {}", err.message());
|
||||
} else if (name == "org.freedesktop.DBus.Error.AccessDenied"sv) {
|
||||
codeHint = OsErrorCode::PermissionDenied;
|
||||
message = std::format("DBus access denied: {}", err.message());
|
||||
} else {
|
||||
message = std::format("DBus error: {} - {}", name, err.message());
|
||||
}
|
||||
|
||||
if (name == "org.freedesktop.DBus.Error.AccessDenied")
|
||||
return OsError { OsErrorCode::PermissionDenied, std::format("DBus access denied: {}", err.message()) };
|
||||
|
||||
return OsError { OsErrorCode::PlatformSpecific, std::format("DBus error: {} - {}", name, err.message()) };
|
||||
return OsError { codeHint, message, loc };
|
||||
}
|
||||
#endif // __linux__
|
||||
#endif // _WIN32
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -297,8 +319,7 @@ struct MediaInfo {
|
|||
|
||||
MediaInfo() = default;
|
||||
|
||||
MediaInfo(Option<String> title, Option<String> artist)
|
||||
: title(std::move(title)), artist(std::move(artist)) {}
|
||||
MediaInfo(Option<String> title, Option<String> artist) : title(std::move(title)), artist(std::move(artist)) {}
|
||||
|
||||
MediaInfo(Option<String> title, Option<String> artist, Option<String> album, Option<String> app)
|
||||
: title(std::move(title)), artist(std::move(artist)), album(std::move(album)), app_name(std::move(app)) {}
|
||||
|
@ -333,7 +354,7 @@ enum class EnvError : u8 {
|
|||
* @return A Result containing the value of the environment variable as a String,
|
||||
* or an EnvError if an error occurred.
|
||||
*/
|
||||
inline auto GetEnv(CStr name) -> Result<String, EnvError> {
|
||||
[[nodiscard]] inline auto GetEnv(CStr name) -> Result<String, EnvError> {
|
||||
#ifdef _WIN32
|
||||
char* rawPtr = nullptr;
|
||||
usize bufferSize = 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue