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}