sysdirs/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2//! # sysdirs
3//!
4//! A low-level library with a minimal API that provides platform-specific, user-accessible
5//! locations for finding and storing configuration, cache and other data on Linux,
6//! Windows (≥ Vista), macOS, **iOS, Android, and WASM**.
7//!
8//! The library provides the location of these directories by leveraging the mechanisms defined by:
9//!
10//! * the [XDG base directory](https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html)
11//!   and the [XDG user directory](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/) specifications on Linux
12//! * the [Known Folder](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776911(v=vs.85).aspx) system on Windows
13//! * the [Standard Directories](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW6) on macOS and iOS
14//! * the app sandbox directories on Android (requires initialization)
15//!
16//! ## Usage
17//!
18//! ```rust
19//! use sysdirs;
20//!
21//! sysdirs::home_dir();
22//! // Lin: Some(/home/alice)
23//! // Win: Some(C:\Users\Alice)
24//! // Mac: Some(/Users/Alice)
25//! // iOS: Some(/var/mobile/Containers/Data/Application/<UUID>)
26//! // Android: Some(/data/data/com.example.app/files) [after init]
27//!
28//! sysdirs::cache_dir();
29//! // Lin: Some(/home/alice/.cache)
30//! // Win: Some(C:\Users\Alice\AppData\Local)
31//! // Mac: Some(/Users/Alice/Library/Caches)
32//! // iOS: Some(<sandbox>/Library/Caches)
33//! // Android: Some(<filesDir>/cache)
34//! ```
35//!
36//! ## Android Setup
37//!
38//! There are two ways to use sysdirs on Android:
39//!
40//! ### Option 1: Pure Rust Android apps (android-activity/ndk-glue)
41//!
42//! Enable the `android-auto` feature and paths are detected automatically:
43//!
44//! ```toml
45//! [dependencies]
46//! sysdirs = { version = "0.1", features = ["android-auto"] }
47//! ```
48//!
49//! ### Option 2: Kotlin/Java apps embedding Rust
50//!
51//! Call `init_android()` once at startup from your JNI layer:
52//!
53//! ```rust,ignore
54//! // Called from Kotlin/Java via JNI at app startup
55//! sysdirs::init_android("/data/data/com.example.app/files");
56//! ```
57//!
58//! The path should be obtained from `Context.getFilesDir()` in Kotlin/Java.
59//!
60//! ## Platform Support
61//!
62//! | Function | Linux | macOS | Windows | iOS | Android | WASM |
63//! |----------|-------|-------|---------|-----|---------|------|
64//! | `home_dir` | ✓ | ✓ | ✓ | ✓ | ✓* | ✗ |
65//! | `cache_dir` | ✓ | ✓ | ✓ | ✓ | ✓* | ✗ |
66//! | `config_dir` | ✓ | ✓ | ✓ | ✓ | ✓* | ✗ |
67//! | `config_local_dir` | ✓ | ✓ | ✓ | ✓ | ✓* | ✗ |
68//! | `data_dir` | ✓ | ✓ | ✓ | ✓ | ✓* | ✗ |
69//! | `data_local_dir` | ✓ | ✓ | ✓ | ✓ | ✓* | ✗ |
70//! | `document_dir` | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ |
71//! | `download_dir` | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
72//! | `preference_dir` | ✓ | ✓ | ✓ | ✓ | ✓* | ✗ |
73//! | `audio_dir` | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
74//! | `desktop_dir` | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
75//! | `executable_dir` | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ |
76//! | `font_dir` | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ |
77//! | `picture_dir` | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
78//! | `public_dir` | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
79//! | `runtime_dir` | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ |
80//! | `state_dir` | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ |
81//! | `template_dir` | ✓ | ✗ | ✓ | ✗ | ✗ | ✗ |
82//! | `video_dir` | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
83//!
84//! \* Requires either the `android-auto` feature or [`init_android()`] to be called first
85
86use std::io;
87use std::path::Path;
88use std::path::PathBuf;
89
90// =============================================================================
91// Path Extension Trait
92// =============================================================================
93
94/// Extension trait for `Option<PathBuf>` that adds chainable path operations.
95///
96/// This trait makes it easy to work with directory paths in a fluent style:
97///
98/// ```rust
99/// use sysdirs::PathExt;
100///
101/// // Chain joins and ensure the directory exists
102/// let app_cache = sysdirs::cache_dir()
103///     .join("my-app")
104///     .join("data")
105///     .ensure();
106/// ```
107pub trait PathExt {
108	/// Joins a path component to the contained path, if present.
109	///
110	/// This is chainable, allowing multiple joins in sequence.
111	///
112	/// # Example
113	///
114	/// ```rust
115	/// use sysdirs::PathExt;
116	///
117	/// let path = sysdirs::data_dir()
118	///     .join("my-app")
119	///     .join("cache");
120	/// // Linux: Some(/home/alice/.local/share/my-app/cache)
121	/// ```
122	fn join<P: AsRef<Path>>(self, path: P) -> Option<PathBuf>;
123
124	/// Ensures the directory exists, creating it if necessary.
125	///
126	/// Returns the path if successful, or an error if:
127	/// - The original `Option` was `None` (directory not available on this platform)
128	/// - Directory creation failed (permissions, disk full, etc.)
129	///
130	/// # Example
131	///
132	/// ```rust,ignore
133	/// use sysdirs::PathExt;
134	///
135	/// let app_data = sysdirs::data_dir()
136	///     .join("my-app")
137	///     .ensure()?;
138	/// // Directory now exists, ready to use
139	/// ```
140	fn ensure(self) -> io::Result<PathBuf>;
141}
142
143impl PathExt for Option<PathBuf> {
144	fn join<P: AsRef<Path>>(self, path: P) -> Option<PathBuf> {
145		self.map(|p| p.join(path))
146	}
147
148	fn ensure(self) -> io::Result<PathBuf> {
149		match self {
150			Some(path) => {
151				std::fs::create_dir_all(&path)?;
152				Ok(path)
153			}
154			None => Err(io::Error::new(
155				io::ErrorKind::NotFound,
156				"directory not available on this platform",
157			)),
158		}
159	}
160}
161
162// =============================================================================
163// Platform Modules
164// =============================================================================
165
166#[cfg(any(
167	target_os = "macos",
168	target_os = "ios",
169	target_os = "tvos",
170	target_os = "watchos",
171	target_os = "visionos"
172))]
173mod apple;
174#[cfg(any(
175	target_os = "macos",
176	target_os = "ios",
177	target_os = "tvos",
178	target_os = "watchos",
179	target_os = "visionos"
180))]
181use apple as platform;
182
183#[cfg(target_os = "linux")]
184mod linux;
185#[cfg(target_os = "linux")]
186use linux as platform;
187
188#[cfg(target_os = "windows")]
189mod windows;
190#[cfg(target_os = "windows")]
191use windows as platform;
192
193#[cfg(target_os = "android")]
194mod android;
195#[cfg(target_os = "android")]
196use android as platform;
197
198#[cfg(target_arch = "wasm32")]
199mod wasm;
200#[cfg(target_arch = "wasm32")]
201use wasm as platform;
202
203// Fallback for other platforms (FreeBSD, etc.)
204#[cfg(not(any(
205	target_os = "macos",
206	target_os = "ios",
207	target_os = "tvos",
208	target_os = "watchos",
209	target_os = "visionos",
210	target_os = "linux",
211	target_os = "windows",
212	target_os = "android",
213	target_arch = "wasm32"
214)))]
215mod unix;
216#[cfg(not(any(
217	target_os = "macos",
218	target_os = "ios",
219	target_os = "tvos",
220	target_os = "watchos",
221	target_os = "visionos",
222	target_os = "linux",
223	target_os = "windows",
224	target_os = "android",
225	target_arch = "wasm32"
226)))]
227use unix as platform;
228
229// =============================================================================
230// Apple Search Path Domain (Apple platforms only)
231// =============================================================================
232
233/// Search path domain for Apple platforms.
234///
235/// Controls which domain to search when looking up directories on macOS, iOS, etc.
236/// Defaults to `User`.
237///
238/// This is only available on Apple platforms.
239#[cfg(any(
240	target_os = "macos",
241	target_os = "ios",
242	target_os = "tvos",
243	target_os = "watchos",
244	target_os = "visionos"
245))]
246#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
247pub enum SearchPathDomain {
248	/// User's home directory (e.g., ~/Library/...)
249	#[default]
250	User,
251	/// Local machine (e.g., /Library/...)
252	Local,
253	/// Network locations (e.g., /Network/Library/...)
254	Network,
255	/// System (e.g., /System/Library/...)
256	System,
257}
258
259/// Set the search path domain for Apple directory lookups.
260///
261/// By default, sysdirs uses the `User` domain which returns paths like `~/Library/Caches`.
262/// System utilities or admin tools may want to use `Local` or `System` domains.
263///
264/// This function is only available on Apple platforms.
265///
266/// # Example
267///
268/// ```rust,ignore
269/// use sysdirs::{SearchPathDomain, set_domain, cache_dir};
270///
271/// // Default: user domain
272/// cache_dir(); // ~/Library/Caches
273///
274/// // Switch to local domain
275/// set_domain(SearchPathDomain::Local);
276/// cache_dir(); // /Library/Caches
277/// ```
278#[cfg(any(
279	target_os = "macos",
280	target_os = "ios",
281	target_os = "tvos",
282	target_os = "watchos",
283	target_os = "visionos"
284))]
285pub fn set_domain(domain: SearchPathDomain) {
286	platform::set_domain(domain);
287}
288
289// =============================================================================
290// Android Initialization
291// =============================================================================
292
293/// Initialize Android-specific paths.
294///
295/// Must be called once at app startup on Android before using any directory functions.
296/// The path should be obtained from `Context.getFilesDir()` in Kotlin/Java.
297///
298/// This function is only available on Android.
299///
300/// # Example
301///
302/// ```rust,ignore
303/// // Called from JNI at app startup
304/// sysdirs::init_android("/data/data/com.example.app/files");
305/// ```
306#[cfg(target_os = "android")]
307pub fn init_android(files_dir: &str) {
308	platform::init_android(files_dir);
309}
310
311/// Initialize Android-specific paths with separate directories.
312///
313/// Like [`init_android()`], but allows specifying both the files directory
314/// and the cache directory separately. Use this if your app needs the actual
315/// cache directory from `Context.getCacheDir()`.
316///
317/// This function is only available on Android.
318///
319/// # Example
320///
321/// ```rust,ignore
322/// sysdirs::init_android_with_cache(
323///     "/data/data/com.example.app/files",
324///     "/data/data/com.example.app/cache"
325/// );
326/// ```
327#[cfg(target_os = "android")]
328pub fn init_android_with_cache(files_dir: &str, cache_dir: &str) {
329	platform::init_android_with_cache(files_dir, cache_dir);
330}
331
332// =============================================================================
333// Base Directories
334// =============================================================================
335
336/// Returns the path to the user's home directory.
337///
338/// The returned value depends on the operating system and is either a `Some`, containing a value
339/// from the following table, or a `None`.
340///
341/// |Platform | Value                                    | Example                          |
342/// | ------- | ---------------------------------------- | -------------------------------- |
343/// | Linux   | `$HOME`                                  | /home/alice                      |
344/// | macOS   | `$HOME`                                  | /Users/Alice                     |
345/// | Windows | `{FOLDERID_Profile}`                     | C:\Users\Alice                   |
346/// | iOS     | sandbox container                        | /var/mobile/.../&lt;UUID&gt;    |
347/// | Android | files directory (after init)             | /data/data/com.example/files     |
348/// | WASM    | `None`                                   |                                  |
349pub fn home_dir() -> Option<PathBuf> {
350	platform::home_dir()
351}
352
353/// Returns the path to the user's cache directory.
354///
355/// The returned value depends on the operating system and is either a `Some`, containing a value
356/// from the following table, or a `None`.
357///
358/// |Platform | Value                               | Example                            |
359/// | ------- | ----------------------------------- | ---------------------------------- |
360/// | Linux   | `$XDG_CACHE_HOME` or `$HOME`/.cache | /home/alice/.cache                 |
361/// | macOS   | `$HOME`/Library/Caches              | /Users/Alice/Library/Caches        |
362/// | Windows | `{FOLDERID_LocalAppData}`           | C:\Users\Alice\AppData\Local       |
363/// | iOS     | sandbox/Library/Caches              | &lt;sandbox&gt;/Library/Caches     |
364/// | Android | files/cache (after init)            | /data/data/com.example/files/cache |
365/// | WASM    | `None`                              |                                    |
366pub fn cache_dir() -> Option<PathBuf> {
367	platform::cache_dir()
368}
369
370/// Returns the path to the user's config directory.
371///
372/// The returned value depends on the operating system and is either a `Some`, containing a value
373/// from the following table, or a `None`.
374///
375/// |Platform | Value                                 | Example                                    |
376/// | ------- | ------------------------------------- | ------------------------------------------ |
377/// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config                        |
378/// | macOS   | `$HOME`/Library/Application Support   | /Users/Alice/Library/Application Support   |
379/// | Windows | `{FOLDERID_RoamingAppData}`           | C:\Users\Alice\AppData\Roaming             |
380/// | iOS     | sandbox/Library/Application Support   | &lt;sandbox&gt;/Library/Application Support |
381/// | Android | files directory (after init)          | /data/data/com.example/files               |
382/// | WASM    | `None`                                |                                            |
383pub fn config_dir() -> Option<PathBuf> {
384	platform::config_dir()
385}
386
387/// Returns the path to the user's local config directory.
388///
389/// The returned value depends on the operating system and is either a `Some`, containing a value
390/// from the following table, or a `None`.
391///
392/// |Platform | Value                                 | Example                                    |
393/// | ------- | ------------------------------------- | ------------------------------------------ |
394/// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config                        |
395/// | macOS   | `$HOME`/Library/Application Support   | /Users/Alice/Library/Application Support   |
396/// | Windows | `{FOLDERID_LocalAppData}`             | C:\Users\Alice\AppData\Local               |
397/// | iOS     | sandbox/Library/Application Support   | &lt;sandbox&gt;/Library/Application Support |
398/// | Android | files directory (after init)          | /data/data/com.example/files               |
399/// | WASM    | `None`                                |                                            |
400pub fn config_local_dir() -> Option<PathBuf> {
401	platform::config_local_dir()
402}
403
404/// Returns the path to the user's data directory.
405///
406/// The returned value depends on the operating system and is either a `Some`, containing a value
407/// from the following table, or a `None`.
408///
409/// |Platform | Value                                       | Example                                    |
410/// | ------- | ------------------------------------------- | ------------------------------------------ |
411/// | Linux   | `$XDG_DATA_HOME` or `$HOME`/.local/share    | /home/alice/.local/share                   |
412/// | macOS   | `$HOME`/Library/Application Support         | /Users/Alice/Library/Application Support   |
413/// | Windows | `{FOLDERID_RoamingAppData}`                 | C:\Users\Alice\AppData\Roaming             |
414/// | iOS     | sandbox/Library/Application Support         | &lt;sandbox&gt;/Library/Application Support |
415/// | Android | files directory (after init)                | /data/data/com.example/files               |
416/// | WASM    | `None`                                      |                                            |
417pub fn data_dir() -> Option<PathBuf> {
418	platform::data_dir()
419}
420
421/// Returns the path to the user's local data directory.
422///
423/// The returned value depends on the operating system and is either a `Some`, containing a value
424/// from the following table, or a `None`.
425///
426/// |Platform | Value                                       | Example                                    |
427/// | ------- | ------------------------------------------- | ------------------------------------------ |
428/// | Linux   | `$XDG_DATA_HOME` or `$HOME`/.local/share    | /home/alice/.local/share                   |
429/// | macOS   | `$HOME`/Library/Application Support         | /Users/Alice/Library/Application Support   |
430/// | Windows | `{FOLDERID_LocalAppData}`                   | C:\Users\Alice\AppData\Local               |
431/// | iOS     | sandbox/Library/Application Support         | &lt;sandbox&gt;/Library/Application Support |
432/// | Android | files directory (after init)                | /data/data/com.example/files               |
433/// | WASM    | `None`                                      |                                            |
434pub fn data_local_dir() -> Option<PathBuf> {
435	platform::data_local_dir()
436}
437
438/// Returns the path to the user's executable directory.
439///
440/// The returned value depends on the operating system and is either a `Some`, containing a value
441/// from the following table, or a `None`.
442///
443/// |Platform | Value                                    | Example                    |
444/// | ------- | ---------------------------------------- | -------------------------- |
445/// | Linux   | `$XDG_BIN_HOME` or `$HOME`/.local/bin    | /home/alice/.local/bin     |
446/// | macOS   | `None`                                   |                            |
447/// | Windows | `None`                                   |                            |
448/// | iOS     | `None`                                   |                            |
449/// | Android | `None`                                   |                            |
450/// | WASM    | `None`                                   |                            |
451pub fn executable_dir() -> Option<PathBuf> {
452	platform::executable_dir()
453}
454
455/// Returns the path to the user's preference directory.
456///
457/// The returned value depends on the operating system and is either a `Some`, containing a value
458/// from the following table, or a `None`.
459///
460/// |Platform | Value                                 | Example                                  |
461/// | ------- | ------------------------------------- | ---------------------------------------- |
462/// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config                      |
463/// | macOS   | `$HOME`/Library/Preferences           | /Users/Alice/Library/Preferences         |
464/// | Windows | `{FOLDERID_RoamingAppData}`           | C:\Users\Alice\AppData\Roaming           |
465/// | iOS     | sandbox/Library/Preferences           | &lt;sandbox&gt;/Library/Preferences      |
466/// | Android | files directory (after init)          | /data/data/com.example/files             |
467/// | WASM    | `None`                                |                                          |
468pub fn preference_dir() -> Option<PathBuf> {
469	platform::preference_dir()
470}
471
472/// Returns the path to the user's runtime directory.
473///
474/// The returned value depends on the operating system and is either a `Some`, containing a value
475/// from the following table, or a `None`.
476///
477/// |Platform | Value              | Example         |
478/// | ------- | ------------------ | --------------- |
479/// | Linux   | `$XDG_RUNTIME_DIR` | /run/user/1000  |
480/// | macOS   | `None`             |                 |
481/// | Windows | `None`             |                 |
482/// | iOS     | `None`             |                 |
483/// | Android | `None`             |                 |
484/// | WASM    | `None`             |                 |
485pub fn runtime_dir() -> Option<PathBuf> {
486	platform::runtime_dir()
487}
488
489/// Returns the path to the user's state directory.
490///
491/// The returned value depends on the operating system and is either a `Some`, containing a value
492/// from the following table, or a `None`.
493///
494/// |Platform | Value                                       | Example                    |
495/// | ------- | ------------------------------------------- | -------------------------- |
496/// | Linux   | `$XDG_STATE_HOME` or `$HOME`/.local/state   | /home/alice/.local/state   |
497/// | macOS   | `None`                                      |                            |
498/// | Windows | `None`                                      |                            |
499/// | iOS     | `None`                                      |                            |
500/// | Android | `None`                                      |                            |
501/// | WASM    | `None`                                      |                            |
502pub fn state_dir() -> Option<PathBuf> {
503	platform::state_dir()
504}
505
506// =============================================================================
507// User Directories
508// =============================================================================
509
510/// Returns the path to the user's audio directory.
511///
512/// The returned value depends on the operating system and is either a `Some`, containing a value
513/// from the following table, or a `None`.
514///
515/// |Platform | Value                 | Example                  |
516/// | ------- | --------------------- | ------------------------ |
517/// | Linux   | `XDG_MUSIC_DIR`       | /home/alice/Music        |
518/// | macOS   | `$HOME`/Music         | /Users/Alice/Music       |
519/// | Windows | `{FOLDERID_Music}`    | C:\Users\Alice\Music     |
520/// | iOS     | `None`                |                          |
521/// | Android | `None`                |                          |
522/// | WASM    | `None`                |                          |
523pub fn audio_dir() -> Option<PathBuf> {
524	platform::audio_dir()
525}
526
527/// Returns the path to the user's desktop directory.
528///
529/// The returned value depends on the operating system and is either a `Some`, containing a value
530/// from the following table, or a `None`.
531///
532/// |Platform | Value                 | Example                  |
533/// | ------- | --------------------- | ------------------------ |
534/// | Linux   | `XDG_DESKTOP_DIR`     | /home/alice/Desktop      |
535/// | macOS   | `$HOME`/Desktop       | /Users/Alice/Desktop     |
536/// | Windows | `{FOLDERID_Desktop}`  | C:\Users\Alice\Desktop   |
537/// | iOS     | `None`                |                          |
538/// | Android | `None`                |                          |
539/// | WASM    | `None`                |                          |
540pub fn desktop_dir() -> Option<PathBuf> {
541	platform::desktop_dir()
542}
543
544/// Returns the path to the user's document directory.
545///
546/// The returned value depends on the operating system and is either a `Some`, containing a value
547/// from the following table, or a `None`.
548///
549/// |Platform | Value                   | Example                    |
550/// | ------- | ----------------------- | -------------------------- |
551/// | Linux   | `XDG_DOCUMENTS_DIR`     | /home/alice/Documents      |
552/// | macOS   | `$HOME`/Documents       | /Users/Alice/Documents     |
553/// | Windows | `{FOLDERID_Documents}`  | C:\Users\Alice\Documents   |
554/// | iOS     | sandbox/Documents       | &lt;sandbox&gt;/Documents  |
555/// | Android | `None`                  |                            |
556/// | WASM    | `None`                  |                            |
557pub fn document_dir() -> Option<PathBuf> {
558	platform::document_dir()
559}
560
561/// Returns the path to the user's download directory.
562///
563/// The returned value depends on the operating system and is either a `Some`, containing a value
564/// from the following table, or a `None`.
565///
566/// |Platform | Value                   | Example                    |
567/// | ------- | ----------------------- | -------------------------- |
568/// | Linux   | `XDG_DOWNLOAD_DIR`      | /home/alice/Downloads      |
569/// | macOS   | `$HOME`/Downloads       | /Users/Alice/Downloads     |
570/// | Windows | `{FOLDERID_Downloads}`  | C:\Users\Alice\Downloads   |
571/// | iOS     | `None`                  |                            |
572/// | Android | `None`                  |                            |
573/// | WASM    | `None`                  |                            |
574pub fn download_dir() -> Option<PathBuf> {
575	platform::download_dir()
576}
577
578/// Returns the path to the user's font directory.
579///
580/// The returned value depends on the operating system and is either a `Some`, containing a value
581/// from the following table, or a `None`.
582///
583/// |Platform | Value                                              | Example                            |
584/// | ------- | -------------------------------------------------- | ---------------------------------- |
585/// | Linux   | `$XDG_DATA_HOME`/fonts or `$HOME`/.local/share/fonts | /home/alice/.local/share/fonts   |
586/// | macOS   | `$HOME`/Library/Fonts                              | /Users/Alice/Library/Fonts         |
587/// | Windows | `None`                                             |                                    |
588/// | iOS     | `None`                                             |                                    |
589/// | Android | `None`                                             |                                    |
590/// | WASM    | `None`                                             |                                    |
591pub fn font_dir() -> Option<PathBuf> {
592	platform::font_dir()
593}
594
595/// Returns the path to the user's picture directory.
596///
597/// The returned value depends on the operating system and is either a `Some`, containing a value
598/// from the following table, or a `None`.
599///
600/// |Platform | Value                   | Example                    |
601/// | ------- | ----------------------- | -------------------------- |
602/// | Linux   | `XDG_PICTURES_DIR`      | /home/alice/Pictures       |
603/// | macOS   | `$HOME`/Pictures        | /Users/Alice/Pictures      |
604/// | Windows | `{FOLDERID_Pictures}`   | C:\Users\Alice\Pictures    |
605/// | iOS     | `None`                  |                            |
606/// | Android | `None`                  |                            |
607/// | WASM    | `None`                  |                            |
608pub fn picture_dir() -> Option<PathBuf> {
609	platform::picture_dir()
610}
611
612/// Returns the path to the user's public directory.
613///
614/// The returned value depends on the operating system and is either a `Some`, containing a value
615/// from the following table, or a `None`.
616///
617/// |Platform | Value                   | Example                    |
618/// | ------- | ----------------------- | -------------------------- |
619/// | Linux   | `XDG_PUBLICSHARE_DIR`   | /home/alice/Public         |
620/// | macOS   | `$HOME`/Public          | /Users/Alice/Public        |
621/// | Windows | `{FOLDERID_Public}`     | C:\Users\Public            |
622/// | iOS     | `None`                  |                            |
623/// | Android | `None`                  |                            |
624/// | WASM    | `None`                  |                            |
625pub fn public_dir() -> Option<PathBuf> {
626	platform::public_dir()
627}
628
629/// Returns the path to the user's template directory.
630///
631/// The returned value depends on the operating system and is either a `Some`, containing a value
632/// from the following table, or a `None`.
633///
634/// |Platform | Value                   | Example                              |
635/// | ------- | ----------------------- | ------------------------------------ |
636/// | Linux   | `XDG_TEMPLATES_DIR`     | /home/alice/Templates                |
637/// | macOS   | `None`                  |                                      |
638/// | Windows | `{FOLDERID_Templates}`  | C:\Users\Alice\AppData\Roaming\Microsoft\Windows\Templates |
639/// | iOS     | `None`                  |                                      |
640/// | Android | `None`                  |                                      |
641/// | WASM    | `None`                  |                                      |
642pub fn template_dir() -> Option<PathBuf> {
643	platform::template_dir()
644}
645
646/// Returns the path to the user's video directory.
647///
648/// The returned value depends on the operating system and is either a `Some`, containing a value
649/// from the following table, or a `None`.
650///
651/// |Platform | Value                 | Example                  |
652/// | ------- | --------------------- | ------------------------ |
653/// | Linux   | `XDG_VIDEOS_DIR`      | /home/alice/Videos       |
654/// | macOS   | `$HOME`/Movies        | /Users/Alice/Movies      |
655/// | Windows | `{FOLDERID_Videos}`   | C:\Users\Alice\Videos    |
656/// | iOS     | `None`                |                          |
657/// | Android | `None`                |                          |
658/// | WASM    | `None`                |                          |
659pub fn video_dir() -> Option<PathBuf> {
660	platform::video_dir()
661}
662
663// =============================================================================
664// sysdirs Extensions
665// =============================================================================
666
667/// Returns the path to the app's temporary directory.
668///
669/// This is a sysdirs extension not present in the `dirs` crate.
670///
671/// The returned value depends on the operating system and is either a `Some`, containing a value
672/// from the following table, or a `None`.
673///
674/// |Platform | Value                        | Example                      |
675/// | ------- | ---------------------------- | ---------------------------- |
676/// | Linux   | `$TMPDIR` or /tmp            | /tmp                         |
677/// | macOS   | `$TMPDIR`                    | /var/folders/.../T/          |
678/// | Windows | `{FOLDERID_LocalAppData}`\Temp | C:\Users\Alice\AppData\Local\Temp |
679/// | iOS     | sandbox/tmp                  | &lt;sandbox&gt;/tmp          |
680/// | Android | files/tmp (after init)       | /data/data/com.example/files/tmp |
681/// | WASM    | `None`                       |                              |
682pub fn temp_dir() -> Option<PathBuf> {
683	platform::temp_dir()
684}
685
686/// Returns the path to the app's Library directory (Apple platforms only).
687///
688/// This is a sysdirs extension not present in the `dirs` crate.
689///
690/// The returned value depends on the operating system and is either a `Some`, containing a value
691/// from the following table, or a `None`.
692///
693/// |Platform | Value                        | Example                      |
694/// | ------- | ---------------------------- | ---------------------------- |
695/// | Linux   | `None`                       |                              |
696/// | macOS   | `$HOME`/Library              | /Users/Alice/Library         |
697/// | Windows | `None`                       |                              |
698/// | iOS     | sandbox/Library              | &lt;sandbox&gt;/Library      |
699/// | Android | `None`                       |                              |
700/// | WASM    | `None`                       |                              |
701pub fn library_dir() -> Option<PathBuf> {
702	platform::library_dir()
703}
704
705// =============================================================================
706// Tests
707// =============================================================================
708
709#[cfg(test)]
710mod tests {
711	use super::*;
712
713	#[test]
714	fn test_home_dir() {
715		// On most platforms we should get something
716		#[cfg(not(target_arch = "wasm32"))]
717		assert!(home_dir().is_some());
718	}
719
720	#[test]
721	fn test_cache_dir() {
722		#[cfg(not(any(target_arch = "wasm32", target_os = "android")))]
723		assert!(cache_dir().is_some());
724	}
725
726	#[test]
727	fn test_config_dir() {
728		#[cfg(not(any(target_arch = "wasm32", target_os = "android")))]
729		assert!(config_dir().is_some());
730	}
731
732	#[test]
733	fn test_data_dir() {
734		#[cfg(not(any(target_arch = "wasm32", target_os = "android")))]
735		assert!(data_dir().is_some());
736	}
737
738	#[test]
739	#[cfg(target_os = "android")]
740	fn test_android_init() {
741		init_android("/data/data/com.test/files");
742		assert_eq!(home_dir(), Some(PathBuf::from("/data/data/com.test/files")));
743		assert_eq!(
744			cache_dir(),
745			Some(PathBuf::from("/data/data/com.test/files/cache"))
746		);
747	}
748}