maybe_fut/api/fs/
dir_builder.rs

1use crate::maybe_fut_method;
2
3/// A builder for creating directories in various manners.
4#[derive(Debug, Unwrap)]
5#[unwrap_types(
6    std(std::fs::DirBuilder),
7    tokio(tokio::fs::DirBuilder),
8    tokio_gated("tokio-fs")
9)]
10pub struct DirBuilder(DirBuilderInner);
11
12#[derive(Debug)]
13enum DirBuilderInner {
14    /// Std variant of file <https://docs.rs/rustc-std-workspace-std/latest/std/fs/struct.DirBuilder.html>
15    Std(std::fs::DirBuilder),
16    #[cfg(tokio_fs)]
17    #[cfg_attr(docsrs, doc(cfg(feature = "tokio-fs")))]
18    /// Tokio variant of file <https://docs.rs/tokio/latest/tokio/fs/struct.DirBuilder.html>
19    Tokio(tokio::fs::DirBuilder),
20}
21
22impl Default for DirBuilder {
23    fn default() -> Self {
24        Self::new()
25    }
26}
27
28impl From<std::fs::DirBuilder> for DirBuilder {
29    fn from(inner: std::fs::DirBuilder) -> Self {
30        Self(DirBuilderInner::Std(inner))
31    }
32}
33
34#[cfg(tokio_fs)]
35#[cfg_attr(docsrs, doc(cfg(feature = "tokio-fs")))]
36impl From<tokio::fs::DirBuilder> for DirBuilder {
37    fn from(inner: tokio::fs::DirBuilder) -> Self {
38        Self(DirBuilderInner::Tokio(inner))
39    }
40}
41
42impl DirBuilder {
43    /// Creates a new set of options with default mode/security settings for all platforms and also non-recursive.
44    pub fn new() -> Self {
45        #[cfg(tokio_fs)]
46        {
47            if crate::context::is_async_context() {
48                tokio::fs::DirBuilder::new().into()
49            } else {
50                std::fs::DirBuilder::new().into()
51            }
52        }
53        #[cfg(not(tokio_fs))]
54        {
55            std::fs::DirBuilder::new().into()
56        }
57    }
58
59    #[cfg(unix)]
60    #[cfg_attr(docsrs, doc(cfg(unix)))]
61    /// Sets the mode to create new directories with.
62    ///
63    /// This option defaults to `0o777`.
64    pub fn mode(&mut self, mode: u32) -> &mut Self {
65        use std::os::unix::fs::DirBuilderExt as _;
66
67        match &mut self.0 {
68            DirBuilderInner::Std(inner) => {
69                inner.mode(mode);
70            }
71            #[cfg(tokio_fs)]
72            #[cfg_attr(docsrs, doc(cfg(feature = "tokio-fs")))]
73            DirBuilderInner::Tokio(inner) => {
74                inner.mode(mode);
75            }
76        }
77
78        self
79    }
80
81    /// Indicates whether to create directories recursively (including all parent directories).
82    /// Parents that do not exist are created with the same security and permissions settings.
83    ///
84    /// This option defaults to `false`.
85    pub fn recursive(&mut self, recursive: bool) -> &mut Self {
86        match &mut self.0 {
87            DirBuilderInner::Std(inner) => {
88                inner.recursive(recursive);
89            }
90            #[cfg(tokio_fs)]
91            #[cfg_attr(docsrs, doc(cfg(feature = "tokio-fs")))]
92            DirBuilderInner::Tokio(inner) => {
93                inner.recursive(recursive);
94            }
95        }
96
97        self
98    }
99
100    maybe_fut_method!(
101        /// Creates the specified directory with the configured options.
102        ///
103        /// It is considered an error if the directory already exists unless recursive mode is enabled.
104        ///
105        /// This is an async version of std::fs::DirBuilder::create.
106        ///
107        /// # Errors
108        ///
109        /// An error will be returned under the following circumstances:
110        ///
111        /// - Path already points to an existing file.
112        /// - Path already points to an existing directory and the mode is non-recursive.
113        /// - The calling process doesn’t have permissions to create the directory or its missing parents.
114        /// - Other I/O error occurred.
115        create(path: impl AsRef<std::path::Path>) -> std::io::Result<()>,
116        DirBuilderInner::Std,
117        DirBuilderInner::Tokio,
118        tokio_fs
119    );
120}
121
122#[cfg(test)]
123mod test {
124
125    use super::*;
126    use crate::SyncRuntime;
127
128    #[test]
129    fn test_dir_builder_sync() {
130        let tempdir = tempfile::tempdir().unwrap();
131        let path = tempdir.path().join("test_dir");
132        let mut builder = DirBuilder::new();
133        builder.recursive(true);
134        SyncRuntime::block_on(builder.create(&path)).expect("Failed to create directory");
135        assert!(path.exists());
136    }
137
138    #[tokio::test]
139    async fn test_dir_builder_async() {
140        let tempdir = tempfile::tempdir().unwrap();
141        let path = tempdir.path().join("test_dir");
142        let mut builder = DirBuilder::new();
143        builder.recursive(true);
144        builder
145            .create(&path)
146            .await
147            .expect("Failed to create directory");
148        assert!(path.exists());
149    }
150}