blob: a9e11e37b26395dc15be5e327d2c04ae8c165053 [file]
use crate::path::{Path, PathBuf};
use crate::sys::fs::{ExtraHomeDirs, ExtraMediaDirs};
/// Common user directory paths used for user-specific application files.
///
/// It is not required that the user directories are accessible by the current
/// user, nor that there is a directory at that path. A robust application
/// should handle the case where user directories are incorrectly configured.
///
/// Even when configured correctly, multiple paths may point to the same location.
/// You should not assume that a file written relative to one directory will not
/// conflict with the same relative path in a different home directory.
///
/// # Platform-specific behavior
///
/// As the filesystem conventions for discovering directories varies between
/// operating systems, constructors for `HomeDirs` that use the host platform's
/// conventions are provided as extension traits under the `std::os` module.
#[unstable(feature = "fs_home_dirs", issue = "162082")]
#[derive(Debug, Clone)]
pub struct HomeDirs {
pub(crate) cache: Option<PathBuf>,
pub(crate) config: Option<PathBuf>,
pub(crate) data: Option<PathBuf>,
pub(crate) state: Option<PathBuf>,
#[cfg_attr(not(unix), expect(dead_code, reason = "no extra home dirs"))]
pub(crate) extra: ExtraHomeDirs,
}
/// Common user directory paths used for user-specific media files.
///
/// It is not required that the media directories are accessible by the current
/// user, nor that there is a directory at that path. A robust application
/// should handle the case where media directories are incorrectly configured.
///
/// Even when configured correctly, multiple paths may point to the same location.
/// You should not assume that a file written relative to one directory will not
/// conflict with the same relative path in a different media directory.
///
/// # Platform-specific behavior
///
/// As the filesystem conventions for discovering directories varies between
/// operating systems, constructors for `MediaDirs` that use the host platform's
/// conventions are provided as extension traits under the `std::os` module.
#[unstable(feature = "fs_media_dirs", issue = "162083")]
#[derive(Debug, Clone)]
pub struct MediaDirs {
pub(crate) desktop: Option<PathBuf>,
pub(crate) documents: Option<PathBuf>,
pub(crate) downloads: Option<PathBuf>,
pub(crate) music: Option<PathBuf>,
pub(crate) pictures: Option<PathBuf>,
pub(crate) videos: Option<PathBuf>,
#[cfg_attr(not(unix), expect(dead_code, reason = "no extra media dirs"))]
pub(crate) extra: ExtraMediaDirs,
}
// NB: HomeDirs and MediaDirs intentionally do not implement Default. Self::empty()
// is a logical default, but users may also intuit the default to use default
// platform conventions. Omitting Default pushes users to explicitly choose.
impl HomeDirs {
/// Create a known user directory set with no known directories.
///
/// This is useful with the builder `set_*` methods to create a `HomeDirs`
/// with exactly the directories you want, without any other defaults.
#[unstable(feature = "fs_home_dirs", issue = "162082")]
pub fn empty() -> Self {
Self { cache: None, config: None, data: None, state: None, extra: Default::default() }
}
/// A base directory relative to which user-specific non-essential cache
/// data files should be stored.
///
/// "Cache" files are temporary data that can be used to cache redundant
/// work of an application, but which can be discarded arbitrarily and
/// recreated as necessary. Files in this directory may potentially be
/// automatically purged any time they are not currently open, or they
/// may not, depending on system configuration. A robust application
/// should ensure that its caches do not grow without a reasonable bound.
///
/// This is the same directory for all applications. Applications should
/// use a subdirectory for application-specific cache files.
///
/// # Platform-specific behavior
///
/// When constructed using platform-specific conventions, the value is:
///
/// | OS | Path |
/// | -- | ---- |
/// | [XDG] (Linux) | `${XDG_CACHE_HOME:-$HOME/.cache}` |
/// | [Darwin] (macOS) | [`NSCachesDirectory`] (`$HOME/Library/Caches`) |
/// | [Windows] | [`{FOLDERID_LocalAppData}`] (`%LOCALAPPDATA%`) |
///
/// Other paths can be configured via [`set_cache_home`](Self::set_cache_home).
///
/// [XDG]: crate::os::unix::fs::HomeDirsExt
/// [Darwin]: crate::os::darwin::fs::HomeDirsExt
/// [Windows]: crate::os::windows::fs::HomeDirsExt
/// [`NSCachesDirectory`]: https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/cachesdirectory?language=objc
/// [`{FOLDERID_LocalAppData}`]: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid#folderid_localappdata
#[unstable(feature = "fs_home_dirs", issue = "162082")]
pub fn cache_home(&self) -> Option<&Path> {
self.cache.as_deref()
}
/// A base directory relative to which user-specific configuration files
/// should be stored.
///
/// "Config" files are configuration managed by the user, either by editing
/// the files directly or through a managing application. Configuration is
/// generally expected to be meaningful to the user and portable enough to
/// back up and synchronize across the same user's account on multiple
/// systems.
///
/// This is the same directory for all applications. Applications should
/// use a subdirectory for application-specific configuration files.
///
/// # Platform-specific behavior
///
/// When constructed using platform-specific conventions, the value is:
///
/// | OS | Path |
/// | -- | ---- |
/// | [XDG] (Linux) | `${XDG_CONFIG_HOME:-$HOME/.config}` |
/// | [Darwin] (macOS) | [`NSApplicationSupportDirectory`] (`$HOME/Library/Application Support`) |
/// | [Windows] | [`{FOLDERID_RoamingAppData}`] (`%APPDATA%`) |
///
/// Other paths can be configured via [`set_config_home`](Self::set_config_home).
///
/// [XDG]: crate::os::unix::fs::HomeDirsExt
/// [Darwin]: crate::os::darwin::fs::HomeDirsExt
/// [Windows]: crate::os::windows::fs::HomeDirsExt
/// [`NSApplicationSupportDirectory`]: https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/applicationsupportdirectory?language=objc
/// [`{FOLDERID_RoamingAppData}`]: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid#folderid_roamingappdata
#[unstable(feature = "fs_home_dirs", issue = "162082")]
pub fn config_home(&self) -> Option<&Path> {
self.config.as_deref()
}
/// A base directory relative to which user-specific data files should be
/// stored.
///
/// "Data" files are application-specific data that is meaningful to the
/// user in some way and does not implicitly rely on system configuration
/// or details of how the application is installed otherwise irrelevant to
/// the user. As such, data makes sense to back up and synchronize between
/// the same user's account on multiple systems. If a file is specific to
/// a single machine, it's probably [state](Self::state_home).
///
/// This is the same directory for all applications. Applications should
/// use a subdirectory for application-specific data files.
///
/// # Platform-specific behavior
///
/// When constructed using platform-specific conventions, the value is:
///
/// | OS | Path |
/// | -- | ---- |
/// | [XDG] (Linux) | `${XDG_DATA_HOME:-$HOME/.local/share}` |
/// | [Darwin] (macOS) | [`NSApplicationSupportDirectory`] (`$HOME/Library/Application Support`) |
/// | [Windows] | [`{FOLDERID_RoamingAppData}`] (`%APPDATA%`) |
///
/// Other paths can be configured via [`set_data_home`](Self::set_data_home).
///
/// [XDG]: crate::os::unix::fs::HomeDirsExt
/// [Darwin]: crate::os::darwin::fs::HomeDirsExt
/// [Windows]: crate::os::windows::fs::HomeDirsExt
/// [`NSApplicationSupportDirectory`]: https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/applicationsupportdirectory?language=objc
/// [`{FOLDERID_RoamingAppData}`]: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid#folderid_roamingappdata
#[unstable(feature = "fs_home_dirs", issue = "162082")]
pub fn data_home(&self) -> Option<&Path> {
self.data.as_deref()
}
/// A base directory relative to which user-specific state files should be
/// stored.
///
/// "State" files are data that should persist between application restarts,
/// but which is not important nor portable enough to the user to synchronize
/// between multiple systems like [data](Self::data_home) are. Common examples
/// include history (such as logs, recently used files, etc) and any current
/// state of the application that should be reused (such as view, layout, open
/// files, undo history, etc).
///
/// This is the same directory for all applications. Applications should
/// use a subdirectory for application-specific state files.
///
/// # Platform-specific behavior
///
/// When constructed using platform-specific conventions, the value is:
///
/// | OS | Path |
/// | -- | ---- |
/// | [XDG] (Linux) | `${XDG_STATE_HOME:-$HOME/.local/state}` |
/// | [Darwin] (macOS) | [`NSApplicationSupportDirectory`] (`$HOME/Library/Application Support`) |
/// | [Windows] | [`{FOLDERID_LocalAppData}`] (`%LOCALAPPDATA%`) |
///
/// Other paths can be configured via [`set_state_home`](Self::set_state_home).
///
/// [XDG]: crate::os::unix::fs::HomeDirsExt
/// [Darwin]: crate::os::darwin::fs::HomeDirsExt
/// [Windows]: crate::os::windows::fs::HomeDirsExt
/// [`NSApplicationSupportDirectory`]: https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/applicationsupportdirectory?language=objc
/// [`{FOLDERID_LocalAppData}`]: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid#folderid_localappdata
#[unstable(feature = "fs_home_dirs", issue = "162082")]
pub fn state_home(&self) -> Option<&Path> {
self.state.as_deref()
}
}
impl MediaDirs {
/// Create a known user directory set with no known directories.
///
/// This is useful with the builder `set_*` methods to create a `MediaDirs`
/// with exactly the directories you want, without any other defaults.
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn empty() -> Self {
Self {
desktop: None,
documents: None,
downloads: None,
music: None,
pictures: None,
videos: None,
extra: Default::default(),
}
}
/// The OS-recognized user "Desktop" directory, often the `Desktop`
/// folder in the user's home directory.
///
/// As a media directory, this should typically be used as a default path
/// for file selection dialogs, not for automatically accessed file paths.
///
/// # Platform-specific behavior
///
/// When constructed using platform-specific conventions, the value is:
///
/// | OS | Path |
/// | -- | ---- |
/// | [XDG] (Linux) | `xdg-user-dir DESKTOP` (`$HOME/Desktop`) |
/// | [Darwin] (macOS) | [`NSDesktopDirectory`] (`$HOME/Desktop`) |
/// | [Windows] | [`{FOLDERID_Desktop}`] (`%USERPROFILE%\Desktop`) |
///
/// Other paths can be configured via [`set_desktop`](Self::set_desktop).
///
/// [XDG]: crate::os::unix::fs::MediaDirsExt
/// [Darwin]: crate::os::darwin::fs::MediaDirsExt
/// [Windows]: crate::os::windows::fs::MediaDirsExt
/// [`NSDesktopDirectory`]: https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/desktopdirectory?language=objc
/// [`{FOLDERID_Desktop}`]: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid#folderid_desktop
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn desktop(&self) -> Option<&Path> {
self.desktop.as_deref()
}
/// The OS-recognized user "Documents" directory, often the `Documents`
/// folder in the user's home directory.
///
/// As a media directory, this should typically be used as a default path
/// for file selection dialogs, not for automatically accessed file paths.
///
/// # Platform-specific behavior
///
/// When constructed using platform-specific conventions, the value is:
///
/// | OS | Path |
/// | -- | ---- |
/// | [XDG] (Linux) | `xdg-user-dir DOCUMENTS` (`$HOME/Documents`) |
/// | [Darwin] (macOS) | [`NSDocumentDirectory`] (`$HOME/Documents`) |
/// | [Windows] | [`{FOLDERID_Documents}`] (`%USERPROFILE%\Documents`) |
///
/// Other paths can be configured via [`set_documents`](Self::set_documents).
///
/// [XDG]: crate::os::unix::fs::MediaDirsExt
/// [Darwin]: crate::os::darwin::fs::MediaDirsExt
/// [Windows]: crate::os::windows::fs::MediaDirsExt
/// [`NSDocumentDirectory`]: https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/documentdirectory?language=objc
/// [`{FOLDERID_Documents}`]: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid#folderid_documents
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn documents(&self) -> Option<&Path> {
self.documents.as_deref()
}
/// The OS-recognized user "Downloads" directory, often the `Downloads`
/// folder in the user's home directory.
///
/// As a media directory, this should typically be used as a default path
/// for file selection dialogs, not for automatically accessed file paths.
///
/// # Platform-specific behavior
///
/// When constructed using platform-specific conventions, the value is:
///
/// | OS | Path |
/// | -- | ---- |
/// | [XDG] (Linux) | `xdg-user-dir DOWNLOAD` (`$HOME/Downloads`) |
/// | [Darwin] (macOS) | [`NSDownloadsDirectory`] (`$HOME/Downloads`) |
/// | [Windows] | [`{FOLDERID_Downloads}`] (`%USERPROFILE%\Downloads`) |
///
/// Other paths can be configured via [`set_downloads`](Self::set_downloads).
///
/// [XDG]: crate::os::unix::fs::MediaDirsExt
/// [Darwin]: crate::os::darwin::fs::MediaDirsExt
/// [Windows]: crate::os::windows::fs::MediaDirsExt
/// [`NSDownloadsDirectory`]: https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/downloadsdirectory?language=objc
/// [`{FOLDERID_Downloads}`]: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid#folderid_downloads
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn downloads(&self) -> Option<&Path> {
self.downloads.as_deref()
}
/// The OS-recognized user "Music" directory, often the `Music`
/// folder in the user's home directory.
///
/// As a media directory, this should typically be used as a default path
/// for file selection dialogs, not for automatically accessed file paths.
///
/// # Platform-specific behavior
///
/// When constructed using platform-specific conventions, the value is:
///
/// | OS | Path |
/// | -- | ---- |
/// | [XDG] (Linux) | `xdg-user-dir MUSIC` (`$HOME/Music`) |
/// | [Darwin] (macOS) | [`NSMusicDirectory`] (`$HOME/Music`) |
/// | [Windows] | [`{FOLDERID_Music}`] (`%USERPROFILE%\Music`) |
///
/// Other paths can be configured via [`set_music`](Self::set_music).
///
/// [XDG]: crate::os::unix::fs::MediaDirsExt
/// [Darwin]: crate::os::darwin::fs::MediaDirsExt
/// [Windows]: crate::os::windows::fs::MediaDirsExt
/// [`NSMusicDirectory`]: https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/musicdirectory?language=objc
/// [`{FOLDERID_Music}`]: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid#folderid_music
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn music(&self) -> Option<&Path> {
self.music.as_deref()
}
/// The OS-recognized user "Pictures" directory, often the `Pictures`
/// folder in the user's home directory.
///
/// As a media directory, this should typically be used as a default path
/// for file selection dialogs, not for automatically accessed file paths.
///
/// # Platform-specific behavior
///
/// When constructed using platform-specific conventions, the value is:
///
/// | OS | Path |
/// | -- | ---- |
/// | [XDG] (Linux) | `xdg-user-dir PICTURES` (`$HOME/Pictures`) |
/// | [Darwin] (macOS) | [`NSPicturesDirectory`] (`$HOME/Pictures`) |
/// | [Windows] | [`{FOLDERID_Pictures}`] (`%USERPROFILE%\Pictures`) |
///
/// Other paths can be configured via [`set_pictures`](Self::set_pictures).
///
/// [XDG]: crate::os::unix::fs::MediaDirsExt
/// [Darwin]: crate::os::darwin::fs::MediaDirsExt
/// [Windows]: crate::os::windows::fs::MediaDirsExt
/// [`NSPicturesDirectory`]: https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/picturesdirectory?language=objc
/// [`{FOLDERID_Pictures}`]: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid#folderid_pictures
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn pictures(&self) -> Option<&Path> {
self.pictures.as_deref()
}
/// The OS-recognized user "Videos" directory, often the `Videos`
/// folder in the user's home directory.
///
/// As a media directory, this should typically be used as a default path
/// for file selection dialogs, not for automatically accessed file paths.
///
/// # Platform-specific behavior
///
/// When constructed using platform-specific conventions, the value is:
///
/// | OS | Path |
/// | -- | ---- |
/// | [XDG] (Linux) | `xdg-user-dir VIDEOS` (`$HOME/Videos`) |
/// | [Darwin] (macOS) | [`NSMoviesDirectory`] (`$HOME/Movies`) |
/// | [Windows] | [`{FOLDERID_Videos}`] (`%USERPROFILE%\Videos`) |
///
/// Other paths can be configured via [`set_videos`](Self::set_videos).
///
/// [XDG]: crate::os::unix::fs::MediaDirsExt
/// [Darwin]: crate::os::darwin::fs::MediaDirsExt
/// [Windows]: crate::os::windows::fs::MediaDirsExt
/// [`NSMoviesDirectory`]: https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/moviesdirectory?language=objc
/// [`{FOLDERID_Videos}`]: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid#folderid_videos
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn videos(&self) -> Option<&Path> {
self.videos.as_deref()
}
}
impl HomeDirs {
/// Set the path for [Self::cache_home].
///
/// # Panics
///
/// Panics if the provided path is not absolute.
#[unstable(feature = "fs_home_dirs", issue = "162082")]
pub fn set_cache_home(&mut self, path: PathBuf) -> &mut Self {
assert!(path.is_absolute(), "cache home directory path must be absolute");
self.cache = Some(path);
self
}
/// Set the path for [Self::config_home].
///
/// # Panics
///
/// Panics if the provided path is not absolute.
#[unstable(feature = "fs_home_dirs", issue = "162082")]
pub fn set_config_home(&mut self, path: PathBuf) -> &mut Self {
assert!(path.is_absolute(), "config home directory path must be absolute");
self.config = Some(path);
self
}
/// Set the path for [Self::data_home].
///
/// # Panics
///
/// Panics if the provided path is not absolute.
#[unstable(feature = "fs_home_dirs", issue = "162082")]
pub fn set_data_home(&mut self, path: PathBuf) -> &mut Self {
assert!(path.is_absolute(), "data home directory path must be absolute");
self.data = Some(path);
self
}
/// Set the path for [Self::state_home].
///
/// # Panics
///
/// Panics if the provided path is not absolute.
#[unstable(feature = "fs_home_dirs", issue = "162082")]
pub fn set_state_home(&mut self, path: PathBuf) -> &mut Self {
assert!(path.is_absolute(), "state home directory path must be absolute");
self.state = Some(path);
self
}
}
impl MediaDirs {
/// Set the path for [Self::desktop].
///
/// # Panics
///
/// Panics if the provided path is not absolute.
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn set_desktop(&mut self, path: PathBuf) -> &mut Self {
assert!(path.is_absolute(), "desktop directory path must be absolute");
self.desktop = Some(path);
self
}
/// Set the path for [Self::documents].
///
/// # Panics
///
/// Panics if the provided path is not absolute.
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn set_documents(&mut self, path: PathBuf) -> &mut Self {
assert!(path.is_absolute(), "documents directory path must be absolute");
self.documents = Some(path);
self
}
/// Set the path for [Self::downloads].
///
/// # Panics
///
/// Panics if the provided path is not absolute.
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn set_downloads(&mut self, path: PathBuf) -> &mut Self {
assert!(path.is_absolute(), "downloads directory path must be absolute");
self.downloads = Some(path);
self
}
/// Set the path for [Self::music].
///
/// # Panics
///
/// Panics if the provided path is not absolute.
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn set_music(&mut self, path: PathBuf) -> &mut Self {
assert!(path.is_absolute(), "music directory path must be absolute");
self.music = Some(path);
self
}
/// Set the path for [Self::pictures].
///
/// # Panics
///
/// Panics if the provided path is not absolute.
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn set_pictures(&mut self, path: PathBuf) -> &mut Self {
assert!(path.is_absolute(), "pictures directory path must be absolute");
self.pictures = Some(path);
self
}
/// Set the path for [Self::videos].
///
/// # Panics
///
/// Panics if the provided path is not absolute.
#[unstable(feature = "fs_media_dirs", issue = "162083")]
pub fn set_videos(&mut self, path: PathBuf) -> &mut Self {
assert!(path.is_absolute(), "videos directory path must be absolute");
self.videos = Some(path);
self
}
}