AppPath
Create paths relative to your executable for truly portable applications.
๐ฏ The Problem
When building applications that need to access files (configs, templates, data), you typically have two choices:
-
System directories (
~/.config/,%APPDATA%, etc.) - Great for installed apps, but...- Requires installation
- Spreads files across the system
- Hard to backup/move
- Needs admin rights on some systems
-
Hardcoded paths - Simple but brittle and non-portable
โจ The Solution
AppPath creates paths relative to your executable location, enabling truly portable applications where everything stays together.
use AppPath;
use PathBuf;
// Create paths relative to your executable - accepts any path-like type
let config = try_new?;
let data = try_new?;
// Efficient ownership transfer for owned types
let log_file = "logs/app.log".to_string;
let logs = try_new?; // String is moved
let path_buf = from;
let cache = try_new?; // PathBuf is moved
// Works with any path-like type
let from_path = try_new?;
// Alternative: Use TryFrom for string types
let settings = try_from?;
// Absolute paths are used as-is (for system integration)
let system_log = try_new?;
let windows_temp = try_new?;
// Get the paths for use with standard library functions
println!;
println!;
// Check existence and create directories
if !logs.exists
๐ Features
- ๐ Zero dependencies - Uses only standard library
- ๐ Cross-platform - Windows, Linux, macOS support
- ๐ก๏ธ Safe API - Uses
try_new()following Rust conventions wherenew()implies infallible construction - ๐ง Easy testing - Override base directory with
with_base()method - ๐ Smart path handling - Relative paths resolve to executable directory, absolute paths used as-is
- โก Efficient ownership - Accepts any path-like type with optimal ownership transfer
- ๐ฏ Ergonomic conversions -
TryFromimplementations for string types - ๐ Comprehensive docs - Extensive examples and clear API documentation
๏ฟฝ Path Resolution Behavior
AppPath handles different path types intelligently:
Relative Paths (Recommended for Portable Apps)
// These resolve relative to your executable's directory
let config = try_new?; // โ exe_dir/config.toml
let data = try_new?; // โ exe_dir/data/users.db
let nested = try_new?; // โ exe_dir/logs/app/debug.log
Absolute Paths (For System Integration)
// These are used as-is, ignoring the executable directory
let system_config = try_new?; // โ /etc/myapp/config.toml
let windows_temp = try_new?; // โ C:\temp\cache.dat
let user_home = try_new?; // โ /home/user/.myapp/settings
This design allows your application to:
- โ Stay portable with relative paths for app-specific files
- โ Integrate with system using absolute paths when needed
- โ Be configurable - users can specify either type in config files
๐ Quick Start
Add to your Cargo.toml:
[]
= "0.1"
use AppPath;
use fs;
๐ Ownership and Performance
AppPath accepts any path-like type with optimal ownership handling:
use AppPath;
use ;
// String literals (no allocation)
let config = try_new?;
// Owned String (moves ownership, no clone)
let filename = "data.db".to_string;
let data = try_new?; // filename is moved
// PathBuf (moves ownership, no clone)
let path_buf = from;
let logs = try_new?; // path_buf is moved
// Path reference (efficient conversion)
let path_ref = new;
let cache = try_new?;
// TryFrom for ergonomic string conversions
let settings = try_from?;
let from_string = try_from?;
๐๏ธ Application Structure
Your portable application structure becomes:
myapp.exe # Your executable
โโโ config.toml # AppPath::try_new("config.toml")
โโโ templates/ # AppPath::try_new("templates")
โ โโโ email.html
โ โโโ report.html
โโโ data/ # AppPath::try_new("data")
โ โโโ cache.db
โโโ logs/ # AppPath::try_new("logs")
โโโ app.log
๐งช Testing Support
Override the base directory for testing:
๐ฏ Why Choose AppPath?
vs. Standard Library (std::env::current_dir())
// โ Brittle - depends on where user runs the program
let config = current_dir?.join;
// โ
Reliable - always relative to your executable
let config = try_new?;
vs. System Directories (directories crate)
// โ Scattered across the system
use ProjectDirs;
let proj_dirs = from.unwrap;
let config = proj_dirs.config_dir.join; // ~/.config/MyApp/config.toml
// โ
Everything together with your app
let config = try_new?; // ./config.toml (next to exe)
vs. Manual Path Joining
// โ Verbose and error-prone
let exe_path = current_exe?;
let exe_dir = exe_path.parent.ok_or?;
let config = exe_dir.join;
// โ
Clean and simple
let config = try_new?;
๐ Perfect For
- Portable applications that travel on USB drives
- Development tools that should work anywhere
- Corporate environments where you can't install software
- Containerized applications with predictable layouts
- Embedded systems with simple file structures
- Quick prototypes that need simple file access
๐ Common Usage Patterns
Replace hardcoded paths:
// Instead of brittle hardcoded paths
let config = from; // Depends on working directory
// Use AppPath for reliable, portable paths
let config = try_new?; // Always relative to executable
Replace manual path construction:
// Instead of verbose manual construction
let exe = current_exe?;
let exe_dir = exe.parent.unwrap;
let config = exe_dir.join;
// Use AppPath for clean, simple code
let config = try_new?;
๐ License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
AppPath: Keep it simple, keep it together. ๐ฏ