Crate app_path

Source
Expand description

§app-path

Create portable applications that keep files together with the executable.

§Quick Start

use app_path::{AppPath, app_path, try_app_path};

// Simple macro usage - files relative to your executable
let config = app_path!("config.toml");        // → /path/to/exe/config.toml
let database = app_path!("data/users.db");    // → /path/to/exe/data/users.db
let logs = app_path!("logs/app.log");         // → /path/to/exe/logs/app.log

// Environment variable overrides for deployment
let config_deploy = app_path!("config.toml", env = "CONFIG_PATH");
// → Uses CONFIG_PATH if set, otherwise /path/to/exe/config.toml

let db_deploy = app_path!("data/users.db", override = std::env::var("DATABASE_PATH").ok());
// → Uses DATABASE_PATH if set, otherwise /path/to/exe/data/users.db

// Advanced override patterns for XDG/system integration
let config_xdg = app_path!("config", fn = || {
    std::env::var("XDG_CONFIG_HOME")
        .or_else(|_| std::env::var("HOME").map(|h| format!("{h}/.config/myapp")))
        .ok()
});
// → /home/user/.config/myapp (Linux) or /path/to/exe/config (fallback)

// Complex override logic with block expressions
let data_dir = app_path!("data", override = {
    std::env::var("DATA_DIR")
        .or_else(|_| std::env::var("XDG_DATA_HOME").map(|p| format!("{p}/myapp")))
        .ok()
});
// → Uses DATA_DIR, then XDG_DATA_HOME/myapp, finally /path/to/exe/data

// Variable capturing in complex expressions
let version = "1.0";
let versioned_cache = app_path!(format!("cache-{version}"));
// → /path/to/exe/cache-1.0

let temp_with_env = app_path!(format!("temp-{version}"), env = "TEMP_DIR");
// → Uses TEMP_DIR if set, otherwise /path/to/exe/temp-1.0

// Fallible variants for libraries (return Result instead of panicking)
let config_safe = try_app_path!("config.toml")?;
// → Ok(/path/to/exe/config.toml) or Err(AppPathError)

let db_safe = try_app_path!("data/users.db", env = "DATABASE_PATH")?;
// → Ok with DATABASE_PATH or default path, or Err(AppPathError)

let cache_safe = try_app_path!(format!("cache-{version}"))?;
// → Ok(/path/to/exe/cache-1.0) or Err(AppPathError)

// Constructor API (alternative to macros)
let traditional = AppPath::new("config.toml");
// → /path/to/exe/config.toml (panics on system failure)

let with_override = AppPath::with_override("config.toml", std::env::var("CONFIG_PATH").ok());
// → Uses CONFIG_PATH if set, otherwise /path/to/exe/config.toml

let fallible = AppPath::try_new("config.toml")?; // For libraries
// → Ok(/path/to/exe/config.toml) or Err(AppPathError)

// Works like standard paths - auto-derefs to &Path
if config.exists() {
    let content = std::fs::read_to_string(&config)?;
    // → Reads file content if config.toml exists
}

// Directory creation with clear intent
logs.create_parents()?;                 // Creates logs/ directory for the file
app_path!("cache").create_dir()?;       // Creates cache/ directory itself
// → Both create directories if they don't exist

§Key Features

  • Portable: Relative paths resolve to executable directory
  • System integration: Absolute paths work as-is
  • Zero dependencies: Only standard library
  • High performance: Static caching, minimal allocations
  • Thread-safe: Concurrent access safe

§API Design

§Function Variants

This crate provides both panicking and fallible variants for most operations:

Panicking (Recommended)Fallible (Libraries)Use Case
AppPath::new()AppPath::try_new()Constructor methods
app_path!try_app_path!Convenient macros
exe_dir()try_exe_dir()Direct directory access

§Macro Syntax Variants

Both app_path! and try_app_path! macros support four syntax forms for maximum flexibility:

// 1. Direct value
let config = app_path!("config.toml");
// → /path/to/exe/config.toml

// 2. With environment override
let config = app_path!("config.toml", env = "CONFIG_PATH");
// → Uses CONFIG_PATH if set, otherwise /path/to/exe/config.toml

// 3. With optional override value
let config = app_path!("config.toml", override = std::env::var("CONFIG_PATH").ok());
// → Uses CONFIG_PATH if available, otherwise /path/to/exe/config.toml

// 4. With function-based override
let config = app_path!("config.toml", fn = || {
    std::env::var("CONFIG_PATH").ok()
});
// → Uses function result if Some, otherwise /path/to/exe/config.toml

§Variable Capturing

Both macros support variable capturing in complex expressions:

let version = "1.0";
let cache = app_path!(format!("cache-{version}")); // Captures `version`
// → /path/to/exe/cache-1.0

// Useful in closures and async blocks
async fn process_data(id: u32) {
    let output = app_path!(format!("output-{id}.json")); // Captures `id`
    // → /path/to/exe/output-123.json (where id = 123)
    // ... async processing
}

§Panic Conditions

AppPath::new() and exe_dir() panic only if executable location cannot be determined:

  • std::env::current_exe() fails (extremely rare system failure)
  • Executable path is empty (indicates system corruption)

These represent unrecoverable system failures that occur at application startup. After the first successful call, the executable directory is cached and subsequent calls never panic.

For libraries or applications requiring graceful error handling, use the fallible variants AppPath::try_new() and try_exe_dir() instead.

§Ecosystem Integration

app-path integrates seamlessly with popular Rust path crates through standard trait implementations:

§UTF-8 Path Serialization (camino)

use app_path::app_path;
use camino::Utf8PathBuf;

let static_dir = app_path!("web/static", env = "STATIC_DIR");
let utf8_static = Utf8PathBuf::try_from(static_dir)?; // Direct conversion

// Safe JSON serialization with UTF-8 guarantees
let config = serde_json::json!({ "static_files": utf8_static });

§Cross-Platform Path Types (typed-path)

use app_path::app_path;
use typed_path::{WindowsPath, UnixPath};

let dist_dir = app_path!("dist");

// Platform-specific paths with proper separators
let win_path = WindowsPath::new(&dist_dir);  // Uses \ on Windows  
let unix_path = UnixPath::new(&dist_dir);    // Uses / on Unix

Macros§

app_path
Convenience macro for creating AppPath instances with optional environment variable overrides.
try_app_path
Fallible version of app_path! that returns a Result instead of panicking.

Structs§

AppPath
Creates paths relative to the executable location for portable applications.

Enums§

AppPathError
Error type for AppPath operations.

Functions§

exe_dir
Get the executable’s directory.
try_exe_dir
Get the executable’s directory (fallible).