dir_spec 0.2.0

A cross-platform Rust library for resolving XDG and platform-specific directories with proper fallbacks.
Documentation

dir_spec

A cross-platform Rust library for resolving XDG and platform-specific directories with proper fallbacks.

Why Another Directory Library?

Most existing directory libraries (like dirs) ignore XDG environment variables on macOS and Windows, defaulting to platform-specific locations even when users have explicitly set XDG variables. This crate prioritizes XDG compliance across all platforms while providing sensible platform-specific fallbacks.

Features

  • XDG-first approach: Respects XDG environment variables on all platforms
  • Platform-aware fallbacks: Uses native conventions when XDG variables aren't set
  • Cross-platform: Works on Linux, macOS, and Windows
  • Zero dependencies: Only uses std library
  • Type-safe: Returns Option<PathBuf> for simple error handling

Usage

Add this to your Cargo.toml:

[dependencies]
dir_spec = "0.2.0"

Basic usage:

use dir_spec::Dir;

fn main() {
    // Get config directory (respects XDG_CONFIG_HOME if set)
    if let Some(config_dir) = Dir::config_home() {
        println!("Config: {}", config_dir.display());
    }
    
    // Get cache directory (respects XDG_CACHE_HOME if set)
    if let Some(cache_dir) = Dir::cache_home() {
        println!("Cache: {}", cache_dir.display());
    }
    
    // Get user's home directory
    if let Some(home_dir) = Dir::home() {
        println!("Home: {}", home_dir.display());
    }
}

Supported Directories

Method XDG Variable Linux Default macOS Default Windows Default
bin_home() XDG_BIN_HOME ~/.local/bin ~/.local/bin %LOCALAPPDATA%\Programs
cache_home() XDG_CACHE_HOME ~/.cache ~/Library/Caches %LOCALAPPDATA%
config_home() XDG_CONFIG_HOME ~/.config ~/Library/Application Support %APPDATA%
data_home() XDG_DATA_HOME ~/.local/share ~/Library/Application Support %APPDATA%
desktop() XDG_DESKTOP_DIR ~/Desktop ~/Desktop %USERPROFILE%\Desktop
documents() XDG_DOCUMENTS_DIR ~/Documents ~/Documents %USERPROFILE%\Documents
downloads() XDG_DOWNLOAD_DIR ~/Downloads ~/Downloads %USERPROFILE%\Downloads
music() XDG_MUSIC_DIR ~/Music ~/Music %USERPROFILE%\Music
pictures() XDG_PICTURES_DIR ~/Pictures ~/Pictures %USERPROFILE%\Pictures
publicshare() XDG_PUBLICSHARE_DIR ~/Public ~/Public C:\Users\Public
runtime() XDG_RUNTIME_DIR $TMPDIR or /tmp $TMPDIR or /tmp %TEMP%
state_home() XDG_STATE_HOME ~/.local/state ~/Library/Application Support %LOCALAPPDATA%
templates() XDG_TEMPLATES_DIR ~/Templates ~/Templates %USERPROFILE%\Templates
videos() XDG_VIDEOS_DIR ~/Videos ~/Movies %USERPROFILE%\Videos
home() HOME / USERPROFILE $HOME $HOME %USERPROFILE%

XDG Environment Variable Priority

This crate always checks XDG environment variables first, regardless of platform:

// This will use XDG_CONFIG_HOME if set, even on macOS/Windows
export XDG_CONFIG_HOME="/custom/config/path"

let config = Dir::config_home(); // Returns Some("/custom/config/path")

If XDG variables aren't set, the crate falls back to platform-appropriate defaults.

Cross-Platform Behavior

Linux

Follows XDG Base Directory Specification defaults when XDG variables aren't set.

macOS

  • Respects XDG variables if set (common among CLI tool users)
  • Falls back to native macOS locations (~/Library/Application Support, etc.)
  • Uses ~/Movies for videos (not ~/Videos)

Windows

  • Respects XDG variables if set
  • Falls back to Windows conventions (%APPDATA%, %LOCALAPPDATA%, etc.)
  • Public directory points to system-wide C:\Users\Public

Error Handling

All methods return Option<PathBuf>. Methods return None when:

  • Home directory cannot be determined
  • Required environment variables are missing (Windows-specific cases)
  • Platform-specific directory resolution fails
match Dir::config_home() {
    Some(path) => println!("Config dir: {}", path.display()),
    None => eprintln!("Failed to get config dir"),
}

// Or using if-let
if let Some(config_path) = Dir::config_home() {
    println!("Config dir: {}", config_path.display());
}

// For fallback handling
let config_dir = Dir::config_home().unwrap_or_else(|| {
    // Fallback to current directory or panic, depending on your needs
    std::env::current_dir().expect("Cannot determine current directory")
});

Migration from 0.1.x

Version 0.2.0 introduces breaking changes:

  • Return type changed: Methods now return Option<PathBuf> instead of Result<PathBuf>
  • Removed deprecated methods: All *_dir() variants have been removed
  • No more eyre dependency: Simpler error handling with Options

Migration guide:

// 0.1.x
let config = Dir::config_home()?;
let desktop = Dir::desktop_dir()?;

// 0.2.x
let config = Dir::config_home().ok_or("Failed to get config dir")?;
let desktop = Dir::desktop().ok_or("Failed to get desktop dir")?;

// Or using if-let
if let Some(config) = Dir::config_home() {
    // use config
}

Dependencies

None! This crate only uses Rust's standard library.

License

Licensed under the MIT LICENSE

Contributing

Contributions are welcome! Please ensure:

  1. All platforms are tested
  2. XDG compliance is maintained
  3. Platform-specific fallbacks follow native conventions
  4. New methods include appropriate documentation

References