file_io/
path.rs

1use std::path::{Path, PathBuf};
2
3/// Retrieves the user's home directory from the `$HOME` environment variable.
4///
5/// # Returns
6///
7/// Path to the user's home directory.
8///
9/// # Panics
10///
11/// If the `$HOME` environment variable is not set.
12///
13/// # Example
14///
15/// ```
16/// use file_io::get_home;
17///
18/// let home: String = get_home();
19/// ```
20pub fn get_home() -> String {
21    std::env::var("HOME").expect("HOME environment variable is not set.")
22}
23
24/// Get the current working directory.
25///
26/// # Returns
27///
28/// Current working directory.
29///
30/// # Panics
31///
32/// If the current directory cannot be determined.
33///
34/// # Example
35///
36/// ```
37/// use file_io::get_cwd;
38/// use std::path::PathBuf;
39///
40/// let cwd: PathBuf = get_cwd();
41/// ```
42pub fn get_cwd() -> PathBuf {
43    std::env::current_dir().expect("Failed to get the current working directory.")
44}
45
46/// Get the last component of a path (file or folder name).
47///
48/// # Arguments
49///
50/// * `path` - Path (can be a `&str`, `String`, `Path`, or `PathBuf`).
51///
52/// # Returns
53///
54/// The last component of the path.
55///
56/// # Panics
57///
58/// If the last path component cannot be determined.
59///
60/// # Examples
61///
62/// ## File path
63///
64/// ```
65/// use file_io::get_last_path_component;
66///
67/// let name = get_last_path_component("/some/path/to/file.txt");
68/// assert_eq!(name, "file.txt");
69/// ```
70///
71/// ## Folder path
72///
73/// ```
74/// use file_io::get_last_path_component;
75///
76/// let name = get_last_path_component("some/path/to/folder");
77/// assert_eq!(name, "folder");
78/// ```
79pub fn get_last_path_component<P: AsRef<Path>>(path: P) -> String {
80    path.as_ref()
81        .components()
82        .next_back()
83        .map(|comp| comp.as_os_str().to_string_lossy().into_owned())
84        .unwrap()
85}
86
87/// Get the file name (including any extension).
88///
89/// # Arguments
90///
91/// * `path` - The path to the file (can be a `&str`, `String`, `Path`, or `PathBuf`).
92///
93/// # Returns
94///
95/// The file name (including any extension).
96///
97/// # Panics
98///
99/// If the file name cannot be determined.
100///
101/// # Example
102///
103/// ```
104/// use file_io::get_file_name;
105///
106/// let file_name = get_file_name("/some/path/to/file.txt");
107/// assert_eq!(file_name, "file.txt");
108/// ```
109pub fn get_file_name<P: AsRef<Path>>(path: P) -> String {
110    path.as_ref()
111        .file_name()
112        .and_then(|s| s.to_str())
113        .map(String::from)
114        .expect("Failed to get the file name.")
115}
116
117/// Get the file stem (i.e. file name without its extension).
118///
119/// # Arguments
120///
121/// * `path` - The path to the file (can be a `&str`, `String`, `Path`, or `PathBuf`).
122///
123/// # Returns
124///
125/// The file stem (i.e. the file name without its extension).
126///
127/// # Panics
128///
129/// If the file stem cannot be determined.
130///
131/// # Example
132///
133/// ```
134/// use file_io::get_file_stem;
135///
136/// let file_stem = get_file_stem("/some/path/to/file.txt");
137/// assert_eq!(file_stem, "file");
138/// ```
139pub fn get_file_stem<P: AsRef<Path>>(path: P) -> String {
140    path.as_ref()
141        .file_stem()
142        .and_then(|s| s.to_str())
143        .map(String::from)
144        .expect("Failed to get the file stem.")
145}
146
147/// Get the file extension.
148///
149/// # Arguments
150///     
151/// * `path` - The path to the file (can be a `&str`, `String`, `Path`, or `PathBuf`).
152///
153/// # Returns
154///
155/// The file extension. If the file has no extension, or if the extension cannot be determined, this
156/// function returns an empty string.
157///
158/// # Example
159///
160/// ```
161/// use file_io::get_file_extension;
162///
163/// let file_extension = get_file_extension("/some/path/to/file.txt");
164/// assert_eq!(file_extension, "txt");
165/// ```
166pub fn get_file_extension<P: AsRef<Path>>(path: P) -> String {
167    path.as_ref()
168        .extension()
169        .and_then(|s| s.to_str())
170        .map(String::from)
171        .unwrap_or(String::from(""))
172}
173
174/// Converts a path to a `PathBuf`.
175///
176/// # Arguments
177///
178/// * `path` - The path to convert (can be a `&str`, `String`, `Path`, or `PathBuf`).
179///
180/// # Returns
181///
182/// A `PathBuf` representation of the path.
183///
184/// # Examples
185///
186/// ## Using a string literal
187///
188/// ```
189/// use file_io::to_path_buf;
190/// use std::path::PathBuf;
191///
192/// let path: &str = "folder/subfolder_9/file.txt";
193/// let path_buf: PathBuf = to_path_buf(path);
194/// ```
195///
196/// ## Using a `Path` reference
197///
198/// ```
199/// use file_io::to_path_buf;
200/// use std::path::{Path, PathBuf};
201///
202/// let path: &Path = Path::new("folder/subfolder_10/file.txt");
203/// let path_buf: PathBuf = to_path_buf(path);
204/// ```
205pub fn to_path_buf<P: AsRef<Path>>(path: P) -> PathBuf {
206    path.as_ref().to_path_buf()
207}
208
209#[cfg(test)]
210mod tests {
211    use super::*;
212    use crate::get_cwd;
213    use serial_test::serial;
214    use temp_env::with_var;
215
216    #[test]
217    fn test_get_home() {
218        with_var("HOME", Some("/tmp/test_home"), || {
219            let home = get_home();
220            assert_eq!(home, "/tmp/test_home");
221        });
222    }
223
224    #[test]
225    #[serial]
226    fn test_get_cwd() {
227        assert_eq!(get_last_path_component(get_cwd()), "file_io");
228    }
229
230    #[test]
231    fn test_get_last_path_component_str() {
232        assert_eq!(
233            get_last_path_component("/some/path/to/file.txt"),
234            "file.txt"
235        );
236        assert_eq!(get_last_path_component("some/path/to/file.txt"), "file.txt");
237        assert_eq!(get_last_path_component("/some/path/to/folder/"), "folder");
238        assert_eq!(get_last_path_component("/some/path/to/folder"), "folder");
239        assert_eq!(get_last_path_component("some/path/to/folder/"), "folder");
240        assert_eq!(get_last_path_component("some/path/to/folder"), "folder");
241        assert_eq!(get_last_path_component("/file.txt"), "file.txt");
242        assert_eq!(get_last_path_component("file.txt"), "file.txt");
243        assert_eq!(get_last_path_component("/folder/"), "folder");
244        assert_eq!(get_last_path_component("/folder"), "folder");
245        assert_eq!(get_last_path_component("folder/"), "folder");
246        assert_eq!(get_last_path_component("folder"), "folder");
247    }
248
249    #[test]
250    fn test_get_last_path_component_other_type_spot_checks() {
251        // Spot check with `String`.
252        assert_eq!(
253            get_last_path_component(String::from("/some/path/to/file.txt")),
254            "file.txt"
255        );
256
257        // Spot check with `Path`.
258        assert_eq!(
259            get_last_path_component(Path::new("/some/path/to/file.txt")),
260            "file.txt"
261        );
262
263        // Spot check with `PathBuf`.
264        assert_eq!(
265            get_last_path_component(PathBuf::from("/some/path/to/file.txt")),
266            "file.txt"
267        );
268    }
269
270    #[test]
271    fn test_get_file_name_str() {
272        assert_eq!(get_file_name("/some/path/to/file.txt"), "file.txt");
273        assert_eq!(get_file_name("some/path/to/file.txt"), "file.txt");
274        assert_eq!(get_file_name("/file.txt"), "file.txt");
275        assert_eq!(get_file_name("file.txt"), "file.txt");
276        assert_eq!(get_file_name("/some/path/to/file"), "file");
277        assert_eq!(get_file_name("some/path/to/file"), "file");
278        assert_eq!(get_file_name("/file"), "file");
279        assert_eq!(get_file_name("file"), "file");
280    }
281
282    #[test]
283    fn test_get_file_name_other_type_spot_checks() {
284        // Spot check with `String`.
285        assert_eq!(
286            get_file_name(String::from("/some/path/to/file.txt")),
287            "file.txt"
288        );
289
290        // Spot check with `Path`.
291        assert_eq!(
292            get_file_name(Path::new("/some/path/to/file.txt")),
293            "file.txt"
294        );
295
296        // Spot check with `PathBuf`.
297        assert_eq!(
298            get_file_name(PathBuf::from("/some/path/to/file.txt")),
299            "file.txt"
300        );
301    }
302
303    #[test]
304    fn test_get_file_stem_str() {
305        assert_eq!(get_file_stem("/some/path/to/file.txt"), "file");
306        assert_eq!(get_file_stem("some/path/to/file.txt"), "file");
307        assert_eq!(get_file_stem("/file.txt"), "file");
308        assert_eq!(get_file_stem("file.txt"), "file");
309        assert_eq!(get_file_stem("/some/path/to/file"), "file");
310        assert_eq!(get_file_stem("some/path/to/file"), "file");
311        assert_eq!(get_file_stem("/file"), "file");
312        assert_eq!(get_file_stem("file"), "file");
313    }
314
315    #[test]
316    fn test_get_file_stem_other_type_spot_checks() {
317        // Spot check with `String`.
318        assert_eq!(
319            get_file_stem(String::from("/some/path/to/file.txt")),
320            "file"
321        );
322
323        // Spot check with `Path`.
324        assert_eq!(get_file_stem(Path::new("/some/path/to/file.txt")), "file");
325
326        // Spot check with `PathBuf`.
327        assert_eq!(
328            get_file_stem(PathBuf::from("/some/path/to/file.txt")),
329            "file"
330        );
331    }
332
333    #[test]
334    fn test_get_file_extension_str() {
335        assert_eq!(get_file_extension("/some/path/to/file.txt"), "txt");
336        assert_eq!(get_file_extension("some/path/to/file.txt"), "txt");
337        assert_eq!(get_file_extension("/file.txt"), "txt");
338        assert_eq!(get_file_extension("file.txt"), "txt");
339        assert_eq!(get_file_extension("/some/path/to/file"), "");
340        assert_eq!(get_file_extension("some/path/to/file"), "");
341        assert_eq!(get_file_extension("/file"), "");
342        assert_eq!(get_file_extension("file"), "");
343    }
344
345    #[test]
346    fn test_get_file_extension_other_type_spot_checks() {
347        // Spot check with `String`.
348        assert_eq!(
349            get_file_extension(String::from("/some/path/to/file.txt")),
350            "txt"
351        );
352
353        // Spot check with `Path`.
354        assert_eq!(
355            get_file_extension(Path::new("/some/path/to/file.txt")),
356            "txt"
357        );
358
359        // Spot check with `PathBuf`.
360        assert_eq!(
361            get_file_extension(PathBuf::from("/some/path/to/file.txt")),
362            "txt"
363        );
364    }
365
366    #[test]
367    fn test_to_path_buf() {
368        // Test with a `&str`.
369        let path_str: &str = "folder/subfolder/file.txt";
370        let path_buf: PathBuf = to_path_buf(path_str);
371        assert_eq!(path_buf.to_str().unwrap(), path_str);
372
373        // Test with a `String`.
374        let path_string: String = String::from("folder/subfolder/file.txt");
375        let path_buf: PathBuf = to_path_buf(path_string);
376        assert_eq!(path_buf.to_str().unwrap(), "folder/subfolder/file.txt");
377
378        // Test with a `Path`.
379        let path: &Path = Path::new("folder/subfolder/file.txt");
380        let path_buf: PathBuf = to_path_buf(path);
381        assert_eq!(path_buf.to_str().unwrap(), "folder/subfolder/file.txt");
382
383        // Test with a `PathBuf`.
384        let path_buf_input: PathBuf = PathBuf::from("folder/subfolder/file.txt");
385        let path_buf_output: PathBuf = to_path_buf(path_buf_input);
386        assert_eq!(
387            path_buf_output.to_str().unwrap(),
388            "folder/subfolder/file.txt"
389        );
390    }
391}