use app_path::AppPath;
use strict_path::PathBoundary;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== App-Path Integration Examples ===\n");
println!("Pattern: AppPath::with(\"subdir\") → PathBoundary::try_new_create() → portable operations\n");
println!("1. Basic Portable Application:");
basic_portable_app()?;
println!("\n2. Multi-Directory Portable App Structure:");
multi_dir_portable_app()?;
println!("\n3. Environment Variable Override (Testing/CI):");
env_override_pattern()?;
println!("\n4. Validating Untrusted CLI Input (Security Pattern):");
cli_input_validation()?;
println!("\nAll examples completed successfully!");
println!("\nPortable apps: config/data/cache travel with the executable");
println!(" Perfect for: USB drives, network shares, no-install deployment");
Ok(())
}
fn basic_portable_app() -> Result<(), Box<dyn std::error::Error>> {
let app_dir = AppPath::with("portable-demo");
println!(" Executable-relative path: {}", app_dir.display());
let app_data_dir: PathBoundary = PathBoundary::try_new_create(app_dir)?;
let config = app_data_dir.strict_join("config.ini")?;
config.write(b"[Settings]\nportable=true\nversion=1.0\n")?;
println!(" ✓ Created config.ini");
let data = app_data_dir.strict_join("userdata.txt")?;
data.write(b"User preferences saved locally")?;
println!(" ✓ Created userdata.txt");
println!(
" ✓ Config content:\n{}",
config
.read_to_string()?
.lines()
.map(|line| format!(" {line}"))
.collect::<Vec<_>>()
.join("\n")
);
app_data_dir.remove_dir_all().ok();
Ok(())
}
fn multi_dir_portable_app() -> Result<(), Box<dyn std::error::Error>> {
struct ConfigDir;
struct DataDir;
struct CacheDir;
struct AppPaths {
config: PathBoundary<ConfigDir>,
data: PathBoundary<DataDir>,
cache: PathBoundary<CacheDir>,
}
impl AppPaths {
fn new(app_name: &str) -> Result<Self, Box<dyn std::error::Error>> {
let base_dir = AppPath::with(app_name);
Ok(Self {
config: PathBoundary::try_new_create(base_dir.join("config"))?,
data: PathBoundary::try_new_create(base_dir.join("data"))?,
cache: PathBoundary::try_new_create(base_dir.join("cache"))?,
})
}
}
let paths = AppPaths::new("portable-demo")?;
let settings = paths.config.strict_join("settings.toml")?;
settings.write(b"[app]\ntheme = 'dark'\nlanguage = 'en'\n")?;
println!(" ✓ Config: {}", settings.strictpath_display());
let user_db = paths.data.strict_join("users/alice.json")?;
user_db.create_parent_dir_all()?;
user_db.write(br#"{"name": "Alice", "role": "admin"}"#)?;
println!(" ✓ Data: {}", user_db.strictpath_display());
let cache_file = paths.cache.strict_join("thumbnails/img1.cache")?;
cache_file.create_parent_dir_all()?;
cache_file.write(b"cached thumbnail data")?;
println!(" ✓ Cache: {}", cache_file.strictpath_display());
println!("\n 📁 Portable app structure:");
println!(" executable.exe");
println!(" portable-demo/");
println!(" ├─ config/settings.toml");
println!(" ├─ data/users/alice.json");
println!(" └─ cache/thumbnails/img1.cache");
paths.config.remove_dir_all().ok();
paths.data.remove_dir_all().ok();
paths.cache.remove_dir_all().ok();
Ok(())
}
fn cli_input_validation() -> Result<(), Box<dyn std::error::Error>> {
let app_dir = AppPath::with("portable-demo-cli");
let app_data_dir: PathBoundary = PathBoundary::try_new_create(app_dir)?;
let cli_args: &[&str] = &[
"report.txt",
"../../etc/passwd", "../outside.txt", "data/summary.csv", ];
println!(" Validating filenames from external input (CLI args / HTTP request):");
for user_input in cli_args {
match app_data_dir.strict_join(user_input) {
Ok(safe_path) => {
safe_path.create_parent_dir_all()?;
safe_path.write(b"app content")?;
println!(
" OK '{user_input}' -> {}",
safe_path.strictpath_display()
);
}
Err(_) => {
println!(" BLOCKED '{user_input}' (path traversal / escape attempt)");
}
}
}
app_data_dir.remove_dir_all().ok();
Ok(())
}
fn env_override_pattern() -> Result<(), Box<dyn std::error::Error>> {
let env_var = "DEMO_APP_DATA_DIR";
let is_overridden = std::env::var(env_var).is_ok();
let app_path = AppPath::with_override("portable-demo", Some(env_var));
if is_overridden {
println!(" 🔧 Using override from ${env_var}");
println!(" Path: {}", app_path.display());
} else {
println!(" 📁 Using executable-relative (no override set)");
println!(" Path: {}", app_path.display());
println!(" Tip: Set {env_var} to override location");
}
let app_data_dir: PathBoundary = PathBoundary::try_new_create(app_path)?;
let log_file = app_data_dir.strict_join("app.log")?;
log_file.write(b"[INFO] Application started\n[INFO] Initialization complete\n")?;
println!(" ✓ Created app.log");
println!("\n 💡 Use cases:");
println!(" • Production: files next to executable");
println!(" • CI: ${env_var} = /tmp/ci-test");
println!(" • Development: override to project directory");
app_data_dir.remove_dir_all().ok();
Ok(())
}