Thank you for your interest in contributing to Draconis++! This document provides guidelines and information to help you get started.
- Getting Started
- Architecture Overview
- Custom Type System
- Platform-Specific Implementation Guide
- Code Style Guidelines
- Submitting Changes
- C++26 compiler (Clang 17+, GCC 13+, or MSVC 19.36+)
- Meson (1.1+) and Ninja
- just (optional, for simplified commands)
# Using just (recommended)
just setup # Configure the build
just build # Build the project
just test # Run tests
just run # Build and run
# Using Meson directly
meson setup build
meson compile -C build
meson test -C buildKey build options can be set via meson configure:
| Option | Type | Default | Description |
|---|---|---|---|
weather |
feature | enabled | Weather data fetching |
nowplaying |
feature | enabled | Now playing media info |
packagecount |
feature | enabled | Package count functionality |
caching |
feature | enabled | Caching system |
plugins |
feature | enabled | Plugin support |
precompiled_config |
bool | false | Use compile-time configuration |
Headers exposed to consumers of the library. These define the stable interface.
- Core/: System data structures (
System.hpp,Package.hpp) - Services/: Service interfaces for external data (weather, packages)
- Utils/: Type aliases, error handling, macros
The core library containing all platform-agnostic and platform-specific code.
- Core/: Cross-platform implementations
- OS/: Platform-specific code (Windows, Linux, macOS, BSD, etc.)
- Services/: External service integrations
- Wrappers/: Thin wrappers around third-party libraries
The user-facing application that consumes the library.
- Config/: TOML configuration parsing and management
- Core/:
SystemInfoclass that aggregates all system data - UI/: Terminal output formatting and theming
Draconis++ uses custom type aliases defined in include/Drac++/Utils/Types.hpp to improve code readability and express intent more clearly.
- Consistency: Uniform naming across the codebase
- Expressiveness: Types like
Option<T>andResult<T>convey meaning - Safety: Wrapper types prevent common errors
- Rust-like ergonomics: Familiar patterns for developers from other languages
| Alias | Standard Type | Description |
|---|---|---|
u8 |
std::uint8_t |
8-bit unsigned integer |
u16 |
std::uint16_t |
16-bit unsigned integer |
u32 |
std::uint32_t |
32-bit unsigned integer |
u64 |
std::uint64_t |
64-bit unsigned integer |
i8 |
std::int8_t |
8-bit signed integer |
i16 |
std::int16_t |
16-bit signed integer |
i32 |
std::int32_t |
32-bit signed integer |
i64 |
std::int64_t |
64-bit signed integer |
f32 |
float |
32-bit floating-point |
f64 |
double |
64-bit floating-point |
usize |
std::size_t |
Unsigned size type |
isize |
std::ptrdiff_t |
Signed size type |
| Alias | Standard Type | Description |
|---|---|---|
String |
std::string |
Owning string |
StringView |
std::string_view |
Non-owning string view |
WString |
std::wstring |
Wide string (Windows) |
| Alias | Standard Type | Description |
|---|---|---|
Vec<T> |
std::vector<T> |
Dynamic array |
Array<T, N> |
std::array<T, N> |
Fixed-size array |
Span<T> |
std::span<T> |
Non-owning view of sequence |
Map<K, V> |
std::map<K, V> |
Ordered map |
UnorderedMap<K,V> |
std::unordered_map<K, V> |
Hash map |
Pair<T1, T2> |
std::pair<T1, T2> |
Pair of values |
| Alias | Standard Type | Description |
|---|---|---|
UniquePointer<T> |
std::unique_ptr<T> |
Unique ownership |
SharedPointer<T> |
std::shared_ptr<T> |
Shared ownership |
| Alias | Standard Type | Description |
|---|---|---|
Option<T> |
std::optional<T> |
Value that may be absent |
Result<T,E> |
std::expected<T, E> |
Value or error |
Err<E> |
std::unexpected<E> |
Error wrapper for Result |
None |
std::nullopt |
Empty Option value |
// Create an Option with a value
Option<int> x = Some(42);
// Create an empty Option
Option<int> y = None;
// Return success from a function returning Result
return Result<String>{"success"};
// Return error from a function returning Result
return Err(DracError("something went wrong"));| Alias | Standard Type | Description |
|---|---|---|
Mutex |
std::mutex |
Mutex lock |
LockGuard |
std::lock_guard<Mutex> |
RAII lock guard |
Future<T> |
std::future<T> |
Asynchronous result |
- Always use custom types in new code
- Import types in
.cppfiles using:using namespace draconis::utils::types;
- Avoid
using namespacein header files — use fully qualified names - Prefer
Result<T>over exceptions for error handling
Platform-specific code lives in src/Lib/OS/. Each platform has its own implementation file.
| File | Platform |
|---|---|
Windows.cpp |
Windows 10/11 |
Linux.cpp |
Linux (glibc/musl) |
macOS.cpp |
macOS 12+ |
BSD.cpp |
FreeBSD, OpenBSD, NetBSD |
Haiku.cpp |
Haiku OS |
Serenity.cpp |
SerenityOS |
Switch.cpp |
Nintendo Switch (devkitPro) |
- Check for existing abstraction in
include/Drac++/Core/ - Implement the function in the appropriate
OS/*.cppfile - Use preprocessor guards when necessary:
#ifdef __linux__
// Linux-specific implementation
#elifdef _WIN32
// Windows-specific implementation
#elifdef __APPLE__
// macOS-specific implementation
#endifThe build system defines these macros:
| Macro | Condition |
|---|---|
DRAC_ARCH_X86_64 |
x86_64 architecture |
DRAC_ARCH_AARCH64 |
ARM64 architecture |
DRAC_ARCH_64BIT |
64-bit pointer size |
DRAC_DEBUG |
Debug build |
-
Declare in header (
include/Drac++/Core/System.hpp):namespace draconis::core { auto GetBatteryLevel() -> Result<u8>; }
-
Implement per-platform (
src/Lib/OS/Windows.cpp):namespace draconis::core { auto GetBatteryLevel() -> Result<u8> { SYSTEM_POWER_STATUS status; if (!GetSystemPowerStatus(&status)) return Err(DracError("Failed to get power status")); return status.BatteryLifePercent; } }
-
Implement for other platforms or provide a fallback:
// Linux.cpp auto GetBatteryLevel() -> Result<u8> { // Read from /sys/class/power_supply/... }
- Use
WStringfor Windows API calls requiringwchar_t* - Convert with
ConvertWStringToUTF8()/ConvertUTF8ToWString() - Link against:
dwmapi,windowsapp,setupapi,dxgi
- Objective-C++ code goes in
src/Lib/OS/macOS/ - Use
.mmextension for Objective-C++ files - Link frameworks via
appleframeworksdependency
- Optional dependencies:
xcb,wayland-client,dbus-1,pugixml - Check feature flags:
DRAC_USE_XCB,DRAC_USE_WAYLAND - Read system info from
/proc/,/sys/,/etc/
- C++26 standard
- 2-space indentation (configured in
.clang-format) constexpr/constevalwhere possiblenoexceptfor non-throwing functions[[nodiscard]]for functions whose return value matters
| Element | Style | Example |
|---|---|---|
| Types/Classes | PascalCase | SystemInfo |
| Functions | PascalCase | GetCpuInfo() |
| Variables | camelCase | cpuCount |
| Constants | SCREAMING_CASE | MAX_BUFFER_SIZE |
| Namespaces | lowercase | draconis::core |
// Use trailing return type with 'fn' macro (defined as 'auto')
fn GetSystemName() -> Result<String>;
// Mark pure functions as [[nodiscard]]
[[nodiscard]] fn CalculateHash(StringView input) -> u64;
// Use noexcept when appropriate
fn SafeOperation() noexcept -> bool;// Prefer Result<T> over exceptions
fn ReadFile(StringView path) -> Result<String> {
std::ifstream file(path);
if (!file)
return Err(DracError("Failed to open file"));
// ...
return content;
}
// Propagate errors explicitly
fn ProcessData() -> Result<Data> {
auto content = ReadFile("config.toml");
if (!content)
return Err(content.error());
// Process content...
}- Fork the repository
- Create a branch for your feature/fix
- Make changes following the style guidelines
- Test your changes:
just test - Format code:
just format - Submit a pull request
Use Conventional Commits:
feat: add battery level monitoring
fix: correct memory leak in cache manager
docs: update contributing guide
refactor: simplify OS detection logic
perf: optimize string conversion on Windows
- Descriptive title summarizing the change
- Reference issues if applicable (
Fixes #123) - Include tests for new functionality
- Update documentation if adding public API
- Keep changes focused — one feature/fix per PR
If you have questions or need help, feel free to open an issue or discussion on the repository.
Thank you for contributing to Draconis++!