some docs

This commit is contained in:
Mars 2025-04-25 01:55:04 -04:00
parent 55819ebfe0
commit c9ea3821b6
7 changed files with 342 additions and 244 deletions

View file

@ -1,10 +1,10 @@
#pragma once
#ifdef _WIN32
#include <windows.h>
#include <windows.h> // GetUserNameA
#else
#include <pwd.h>
#include <unistd.h>
#include <pwd.h> // getpwuid
#include <unistd.h> // getuid
#endif
#include <toml++/toml.hpp>
@ -12,46 +12,91 @@
#include "src/util/macros.h"
#include "weather.h"
/// Alias for the location type used in Weather config, can be a city name (String) or coordinates (Coords).
using Location = std::variant<String, Coords>;
/**
* @struct General
* @brief Holds general configuration settings.
*/
struct General {
String name = []() -> String {
String name; ///< Default display name, retrieved from the system.
/**
* @brief Retrieves the default name for the user.
* @return The default name for the user, either from the system or a fallback.
*
* Retrieves the default name for the user based on the operating system.
* On Windows, it uses GetUserNameA to get the username.
* On POSIX systems, it first tries to get the username using getpwuid,
* then checks the USER and LOGNAME environment variables.
*/
static fn getDefaultName() -> String {
#ifdef _WIN32
// Try to get the username using GetUserNameA
Array<char, 256> username;
DWORD size = sizeof(username);
return GetUserNameA(username.data(), &size) ? username.data() : "User";
#else
// Try to get the username using getpwuid
if (const passwd* pwd = getpwuid(getuid()))
return pwd->pw_name;
// Try to get the username using environment variables
if (Result<String, EnvError> envUser = GetEnv("USER"))
return *envUser;
// Finally, try to get the username using LOGNAME
if (Result<String, EnvError> envLogname = GetEnv("LOGNAME"))
return *envLogname;
// If all else fails, return a default name
return "User";
#endif
}();
}
/**
* @brief Parses a TOML table to create a General instance.
* @param tbl The TOML table to parse, containing [general].
* @return A General instance with the parsed values, or defaults otherwise.
*/
static fn fromToml(const toml::table& tbl) -> General {
General gen;
return {
.name = tbl["name"].value_or(gen.name),
};
const toml::node_view<const toml::node> nameNode = tbl["name"];
return { .name = nameNode ? *nameNode.value<String>() : getDefaultName() };
}
};
/**
* @struct NowPlaying
* @brief Holds configuration settings for the Now Playing feature.
*/
struct NowPlaying {
bool enabled = false;
bool enabled = false; ///< Flag to enable or disable the Now Playing feature.
/**
* @brief Parses a TOML table to create a NowPlaying instance.
* @param tbl The TOML table to parse, containing [now_playing].
* @return A NowPlaying instance with the parsed values, or defaults otherwise.
*/
static fn fromToml(const toml::table& tbl) -> NowPlaying { return { .enabled = tbl["enabled"].value_or(false) }; }
};
/**
* @struct Weather
* @brief Holds configuration settings for the Weather feature.
*/
struct Weather {
bool enabled = false;
bool show_town_name = false;
Location location;
String api_key;
String units;
bool enabled = false; ///< Flag to enable or disable the Weather feature.
bool show_town_name = false; ///< Flag to show the town name in the output.
Location location; ///< Location for weather data, can be a city name or coordinates.
String api_key; ///< API key for the weather service.
String units; ///< Units for temperature, either "metric" or "imperial".
/**
* @brief Parses a TOML table to create a Weather instance.
* @param tbl The TOML table to parse, containing [weather].
* @return A Weather instance with the parsed values, or defaults otherwise.
*/
static fn fromToml(const toml::table& tbl) -> Weather {
Weather weather;
@ -81,14 +126,31 @@ struct Weather {
return weather;
}
/**
* @brief Retrieves the weather information based on the configuration.
* @return The weather information as a WeatherOutput object.
*
* This function fetches the weather data based on the configured location,
* API key, and units. It returns a WeatherOutput object containing the
* retrieved weather data.
*/
[[nodiscard]] fn getWeatherInfo() const -> WeatherOutput;
};
/**
* @struct Config
* @brief Holds the application configuration settings.
*/
struct Config {
General general;
NowPlaying now_playing;
Weather weather;
General general; ///< General configuration settings.
NowPlaying now_playing; ///< Now Playing configuration settings.
Weather weather; ///< Weather configuration settings.`
/**
* @brief Parses a TOML table to create a Config instance.
* @param tbl The TOML table to parse, containing [general], [now_playing], and [weather].
* @return A Config instance with the parsed values, or defaults otherwise.
*/
static fn fromToml(const toml::table& tbl) -> Config {
const toml::node_view genTbl = tbl["general"];
const toml::node_view npTbl = tbl["now_playing"];
@ -101,5 +163,13 @@ struct Config {
};
}
/**
* @brief Retrieves the path to the configuration file.
* @return The path to the configuration file.
*
* This function constructs the path to the configuration file based on
* the operating system and user directory. It returns a std::filesystem::path
* object representing the configuration file path.
*/
static fn getInstance() -> Config;
};

View file

@ -5,9 +5,16 @@
#include "../util/types.h"
// NOLINTBEGIN(readability-identifier-naming) - Needs to specifically use `glaze`
/**
* @struct Condition
* @brief Represents weather conditions.
*/
struct Condition {
String description;
String description; ///< Weather condition description (e.g., "clear sky", "light rain").
/**
* @brief Glaze serialization and deserialization for Condition.
*/
struct [[maybe_unused]] glaze {
using T = Condition;
@ -15,9 +22,16 @@ struct Condition {
};
};
/**
* @struct Main
* @brief Represents the main weather data.
*/
struct Main {
f64 temp;
f64 temp; ///< Temperature in degrees (C/F, depending on config).
/**
* @brief Glaze serialization and deserialization for Main.
*/
struct [[maybe_unused]] glaze {
using T = Main;
@ -25,17 +39,30 @@ struct Main {
};
};
/**
* @struct Coords
* @brief Represents geographical coordinates.
*/
struct Coords {
double lat;
double lon;
double lat; ///< Latitude coordinate.
double lon; ///< Longitude coordinate.
};
/**
* @struct WeatherOutput
* @brief Represents the output of the weather API.
*
* Contains main weather data, location name, and weather conditions.
*/
struct WeatherOutput {
Main main;
String name;
Vec<Condition> weather;
usize dt;
Main main; ///< Main weather data (temperature, etc.).
String name; ///< Location name (e.g., city name).
Vec<Condition> weather; ///< List of weather conditions (e.g., clear, rain).
usize dt; ///< Timestamp of the weather data (in seconds since epoch).
/**
* @brief Glaze serialization and deserialization for WeatherOutput.
*/
struct [[maybe_unused]] glaze {
using T = WeatherOutput;

View file

@ -11,17 +11,12 @@ namespace {
const year_month_day ymd = year_month_day { floor<days>(system_clock::now()) };
String month = std::format("{:%B}", ymd);
u32 day = static_cast<u32>(ymd.day());
CStr suffix = day >= 11 && day <= 13 ? "th"
: day % 10 == 1 ? "st"
: day % 10 == 2 ? "nd"
: day % 10 == 3 ? "rd"
: "th";
return std::format("{} {}{}", month, day, suffix);
try {
return std::format(std::locale(""), "{:%B %d}", ymd);
} catch (const std::runtime_error& e) {
ERROR_LOG("Warning: Could not retrieve or use system locale ({}). Falling back to default C locale.", e.what());
return std::format(std::locale::classic(), "{:%B %d}", ymd);
}
}
}

View file

@ -243,9 +243,6 @@ namespace {
}
fn main() -> i32 {
std::locale::global(std::locale(""));
DEBUG_LOG("Global locale set to: {}", std::locale().name());
const Config& config = Config::getInstance();
const SystemData data = SystemData::fetchSystemData(config);

View file

@ -3,56 +3,95 @@
#include "../util/macros.h"
#include "../util/types.h"
/**
* @namespace os
* @brief Provides a platform-abstracted interface for retrieving Operating System information.
*
* This namespace declares functions to get various system details like memory,
* OS version, hardware identifiers, media playback status, etc.
* The actual implementation for each function is platform-specific
* (found in linux.cpp, windows.cpp, macos.cpp).
*/
namespace os {
/**
* @brief Get the amount of installed RAM in bytes.
* @brief Get the total amount of physical RAM installed in the system.
* @return A Result containing the total RAM in bytes (u64) on success,
* or an error message (String) on failure.
*/
fn GetMemInfo() -> Result<u64, String>;
/**
* @brief Get the currently playing song metadata.
* @brief Gets metadata about the currently playing media.
* @return A Result containing the media information (String) on success,
* or an error code (NowPlayingError) on failure.
*/
fn GetNowPlaying() -> Result<String, NowPlayingError>;
/**
* @brief Get the OS version.
* @brief Gets the "pretty" name of the operating system.
* @details Examples: "Ubuntu 24.04.2 LTS", "Windows 11 Pro 24H2", "macOS 15 Sequoia".
* @return A Result containing the OS version String on success,
* or an error message (String) on failure.
*/
fn GetOSVersion() -> Result<String, String>;
/**
* @brief Get the current desktop environment.
* @brief Attempts to retrieve the desktop environment.
* @details This is most relevant on Linux. May check environment variables (XDG_CURRENT_DESKTOP),
* session files, or running processes. On Windows/macOS, it might return a
* UI theme identifier (e.g., "Fluent", "Aqua") or None.
* @return An Option containing the detected DE name String, or None if detection fails or is not applicable.
*/
fn GetDesktopEnvironment() -> Option<String>;
/**
* @brief Get the current window manager.
* @brief Attempts to retrieve the window manager.
* @details On Linux, checks Wayland compositor or X11 WM properties. On Windows, returns "DWM" or similar.
* On macOS, might return "Quartz Compositor" or a specific tiling WM name if active.
* @return A String containing the detected WM name. Might return "Unknown" or a default value if detection fails.
*/
fn GetWindowManager() -> String;
/**
* @brief Get the current shell.
* @brief Attempts to detect the current user shell.
* @details Checks the SHELL environment variable on Linux/macOS. On Windows, inspects the process tree
* to identify known shells like PowerShell, Cmd, or MSYS2 shells (Bash, Zsh).
* @return A String containing the detected shell name (e.g., "Bash", "Zsh", "PowerShell", "Fish").
* May return the full path or "Unknown" as a fallback.
*/
fn GetShell() -> String;
/**
* @brief Get the product family
* @brief Gets a system identifier, often the hardware model or product family.
* @details Examples: "MacBookPro18,3", "Latitude 5420", "ThinkPad T490".
* Implementation varies: reads DMI info on Linux, registry on Windows, sysctl on macOS.
* @return A String containing the host/product identifier. May be empty if retrieval fails.
*/
fn GetHost() -> String;
/**
* @brief Get the kernel version.
* @brief Gets the operating system's kernel version string.
* @details Examples: "5.15.0-76-generic", "10.0.22621", "23.1.0".
* Uses uname() on Linux/macOS, WinRT/registry on Windows.
* @return A String containing the kernel version. May be empty if retrieval fails.
*/
fn GetKernelVersion() -> String;
/**
* @brief Get the number of installed packages.
* @brief Gets the number of installed packages (Linux-specific).
* @details Sums counts from various package managers (dpkg, rpm, pacman, flatpak, snap, etc.).
* Returns 0 on non-Linux platforms or if no package managers are found.
* @return A u64 representing the total count of detected packages.
*/
fn GetPackageCount() -> u64;
fn GetPackageCount() -> u64; // Note: Implementation likely exists only in linux.cpp
/**
* @brief Get the current disk usage.
* @return std::pair<u64, u64> Used space/total space
* @brief Gets the disk usage for the primary/root filesystem.
* @details Uses statvfs on Linux/macOS, GetDiskFreeSpaceExW on Windows.
* @return A Pair<u64, u64> where:
* - first: Used disk space in bytes.
* - second: Total disk space in bytes.
* Returns {0, 0} on failure.
*/
fn GetDiskUsage() -> Pair<u64, u64>;
}

View file

@ -201,7 +201,11 @@ 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
using enum term::Color;
#else
using enum Color;
#endif
const auto [color, levelStr] = [&] {
switch (level) {
@ -213,32 +217,66 @@ fn LogImpl(const LogLevel level, const std::source_location& loc, std::format_st
}
}();
const String filename = std::filesystem::path(loc.file_name()).lexically_normal().string();
Print(BrightWhite, "[{:%X}] ", zoned_time { current_zone(), std::chrono::floor<seconds>(system_clock::now()) });
Print(Emphasis::Bold | color, "{} ", levelStr);
Print(fmt, std::forward<Args>(args)...);
#ifndef NDEBUG
Print(BrightWhite, "\n{:>14} ", "╰──");
Print(Emphasis::Italic | BrightWhite, "{}:{}", filename, loc.line());
Print(
Emphasis::Italic | BrightWhite,
"{}:{}",
std::filesystem::path(loc.file_name()).lexically_normal().string(),
loc.line()
);
#endif
Print("\n");
}
// Suppress unused macro warnings in Clang
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-macros"
#endif
#ifdef NDEBUG
#define DEBUG_LOG(...) 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 INFO_LOG(...)
* @brief Logs a message at the INFO level.
* @details Includes timestamp, level, message, and source location (in debug builds).
* @param ... Format string and arguments for the log message.
*/
#define INFO_LOG(...) LogImpl(LogLevel::INFO, std::source_location::current(), __VA_ARGS__)
/**
* @def WARN_LOG(...)
* @brief Logs a message at the WARN level.
* @details Includes timestamp, level, message, and source location (in debug builds).
* @param ... Format string and arguments for the log message.
*/
#define WARN_LOG(...) LogImpl(LogLevel::WARN, std::source_location::current(), __VA_ARGS__)
/**
* @def ERROR_LOG(...)
* @brief Logs a message at the ERROR level.
* @details Includes timestamp, level, message, and source location (in debug builds).
* @param ... Format string and arguments for the log message.
*/
#define ERROR_LOG(...) LogImpl(LogLevel::ERROR, std::source_location::current(), __VA_ARGS__)
#ifdef __clang__
#pragma clang diagnostic pop
#endif

View file

@ -1,253 +1,170 @@
#pragma once
#include <array>
#include <cstdlib>
#include <expected>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include <array> // std::array alias (Array)
#include <cstdlib> // std::getenv, std::free
#include <expected> // std::expected alias (Result)
#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 <utility> // std::pair alias (Pair)
#include <variant> // std::variant alias (NowPlayingError)
#include <vector> // std::vector alias (Vec)
#ifdef _WIN32
// ReSharper disable once CppUnusedIncludeDirective
#include <guiddef.h>
#include <variant>
#include <winrt/base.h>
#else
#include <variant>
#include <winrt/base.h> // winrt::hresult_error (WindowsError)
#endif
/**
* @typedef u8
* @brief Represents an 8-bit unsigned integer.
*
* This type alias is used for 8-bit unsigned integers, ranging from 0 to 255.
* It is based on the std::uint8_t type.
*/
using u8 = std::uint8_t;
//----------------------------------------------------------------//
// Integer Type Aliases //
// Provides concise names for standard fixed-width integer types. //
//----------------------------------------------------------------//
using u8 = std::uint8_t; ///< 8-bit unsigned integer.
using u16 = std::uint16_t; ///< 16-bit unsigned integer.
using u32 = std::uint32_t; ///< 32-bit unsigned integer.
using u64 = std::uint64_t; ///< 64-bit unsigned integer.
using i8 = std::int8_t; ///< 8-bit signed integer.
using i16 = std::int16_t; ///< 16-bit signed integer.
using i32 = std::int32_t; ///< 32-bit signed integer.
using i64 = std::int64_t; ///< 64-bit signed integer.
//-----------------------------------------------------------//
// Floating-Point Type Aliases //
// Provides concise names for standard floating-point types. //
//-----------------------------------------------------------//
using f32 = std::float_t; ///< 32-bit floating-point number.
using f64 = std::double_t; ///< 64-bit floating-point number.
//-------------------------------------------------//
// Size Type Aliases //
// Provides concise names for standard size types. //
//-------------------------------------------------//
using usize = std::size_t; ///< Unsigned size type (result of sizeof).
using isize = std::ptrdiff_t; ///< Signed size type (result of pointer subtraction).
//---------------------------------------------------//
// String Type Aliases //
// Provides concise names for standard string types. //
//---------------------------------------------------//
using String = std::string; ///< Owning, mutable string.
using StringView = std::string_view; ///< Non-owning view of a string.
using CStr = const char*; ///< Pointer to a null-terminated C-style string.
//----------------------------------------------------//
// Standard Library Type Aliases //
// Provides concise names for standard library types. //
//----------------------------------------------------//
using Exception = std::exception; ///< Standard exception type.
/**
* @typedef u16
* @brief Represents a 16-bit unsigned integer.
*
* This type alias is used for 16-bit unsigned integers, ranging from 0 to 65,535.
* It is based on the std::uint16_t type.
*/
using u16 = std::uint16_t;
/**
* @typedef u32
* @brief Represents a 32-bit unsigned integer.
*
* This type alias is used for 32-bit unsigned integers, ranging from 0 to 4,294,967,295.
* It is based on the std::uint32_t type.
*/
using u32 = std::uint32_t;
/**
* @typedef u64
* @brief Represents a 64-bit unsigned integer.
*
* This type alias is used for 64-bit unsigned integers, ranging from 0 to
* 18,446,744,073,709,551,615. It is based on the std::uint64_t type.
*/
using u64 = std::uint64_t;
// Type Aliases for Signed Integers
/**
* @typedef i8
* @brief Represents an 8-bit signed integer.
*
* This type alias is used for 8-bit signed integers, ranging from -128 to 127.
* It is based on the std::int8_t type.
*/
using i8 = std::int8_t;
/**
* @typedef i16
* @brief Represents a 16-bit signed integer.
*
* This type alias is used for 16-bit signed integers, ranging from -32,768 to 32,767.
* It is based on the std::int16_t type.
*/
using i16 = std::int16_t;
/**
* @typedef i32
* @brief Represents a 32-bit signed integer.
*
* This type alias is used for 32-bit signed integers, ranging from -2,147,483,648 to 2,147,483,647.
* It is based on the std::int32_t type.
*/
using i32 = std::int32_t;
/**
* @typedef i64
* @brief Represents a 64-bit signed integer.
*
* This type alias is used for 64-bit signed integers, ranging from -9,223,372,036,854,775,808 to
* 9,223,372,036,854,775,807. It is based on the std::int64_t type.
*/
using i64 = std::int64_t;
// Type Aliases for Floating-Point Numbers
/**
* @typedef f32
* @brief Represents a 32-bit floating-point number.
*
* This type alias is used for 32-bit floating-point numbers, which follow the IEEE 754 standard.
* It is based on the float type.
*/
using f32 = float;
/**
* @typedef f64
* @brief Represents a 64-bit floating-point number.
*
* This type alias is used for 64-bit floating-point numbers, which follow the IEEE 754 standard.
* It is based on the double type.
*/
using f64 = double;
// Type Aliases for Size Types
/**
* @typedef usize
* @brief Represents an unsigned size type.
*
* This type alias is used for representing the size of objects in bytes.
* It is based on the std::size_t type, which is the result type of the sizeof operator.
*/
using usize = std::size_t;
/**
* @typedef isize
* @brief Represents a signed size type.
*
* This type alias is used for representing pointer differences.
* It is based on the std::ptrdiff_t type, which is the signed integer type returned when
* subtracting two pointers.
*/
using isize = std::ptrdiff_t;
/**
* @typedef String
* @brief Represents a string.
*/
using String = std::string;
/**
* @typedef StringView
* @brief Represents a string view.
*
* This type alias is used for non-owning views of strings, allowing for efficient string manipulation
* without copying the underlying data.
*/
using StringView = std::string_view;
/**
* @typedef Exception
* @brief Represents a generic exception type.
*/
using Exception = std::exception;
/**
* @typedef Expected
* @brief Represents an expected value or an error.
* @typedef Result
* @brief Alias for std::expected<Tp, Er>. Represents a value that can either be
* a success value of type Tp or an error value of type Er.
* @tparam Tp The type of the success value.
* @tparam Er The type of the error value.
*/
template <typename Tp, typename Er>
using Result = std::expected<Tp, Er>;
/**
* @typedef Unexpected
* @brief Represents an unexpected error.
* @typedef Err
* @brief Alias for std::unexpected<Er>. Used to construct a Result in an error state.
* @tparam Er The type of the error value.
*/
template <typename Er>
using Err = std::unexpected<Er>;
/**
* @typedef Optional
* @brief Represents an optional value.
* @typedef Option
* @brief Alias for std::optional<Tp>. Represents a value that may or may not be present.
* @tparam Tp The type of the potential value.
*/
template <typename Tp>
using Option = std::optional<Tp>;
/**
* @typedef Array
* @brief Represents a fixed-size array.
* @brief Alias for std::array<Tp, sz>. Represents a fixed-size array.
* @tparam Tp The element type.
* @tparam sz The size of the array.
*/
template <typename Tp, usize sz>
using Array = std::array<Tp, sz>;
/**
* @typedef Vec
* @brief Represents a dynamic array (vector).
* @brief Alias for std::vector<Tp>. Represents a dynamic-size array (vector).
* @tparam Tp The element type.
*/
template <typename Tp>
using Vec = std::vector<Tp>;
/**
* @typedef Pair
* @brief Represents a pair of values.
* @brief Alias for std::pair<T1, T2>. Represents a pair of values.
* @tparam T1 The type of the first element.
* @tparam T2 The type of the second element.
*/
template <typename T1, typename T2>
using Pair = std::pair<T1, T2>;
/**
* @typedef Map
* @brief Represents a map (dictionary) of key-value pairs.
* @brief Alias for std::map<Key, Val>. Represents an ordered map (dictionary).
* @tparam Key The key type.
* @tparam Val The value type.
*/
template <typename Key, typename Val>
using Map = std::map<Key, Val>;
/**
* @typedef SharedPointer
* @brief Represents a shared pointer.
*
* This type alias is used for shared ownership of dynamically allocated objects.
* @brief Alias for std::shared_ptr<Tp>. Manages shared ownership of a dynamically allocated object.
* @tparam Tp The type of the managed object.
*/
template <typename Tp>
using SharedPointer = std::shared_ptr<Tp>;
/**
* @typedef UniquePointer
* @brief Represents a unique pointer.
*
* This type alias is used for unique ownership of dynamically allocated objects.
* @brief Alias for std::unique_ptr<Tp, Dp>. Manages unique ownership of a dynamically allocated object.
* @tparam Tp The type of the managed object.
* @tparam Dp The deleter type (defaults to std::default_delete<Tp>).
*/
template <typename Tp, typename Dp>
template <typename Tp, typename Dp = std::default_delete<Tp>>
using UniquePointer = std::unique_ptr<Tp, Dp>;
/**
* @typedef CStr
* @brief Represents a C string (const char*).
*
* This type alias is used for C-style strings, which are null-terminated arrays of characters.
*/
using CStr = const char*;
//--------------------------------------------------------//
// Application-Specific Type Aliases //
// Provides concise names for application-specific types. //
//--------------------------------------------------------//
/**
* @enum NowPlayingCode
* @brief Represents error codes for Now Playing functionality.
* @brief Error codes specific to the Now Playing feature.
*/
enum class NowPlayingCode : u8 {
NoPlayers,
NoActivePlayer,
NoPlayers, ///< No media players were found (e.g., no MPRIS services on Linux).
NoActivePlayer, ///< Players were found, but none are currently active or playing.
};
#ifdef _WIN32
/**
* @typedef WindowsError
* @brief Represents a Windows-specific error.
*/
using WindowsError = winrt::hresult_error;
using WindowsError = winrt::hresult_error; ///< Alias for WinRT HRESULT error type.
#endif
// Unified error type
/**
* @typedef NowPlayingError
* @brief Represents the possible errors returned by "Now Playing" functions.
* It's a variant that can hold either a generic NowPlayingCode,
* a platform-specific error (WindowsError on Windows, String on others),
* or potentially other error types if extended.
*/
using NowPlayingError = std::variant<
NowPlayingCode,
#ifdef _WIN32
@ -257,30 +174,45 @@ using NowPlayingError = std::variant<
#endif
>;
enum class EnvError : u8 { NotFound, AccessError };
/**
* @enum EnvError
* @brief Error codes for environment variable retrieval.
*/
enum class EnvError : u8 {
NotFound, ///< Environment variable not found.
AccessError, ///< Access error when trying to retrieve the variable.
};
/**
* @brief Safely retrieves an environment variable.
* @param name The name of the environment variable to retrieve.
* @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> {
#ifdef _WIN32
char* rawPtr = nullptr;
usize bufferSize = 0;
// Use _dupenv_s to safely retrieve environment variables on Windows
const i32 err = _dupenv_s(&rawPtr, &bufferSize, name);
const UniquePointer<char, decltype(&free)> ptrManager(rawPtr, free);
if (err != 0)
return Err(EnvError::AccessError);
return Err(EnvError::AccessError); // Error retrieving environment variable
if (!ptrManager)
return Err(EnvError::NotFound);
return Err(EnvError::NotFound); // Environment variable not found
return ptrManager.get();
#else
// Use std::getenv to retrieve environment variables on POSIX systems
const CStr value = std::getenv(name);
if (!value)
return Err(EnvError::NotFound);
return Err(EnvError::NotFound); // Environment variable not found
return String(value);
return value;
#endif
}