file_io/
create.rs

1use std::path::Path;
2
3/// Creates a new folder at the specified path if it does not already exist.
4///
5/// # Arguments
6///
7/// * `path` - The path where the folder should be created (can be a `&str`, [`String`], [`Path`],
8///   or [`std::path::PathBuf`]).
9///
10/// # Panics
11///
12/// If some error is encountered while creating the folder at `path`.
13///
14/// # Examples
15///
16/// ## Using a string literal
17///
18/// ```
19/// use file_io::create_folder;
20///
21/// let path: &str = "folder/subfolder_1";
22/// create_folder(path);
23/// ```
24///
25/// ## Using a `Path` reference
26///
27/// ```
28/// use file_io::create_folder;
29/// use std::path::Path;
30///
31/// let path: &Path = Path::new("folder/subfolder_2");
32/// create_folder(path);
33/// ```
34pub fn create_folder<P: AsRef<Path>>(path: P) {
35    let path = path.as_ref();
36    if !path.exists() {
37        std::fs::create_dir_all(path)
38            .unwrap_or_else(|_| panic!("Failed to create folder at '{path:?}'."));
39    }
40}
41
42/// Creates the parent folder for a file at the specified path if it does not already exist.
43///
44/// # Arguments
45///
46/// * `path` - The path to the file for which the parent folder should be created (can be a `&str`,
47///   [`String`], [`Path`], or [`std::path::PathBuf`]).
48///
49/// # Panics
50///
51/// If some error is encountered while creating the parent folder.
52///
53/// # Examples
54///
55/// ## Using a string literal
56///
57/// ```
58/// use file_io::create_folder_for_file;
59///     
60/// let path: &str = "folder/subfolder_3/file_1.txt";
61///
62/// // This will create "folder/subfolder_3" if it does not exist.
63/// create_folder_for_file(path);
64/// ```
65///
66/// ## Using a `Path` reference
67///
68/// ```
69/// use file_io::create_folder_for_file;
70/// use std::path::Path;
71///
72/// let path: &Path = Path::new("folder/subfolder_4/file_2.txt");
73///
74/// // This will create "folder/subfolder_4" if it does not exist.
75/// create_folder_for_file(path);
76/// ```
77pub fn create_folder_for_file<P: AsRef<Path>>(path: P) {
78    let path = path.as_ref();
79    if let Some(parent) = path.parent() {
80        create_folder(parent);
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use crate::delete::delete_folder;
88    use crate::path::to_path_buf;
89    use crate::test_utils::{assert_folder_exists, get_temp_dir_path};
90    use tempfile::tempdir;
91
92    #[test]
93    fn test_create_delete_folder_basic() {
94        // Create a temporary directory to work in.
95        let temp_dir = tempdir().unwrap();
96
97        // Define the new folder path.
98        let new_folder_path = get_temp_dir_path(&temp_dir).join("new_folder");
99
100        // New folder path in different formats.
101        let new_folder_paths: Vec<Box<dyn AsRef<Path>>> = vec![
102            Box::new(new_folder_path.to_str().unwrap()), // &str
103            Box::new(new_folder_path.to_str().unwrap().to_string()), // String
104            Box::new(new_folder_path.as_path()),         // Path
105            Box::new(new_folder_path.clone()),           // PathBuf
106        ];
107
108        // Test with all different path formats.
109        for new_folder_path in new_folder_paths {
110            // Get a reference to this path representation (i.e. "unbox").
111            let new_folder_path: &dyn AsRef<Path> = new_folder_path.as_ref();
112
113            // The new folder should not exist yet.
114            assert!(!to_path_buf(new_folder_path).exists());
115
116            // Create the new folder.
117            create_folder(new_folder_path);
118
119            // Now the new folder should exist.
120            assert_folder_exists(new_folder_path);
121
122            // Try creating the folder again (should not panic or error).
123            create_folder(new_folder_path);
124
125            // The new folder should still exist.
126            assert_folder_exists(new_folder_path);
127
128            // Delete the new folder.
129            delete_folder(new_folder_path);
130        }
131    }
132
133    #[test]
134    fn test_create_folder_nested() {
135        // Create a temporary directory to work in.
136        let temp_dir = tempdir().unwrap();
137
138        // Define a nested folder path.
139        let nested = get_temp_dir_path(&temp_dir).join("a/b/c");
140
141        // Create the nested folder.
142        create_folder(&nested);
143
144        // Check that the deepest directory was successfully created.
145        assert_folder_exists(nested);
146    }
147
148    #[test]
149    fn test_create_folder_for_file() {
150        // Create a temporary directory to work in.
151        let temp_dir = tempdir().unwrap();
152
153        // Define a file path that requires a parent directory.
154        let file_path = get_temp_dir_path(&temp_dir).join("a/b/c/file.txt");
155
156        // File path in different formats.
157        let file_paths: Vec<Box<dyn AsRef<Path>>> = vec![
158            Box::new(file_path.to_str().unwrap()),             // &str
159            Box::new(file_path.to_str().unwrap().to_string()), // String
160            Box::new(file_path.as_path()),                     // Path
161            Box::new(file_path.clone()),                       // PathBuf
162        ];
163
164        // Test with all different path formats.
165        for file_path in file_paths {
166            // Get a reference to this path representation (i.e. "unbox").
167            let file_path = file_path.as_ref();
168
169            // File path as a pathbuf.
170            let file_path_buf = to_path_buf(file_path);
171
172            // The parent directory should not exist yet.
173            assert!(!file_path_buf.parent().unwrap().exists());
174
175            // Create the parent directory for the file.
176            create_folder_for_file(file_path);
177
178            // Now the parent directory should exist.
179            assert_folder_exists(file_path_buf.parent().unwrap());
180
181            // The file itself should not exist yet.
182            assert!(!file_path_buf.exists());
183
184            // Call `create_folder_for_file` again (should not panic or error).
185            create_folder_for_file(file_path);
186
187            // The parent directory should still exist.
188            assert_folder_exists(file_path_buf.parent().unwrap());
189
190            // Delete the parent directory.
191            delete_folder(file_path_buf.parent().unwrap());
192        }
193    }
194}