Create valid paths and hidden directories for your application on Windows, Linux, and macOS.
This zero-dependency Rust crate manages hidden config and state directories across Windows, Linux, and macOS, handling platform-specific hiding logic automatically. Like the Greek nymph who hid her son in vines, Areia keeps your data safe and unseen if needed.
I want to shout out dirs and directories, as they inspired this crate!
All major Operating Systems (Windows, Linux, macOS) are supported.
The crate is tested on Linux. It builds on Windows and macOS (on GitHub Actions) but I lack the capability to test them.
- Get paths to standard directories (e.g.
home,cache, etc.) - Create or unhide hidden paths (Unix only)
- Create or unhide hidden files / directories
- Create or unhide super hidden files / directories
- Zero Dependencies
- Auto-Creator and Auto-Deletor for nested directories
Areia uses my nomos project management system.
The roadmap for this project can be found in the nomos.md file.
All nomos files follow the syntax defined here.
The main reason for writing this, was as always, the zero external Dependencies goal. Along with that, I also really wanted to play around with supporting different operating system architectures again.
During designing and scoping the project, I also set my sights on implementing some FFI and creating my own trait for the first time.
[dependencies]
areia = { git = "https://github.com/xqhare/areia" }use areia::BaseDirs;
if let Ok(base_dirs) = BaseDirs::new() {
assert!(base_dirs.home_dir().is_dir());
assert!(base_dirs.cache_dir().is_dir());
assert!(base_dirs.config_dir().is_dir());
assert!(base_dirs.config_local_dir().is_dir());
assert!(base_dirs.data_dir().is_dir());
assert!(base_dirs.data_local_dir().is_dir());
if let Some(executable_dir) = base_dirs.executable_dir() {
assert!(executable_dir.is_dir());
}
assert!(base_dirs.preference_dir().is_dir());
if let Some(runtime_dir) = base_dirs.runtime_dir() {
assert!(runtime_dir.is_dir());
}
if let Some(state_dir) = base_dirs.state_dir() {
assert!(state_dir.is_dir());
}
}use areia::UserDirs;
if let Ok(user_dirs) = UserDirs::new() {
assert!(user_dirs.home_dir().is_dir());
if let Some(audio_dir) = user_dirs.audio_dir() {
assert!(audio_dir.is_dir());
}
if let Some(desktop_dir) = user_dirs.desktop_dir() {
assert!(desktop_dir.is_dir());
}
if let Some(document_dir) = user_dirs.document_dir() {
assert!(document_dir.is_dir());
}
if let Some(download_dir) = user_dirs.download_dir() {
assert!(download_dir.is_dir());
}
if let Some(font_dir) = user_dirs.font_dir() {
assert!(font_dir.is_dir());
}
if let Some(picture_dir) = user_dirs.picture_dir() {
assert!(picture_dir.is_dir());
}
if let Some(public_dir) = user_dirs.public_dir() {
assert!(public_dir.is_dir());
}
if let Some(template_dir) = user_dirs.template_dir() {
assert!(template_dir.is_dir());
}
if let Some(video_dir) = user_dirs.video_dir() {
assert!(video_dir.is_dir());
}
}Hidden
If the path doesn't exist:
use areia::Hidden;
use std::path::PathBuf;
let mut path = PathBuf::from("to_hide/some.file");
let hidden_path = path.hide();
if cfg!(target_os = "windows") {
assert!(hidden_path.is_err());
} else {
assert!(hidden_path.is_ok());
assert!(hidden_path.as_ref().unwrap().exists());
assert!(hidden_path.as_ref().unwrap().is_file());
assert!(hidden_path.as_ref().unwrap().is_hidden().unwrap());
let unhidden_path = hidden_path.as_ref().unwrap().clone().unhide();
assert!(unhidden_path.is_ok());
assert!(unhidden_path.as_ref().unwrap().exists() && !hidden_path.as_ref().unwrap().exists());
assert!(unhidden_path.as_ref().unwrap().is_file());
assert!(!unhidden_path.as_ref().unwrap().is_hidden().unwrap());
assert_eq!(unhidden_path.as_ref().unwrap(), &path);
// Cleanup created files
assert!(std::fs::remove_file(unhidden_path.as_ref().unwrap()).is_ok());
assert!(std::fs::remove_dir_all(unhidden_path.as_ref().unwrap().parent().unwrap()).is_ok());
}Or if the path already exists:
use areia::Hidden;
use std::path::PathBuf;
let mut path = PathBuf::from("real_dir/existing.file");
assert!(std::fs::create_dir_all(&path.parent().unwrap()).is_ok());
assert!(std::fs::File::create(&path).is_ok());
let mut hidden_path = path.hide().unwrap();
assert!(hidden_path.exists());
assert!(hidden_path.is_file());
assert!(hidden_path.is_hidden().unwrap());
let unhidden_path = hidden_path.unhide().unwrap();
assert!(unhidden_path.exists() && !hidden_path.exists());
assert!(unhidden_path.is_file());
assert!(!unhidden_path.is_hidden().unwrap());
assert_eq!(unhidden_path, path);
// cleanup created files
assert!(std::fs::remove_file(&unhidden_path).is_ok());
assert!(std::fs::remove_dir_all(&unhidden_path.parent().unwrap()).is_ok());Or if the path is inside a hidden system directory:
use areia::{BaseDirs, Hidden};
use std::path::PathBuf;
let base_dirs = BaseDirs::new().unwrap();
let cache_dir = base_dirs.cache_dir();
let mut path = cache_dir.join("hidden_dir/hidden.file");
let hidden_path = path.hide();
assert!(hidden_path.is_ok());
assert_eq!(hidden_path.as_ref().unwrap(), &path);
assert!(hidden_path.as_ref().unwrap().exists());
assert!(hidden_path.as_ref().unwrap().is_file());
assert!(hidden_path.as_ref().unwrap().is_hidden().unwrap());
// Can't unhide a file inside a hidden system directory
let unhidden_path = hidden_path.as_ref().unwrap().clone().unhide();
assert!(unhidden_path.is_err());
// Cleanup created files
assert!(std::fs::remove_file(hidden_path.as_ref().unwrap()).is_ok());
assert!(std::fs::remove_dir(hidden_path.as_ref().unwrap().parent().unwrap()).is_ok());This concept does not apply on Windows.
try_into_hidden_path
A convenience function provided by the Hidden trait.
It has the same behavior as hide but does not create any files or directories.
It creates a new path with the last component hidden and returns it.
if cfg!(not(target_os = "windows")) {
use areia::Hidden;
use std::path::PathBuf;
let mut path = PathBuf::from("non_existing/some.file");
let hidden_path = path.try_into_hidden_path();
assert!(hidden_path.is_ok());
assert_eq!(hidden_path.as_ref().unwrap(), &PathBuf::from("non_existing/.some.file"));
assert!(!hidden_path.as_ref().unwrap().exists());
assert!(hidden_path.as_ref().unwrap().is_hidden().unwrap());
let mut path2 = PathBuf::from("a_dir/");
let hidden_path2 = path2.try_into_hidden_path();
assert!(hidden_path2.is_ok());
assert_eq!(hidden_path2.as_ref().unwrap(), &PathBuf::from(".a_dir/"));
assert!(!hidden_path2.as_ref().unwrap().exists());
assert!(hidden_path2.as_ref().unwrap().is_hidden().unwrap());
}try_into_unhidden_path
A convenience function provided by the Hidden trait.
It has the same behavior as unhide but does not create any files or directories.
It creates a new path with the last component unhidden and returns it.
if cfg!(not(target_os = "windows")) {
use areia::Hidden;
use std::path::PathBuf;
let path = PathBuf::from("non_existing/.some.file");
let unhidden_path = path.try_into_unhidden_path();
assert!(unhidden_path.is_ok());
assert_eq!(unhidden_path.as_ref().unwrap(), &PathBuf::from("non_existing/some.file"));
assert!(!unhidden_path.as_ref().unwrap().exists());
assert!(!unhidden_path.as_ref().unwrap().is_hidden().unwrap());
let path2 = PathBuf::from(".a_dir/");
let unhidden_path2 = path2.try_into_unhidden_path();
assert!(unhidden_path2.is_ok());
assert_eq!(unhidden_path2.as_ref().unwrap(), &PathBuf::from("a_dir/"));
assert!(!unhidden_path2.as_ref().unwrap().exists());
assert!(!unhidden_path2.as_ref().unwrap().is_hidden().unwrap());
}Super Hidden
Super Hidden is supported on macOS and Windows - The concept doesn't apply on Linux.
See theSuperHiddendocumentation for more details.
If the path doesn't exist:
if cfg!(not(target_os = "linux")) {
use areia::SuperHidden;
use std::path::PathBuf;
let mut path = PathBuf::from("super_hide/some.file");
let super_hidden_path = path.super_hide();
assert!(super_hidden_path.is_ok());
assert!(super_hidden_path.as_ref().unwrap().exists());
assert!(super_hidden_path.as_ref().unwrap().is_file());
assert!(super_hidden_path.as_ref().unwrap().is_super_hidden().unwrap());
let unhidden_path = super_hidden_path.as_ref().unwrap().clone().super_unhide();
assert!(unhidden_path.is_ok());
assert!(unhidden_path.as_ref().unwrap().exists() && !super_hidden_path.as_ref().unwrap().exists());
assert!(unhidden_path.as_ref().unwrap().is_file());
assert!(!unhidden_path.as_ref().unwrap().is_super_hidden().unwrap());
assert_eq!(unhidden_path.as_ref().unwrap(), &path);
// Cleanup created files
assert!(std::fs::remove_file(unhidden_path.as_ref().unwrap()).is_ok());
assert!(std::fs::remove_dir_all(unhidden_path.as_ref().unwrap().parent().unwrap()).is_ok());
}Or if the path already exists:
if cfg!(not(target_os = "linux")) {
use areia::SuperHidden;
use std::path::PathBuf;
let mut path = PathBuf::from("any_dir/existing.file");
assert!(std::fs::create_dir_all(&path.parent().unwrap()).is_ok());
assert!(std::fs::File::create(&path).is_ok());
let mut super_hidden_path = path.super_hide().unwrap();
assert!(super_hidden_path.exists());
assert!(super_hidden_path.is_file());
assert!(super_hidden_path.is_super_hidden().unwrap());
let unhidden_path = super_hidden_path.super_unhide().unwrap();
assert!(unhidden_path.exists() && !super_hidden_path.exists());
assert!(unhidden_path.is_file());
assert!(!unhidden_path.is_super_hidden().unwrap());
assert_eq!(unhidden_path, path);
// cleanup created files
assert!(std::fs::remove_file(&unhidden_path).is_ok());
assert!(std::fs::remove_dir_all(&unhidden_path.parent().unwrap()).is_ok());
}Or if the path is inside a hidden system directory:
if cfg!(not(target_os = "linux")) {
use areia::{BaseDirs, SuperHidden};
use std::path::PathBuf;
let base_dirs = BaseDirs::new().unwrap();
let cache_dir = base_dirs.cache_dir();
let mut path = cache_dir.join("hidden_dir/hidden.file");
let super_hidden_path = path.super_hide();
assert!(super_hidden_path.is_ok());
assert_eq!(super_hidden_path.as_ref().unwrap(), &path);
assert!(super_hidden_path.as_ref().unwrap().exists());
assert!(super_hidden_path.as_ref().unwrap().is_file());
assert!(super_hidden_path.as_ref().unwrap().is_super_hidden().unwrap());
// Can't unhide a file inside a hidden system directory
let unhidden_path = super_hidden_path.as_ref().unwrap().clone().super_unhide();
assert!(unhidden_path.is_err());
// Cleanup created files
assert!(std::fs::remove_file(super_hidden_path.as_ref().unwrap()).is_ok());
assert!(std::fs::remove_dir(super_hidden_path.as_ref().unwrap().parent().unwrap()).is_ok());
}The functions auto_creator and auto_deleter are provided for convenience.
Especially the
auto_deletoris very powerful and must be used with care.
Please read the provided documentation directly on the function itself.
use areia::{auto_creator, auto_deletor};
use std::path::PathBuf;
let path = PathBuf::from("test_dir/test_file.txt");
assert!(auto_creator(&path).is_ok());
assert!(&path.exists());
assert!(auto_deletor(&path).is_ok());
assert!(!&path.exists());They accept anything that implements Into<PathBuf>:
use areia::{auto_creator, auto_deletor};
let path = "str_test_dir/test_file.txt";
assert!(auto_creator(path).is_ok());
assert!(std::path::Path::new(path).exists());
assert!(auto_deletor(path).is_ok());
assert!(!std::path::Path::new(path).exists());The tables below are taken from the directories crate. Click for the full license.
Copyright (c) 2018 directories-rs contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
| Function name | Value on Linux | Value on Windows | Value on macOS |
|---|---|---|---|
home_dir |
$HOME |
{FOLDERID_Profile} |
$HOME |
cache_dir |
$XDG_CACHE_HOME or $HOME/.cache |
{FOLDERID_LocalAppData} |
$HOME/Library/Caches |
config_dir |
$XDG_CONFIG_HOME or $HOME/.config |
{FOLDERID_RoamingAppData} |
$HOME/Library/Application Support |
config_local_dir |
$XDG_CONFIG_HOME or $HOME/.config |
{FOLDERID_LocalAppData} |
$HOME/Library/Application Support |
data_dir |
$XDG_DATA_HOME or $HOME/.local/share |
{FOLDERID_RoamingAppData} |
$HOME/Library/Application Support |
data_local_dir |
$XDG_DATA_HOME or $HOME/.local/share |
{FOLDERID_LocalAppData} |
$HOME/Library/Application Support |
executable_dir |
Some($XDG_BIN_HOME) or Some($HOME/.local/bin) |
None |
None |
preference_dir |
$XDG_CONFIG_HOME or $HOME/.config |
{FOLDERID_RoamingAppData} |
$HOME/Library/Preferences |
runtime_dir |
Some($XDG_RUNTIME_DIR) or None |
None |
None |
state_dir |
Some($XDG_STATE_HOME) or Some($HOME/.local/state) |
None |
None |
| Function name | Value on Linux | Value on Windows | Value on macOS |
|---|---|---|---|
home_dir |
$HOME |
{FOLDERID_Profile} |
$HOME |
audio_dir |
Some(XDG_MUSIC_DIR) or None |
Some({FOLDERID_Music}) |
Some($HOME/Music/) |
desktop_dir |
Some(XDG_DESKTOP_DIR) or None |
Some({FOLDERID_Desktop}) |
Some($HOME/Desktop/) |
document_dir |
Some(XDG_DOCUMENTS_DIR) or None |
Some({FOLDERID_Documents}) |
Some($HOME/Documents/) |
download_dir |
Some(XDG_DOWNLOAD_DIR) or None |
Some({FOLDERID_Downloads}) |
Some($HOME/Downloads/) |
font_dir |
Some($XDG_DATA_HOME/fonts/) or Some($HOME/.local/share/fonts/) |
None |
Some($HOME/Library/Fonts/) |
picture_dir |
Some(XDG_PICTURES_DIR) or None |
Some({FOLDERID_Pictures}) |
Some($HOME/Pictures/) |
public_dir |
Some(XDG_PUBLICSHARE_DIR) or None |
Some({FOLDERID_Public}) |
Some($HOME/Public/) |
template_dir |
Some(XDG_TEMPLATES_DIR) or None |
Some({FOLDERID_Templates}) |
None |
video_dir |
Some(XDG_VIDEOS_DIR) or None |
Some({FOLDERID_Videos}) |
Some($HOME/Movies/) |