pathkit/
async_fs_ops.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
use anyhow::Result;
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json::{from_slice, to_vec_pretty};
use std::fs::{Metadata, Permissions};
use tokio::fs::{self, OpenOptions, ReadDir};
use tokio::task::spawn_blocking;

use super::core::Path;

#[async_trait::async_trait]
pub trait AsyncFsOps {
    #[cfg(unix)]
    async fn chmod(&self, mode: u32) -> Result<()>;
    #[cfg(unix)]
    async fn chown(&self, uid: Option<u32>, gid: Option<u32>) -> Result<()>;
    async fn create_dir(&self) -> Result<()>;
    async fn create_dir_all(&self) -> Result<()>;
    async fn empty_dir(&self) -> Result<()>;
    async fn exists(&self) -> Result<bool>;
    async fn get_file_size(&self) -> Result<u64>;
    #[cfg(unix)]
    async fn is_block_device(&self) -> Result<bool>;
    #[cfg(unix)]
    async fn is_char_device(&self) -> Result<bool>;
    async fn is_dir(&self) -> Result<bool>;
    #[cfg(unix)]
    async fn is_fifo(&self) -> Result<bool>;
    async fn is_file(&self) -> Result<bool>;
    #[cfg(unix)]
    async fn is_socket(&self) -> Result<bool>;
    async fn is_symlink(&self) -> Result<bool>;
    async fn metadata(&self) -> Result<Metadata>;
    async fn read(&self) -> Result<Vec<u8>>;
    async fn read_dir(&self) -> Result<ReadDir>;
    async fn read_json<T: DeserializeOwned>(&self) -> Result<T>;
    async fn read_to_string(&self) -> Result<String>;
    async fn remove_dir(&self) -> Result<()>;
    async fn remove_dir_all(&self) -> Result<()>;
    async fn set_permissions(&self, permissions: Permissions) -> Result<()>;
    async fn truncate(&self, len: Option<u64>) -> Result<()>;
    async fn write(&self, contents: impl AsRef<[u8]> + Send) -> Result<()>;
    async fn write_json(&self, data: impl Serialize + Send) -> Result<()>;
}

#[async_trait::async_trait]
impl AsyncFsOps for Path {
    #[cfg(unix)]
    async fn chmod(&self, mode: u32) -> Result<()> {
        use std::os::unix::fs::PermissionsExt;
        return Ok(fs::set_permissions(self, Permissions::from_mode(mode)).await?);
    }

    #[cfg(unix)]
    async fn chown(&self, uid: Option<u32>, gid: Option<u32>) -> Result<()> {
        let path = self.path.clone();
        return Ok(spawn_blocking(move || std::os::unix::fs::chown(path, uid, gid)).await??);
    }

    async fn create_dir(&self) -> Result<()> {
        return Ok(fs::create_dir(self).await?);
    }

    async fn create_dir_all(&self) -> Result<()> {
        return Ok(fs::create_dir_all(self).await?);
    }

    async fn empty_dir(&self) -> Result<()> {
        if !self.exists().await? {
            return self.create_dir_all().await;
        }

        let mut entries = fs::read_dir(self).await?;
        while let Some(entry) = entries.next_entry().await? {
            let entry_path = entry.path();
            if entry_path.is_dir() {
                fs::remove_dir_all(entry_path).await?;
            } else {
                fs::remove_file(entry_path).await?;
            }
        }

        return Ok(());
    }

    async fn exists(&self) -> Result<bool> {
        return Ok(fs::try_exists(self).await?);
    }

    async fn get_file_size(&self) -> Result<u64> {
        return Ok(self.metadata().await?.len());
    }

    #[cfg(unix)]
    async fn is_block_device(&self) -> Result<bool> {
        use std::os::unix::fs::FileTypeExt;
        return Ok(self.metadata().await?.file_type().is_block_device());
    }

    #[cfg(unix)]
    async fn is_char_device(&self) -> Result<bool> {
        use std::os::unix::fs::FileTypeExt;
        return Ok(self.metadata().await?.file_type().is_char_device());
    }

    async fn is_dir(&self) -> Result<bool> {
        return Ok(self.metadata().await?.is_dir());
    }

    #[cfg(unix)]
    async fn is_fifo(&self) -> Result<bool> {
        use std::os::unix::fs::FileTypeExt;
        return Ok(self.metadata().await?.file_type().is_fifo());
    }

    async fn is_file(&self) -> Result<bool> {
        return Ok(self.metadata().await?.is_file());
    }

    #[cfg(unix)]
    async fn is_socket(&self) -> Result<bool> {
        use std::os::unix::fs::FileTypeExt;
        return Ok(self.metadata().await?.file_type().is_socket());
    }

    async fn is_symlink(&self) -> Result<bool> {
        return Ok(fs::symlink_metadata(self).await?.file_type().is_symlink());
    }

    async fn metadata(&self) -> Result<Metadata> {
        return Ok(fs::metadata(self).await?);
    }

    async fn read(&self) -> Result<Vec<u8>> {
        return Ok(fs::read(self).await?);
    }

    async fn read_dir(&self) -> Result<ReadDir> {
        return Ok(fs::read_dir(self).await?);
    }

    async fn read_json<T: DeserializeOwned>(&self) -> Result<T> {
        return Ok(from_slice::<T>(&self.read().await?)?);
    }

    async fn read_to_string(&self) -> Result<String> {
        return Ok(fs::read_to_string(self).await?);
    }

    async fn remove_dir(&self) -> Result<()> {
        return Ok(fs::remove_dir(self).await?);
    }

    async fn remove_dir_all(&self) -> Result<()> {
        return Ok(fs::remove_dir_all(self).await?);
    }

    async fn set_permissions(&self, permissions: Permissions) -> Result<()> {
        return Ok(fs::set_permissions(self, permissions).await?);
    }

    async fn truncate(&self, len: Option<u64>) -> Result<()> {
        return Ok(OpenOptions::new()
            .write(true)
            .open(self)
            .await?
            .set_len(len.unwrap_or(0))
            .await?);
    }

    async fn write(&self, contents: impl AsRef<[u8]> + Send) -> Result<()> {
        return Ok(fs::write(self, contents).await?);
    }

    async fn write_json(&self, data: impl Serialize + Send) -> Result<()> {
        return self.write(to_vec_pretty(&data)?).await;
    }
}