etcetera/app_strategy/windows.rs
1use crate::base_strategy::BaseStrategy;
2use crate::{HomeDirError, base_strategy};
3use std::path::{Path, PathBuf};
4
5/// This strategy follows Windows’ conventions. It seems that all Windows GUI apps, and some command-line ones follow this pattern. The specification is available [here](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid).
6///
7/// This initial example removes all the relevant environment variables to show the strategy’s use of the:
8/// - (on Windows) SHGetKnownFolderPath API.
9/// - (on non-Windows) Windows default directories.
10///
11/// ```
12/// use etcetera::app_strategy::AppStrategy;
13/// use etcetera::app_strategy::AppStrategyArgs;
14/// use etcetera::app_strategy::Windows;
15/// use std::path::Path;
16///
17/// // Remove the environment variables that the strategy reads from.
18/// unsafe {
19/// std::env::remove_var("USERPROFILE");
20/// std::env::remove_var("APPDATA");
21/// std::env::remove_var("LOCALAPPDATA");
22/// }
23///
24/// let app_strategy = Windows::new(AppStrategyArgs {
25/// top_level_domain: "org".to_string(),
26/// author: "Acme Corp".to_string(),
27/// app_name: "Frobnicator Plus".to_string(),
28/// }).unwrap();
29///
30/// let home_dir = etcetera::home_dir().unwrap();
31///
32/// assert_eq!(
33/// app_strategy.home_dir(),
34/// &home_dir
35/// );
36/// assert_eq!(
37/// app_strategy.config_dir().strip_prefix(&home_dir),
38/// Ok(Path::new("AppData/Roaming/Acme Corp/Frobnicator Plus/config"))
39/// );
40/// assert_eq!(
41/// app_strategy.data_dir().strip_prefix(&home_dir),
42/// Ok(Path::new("AppData/Roaming/Acme Corp/Frobnicator Plus/data"))
43/// );
44/// assert_eq!(
45/// app_strategy.cache_dir().strip_prefix(&home_dir),
46/// Ok(Path::new("AppData/Local/Acme Corp/Frobnicator Plus/cache"))
47/// );
48/// assert_eq!(
49/// app_strategy.state_dir(),
50/// None
51/// );
52/// assert_eq!(
53/// app_strategy.runtime_dir(),
54/// None
55/// );
56/// ```
57///
58/// This next example gives the environment variables values:
59///
60/// ```
61/// use etcetera::app_strategy::AppStrategy;
62/// use etcetera::app_strategy::AppStrategyArgs;
63/// use etcetera::app_strategy::Windows;
64/// use std::path::Path;
65///
66/// let home_path = if cfg!(windows) {
67/// "C:\\my_home_location\\".to_string()
68/// } else {
69/// etcetera::home_dir().unwrap().to_string_lossy().to_string()
70/// };
71/// let data_path = if cfg!(windows) {
72/// "C:\\my_data_location\\"
73/// } else {
74/// "/my_data_location/"
75/// };
76/// let cache_path = if cfg!(windows) {
77/// "C:\\my_cache_location\\"
78/// } else {
79/// "/my_cache_location/"
80/// };
81///
82/// unsafe {
83/// std::env::set_var("USERPROFILE", &home_path);
84/// std::env::set_var("APPDATA", data_path);
85/// std::env::set_var("LOCALAPPDATA", cache_path);
86/// }
87///
88/// let app_strategy = Windows::new(AppStrategyArgs {
89/// top_level_domain: "org".to_string(),
90/// author: "Acme Corp".to_string(),
91/// app_name: "Frobnicator Plus".to_string(),
92/// }).unwrap();
93///
94/// assert_eq!(
95/// app_strategy.home_dir(),
96/// Path::new(&home_path)
97/// );
98/// assert_eq!(
99/// app_strategy.config_dir(),
100/// Path::new(&format!("{}/Acme Corp/Frobnicator Plus/config", data_path))
101/// );
102/// assert_eq!(
103/// app_strategy.data_dir(),
104/// Path::new(&format!("{}/Acme Corp/Frobnicator Plus/data", data_path))
105/// );
106/// assert_eq!(
107/// app_strategy.cache_dir(),
108/// Path::new(&format!("{}/Acme Corp/Frobnicator Plus/cache", cache_path))
109/// );
110/// assert_eq!(
111/// app_strategy.state_dir(),
112/// None
113/// );
114/// assert_eq!(
115/// app_strategy.runtime_dir(),
116/// None
117/// );
118/// ```
119
120#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
121pub struct Windows {
122 base_strategy: base_strategy::Windows,
123 author_app_name_path: PathBuf,
124}
125
126macro_rules! dir_method {
127 ($self: ident, $base_strategy_method: ident, $subfolder_name: expr) => {{
128 let mut path = $self.base_strategy.$base_strategy_method();
129 path.push(&$self.author_app_name_path);
130 path.push($subfolder_name);
131
132 path
133 }};
134}
135
136impl Windows {
137 /// Create a new Windows AppStrategy
138 pub fn new(args: super::AppStrategyArgs) -> Result<Self, HomeDirError> {
139 Ok(Self {
140 base_strategy: base_strategy::Windows::new()?,
141 author_app_name_path: PathBuf::from(args.author).join(args.app_name),
142 })
143 }
144}
145
146impl super::AppStrategy for Windows {
147 fn home_dir(&self) -> &Path {
148 self.base_strategy.home_dir()
149 }
150
151 fn config_dir(&self) -> PathBuf {
152 dir_method!(self, config_dir, "config")
153 }
154
155 fn data_dir(&self) -> PathBuf {
156 dir_method!(self, data_dir, "data")
157 }
158
159 fn cache_dir(&self) -> PathBuf {
160 dir_method!(self, cache_dir, "cache")
161 }
162
163 fn state_dir(&self) -> Option<PathBuf> {
164 None
165 }
166
167 fn runtime_dir(&self) -> Option<PathBuf> {
168 None
169 }
170}