Macro try_app_path

Source
macro_rules! try_app_path {
    ($path:expr) => { ... };
    ($path:expr, env = $env_var:expr) => { ... };
    ($path:expr, override = $override_expr:expr) => { ... };
    ($path:expr, fn = $override_fn:expr) => { ... };
}
Expand description

Fallible version of app_path! that returns a Result instead of panicking.

This macro provides the same convenient syntax as app_path! but returns Result<AppPath, AppPathError> for explicit error handling. Perfect for libraries and applications that need graceful error handling.

§Syntax

  • try_app_path!(path) - Simple path creation (equivalent to AppPath::try_new(path))
  • try_app_path!(path, env = "VAR_NAME") - With environment variable override
  • try_app_path!(path, override = expression) - With any optional override expression
  • try_app_path!(path, fn = function) - With function-based override logic

§Examples

§Basic Usage

use app_path::{try_app_path, AppPathError};

fn setup_config() -> Result<(), AppPathError> {
    let config = try_app_path!("config.toml")?;
    let database = try_app_path!("data/users.db")?;
     
    // Use paths normally
    if config.exists() {
        println!("Config found at: {}", config.display());
    }
     
    Ok(())
}

§Environment Variable Overrides

use app_path::try_app_path;

fn setup_logging() -> Result<(), Box<dyn std::error::Error>> {
    // Uses "logs/app.log" by default, LOG_PATH env var if set
    let log_file = try_app_path!("logs/app.log", env = "LOG_PATH")?;
    log_file.ensure_parent_dirs()?;
     
    std::fs::write(&log_file, "Application started")?;
    Ok(())
}

§Custom Override Logic

use app_path::try_app_path;

fn get_data_dir() -> Option<String> {
    std::env::var("XDG_DATA_HOME")
        .or_else(|_| std::env::var("HOME").map(|h| format!("{h}/.local/share")))
        .ok()
}

fn setup_data() -> Result<(), Box<dyn std::error::Error>> {
    let data_dir = try_app_path!("data", override = get_data_dir())?;
    data_dir.ensure_dir_exists()?;
    Ok(())
}

§Function-Based Override

use app_path::try_app_path;

fn setup_cache() -> Result<(), Box<dyn std::error::Error>> {
    let cache_dir = try_app_path!("cache", fn = || {
        std::env::var("XDG_CACHE_HOME")
            .or_else(|_| std::env::var("HOME").map(|h| format!("{h}/.cache")))
            .ok()
    })?;
    cache_dir.ensure_dir_exists()?;
    Ok(())
}

§Error Handling Patterns

use app_path::{try_app_path, AppPathError};

match try_app_path!("config.toml") {
    Ok(config) => {
        println!("Config path: {}", config.display());
    }
    Err(AppPathError::ExecutableNotFound(msg)) => {
        eprintln!("Cannot determine executable location: {msg}");
    }
    Err(AppPathError::InvalidExecutablePath(msg)) => {
        eprintln!("Invalid executable path: {msg}");
    }
}

§Library Usage

use app_path::{try_app_path, AppPathError};

/// Library function that gracefully handles path errors
pub fn load_user_config() -> Result<String, Box<dyn std::error::Error>> {
    let config_path = try_app_path!("config.toml", env = "USER_CONFIG")?;
         
    if !config_path.exists() {
        return Err("Config file not found".into());
    }
     
    let content = std::fs::read_to_string(&config_path)?;
    Ok(content)
}

§Comparison with app_path!

Featureapp_path!try_app_path!
Return typeAppPathResult<AppPath, AppPathError>
Error handlingPanics on failureReturns Err on failure
Use caseApplicationsLibraries, explicit error handling
SyntaxSameSame
PerformanceSameSame

§When to Use

  • Use try_app_path! for libraries, when you need graceful error handling, or when integrating with other fallible operations
  • Use app_path! for applications where you want to fail fast on system errors

§See Also