Skip to main content

path_extra/tokio/
fs.rs

1#[cfg(unix)]
2use std::os::unix::fs::PermissionsExt as _;
3use std::{io, path::Path};
4
5use tokio::fs::{File, OpenOptions};
6
7#[trait_variant::make(Send)]
8pub trait FileExt {
9    async fn open_if_exists(path: impl AsRef<Path> + Send) -> io::Result<Option<Self>>
10    where
11        Self: Sized;
12
13    async fn create_if_not_exists(path: impl AsRef<Path> + Send) -> io::Result<Option<Self>>
14    where
15        Self: Sized;
16
17    async fn create_new_if_not_exists(path: impl AsRef<Path> + Send) -> io::Result<Option<Self>>
18    where
19        Self: Sized;
20
21    #[cfg(unix)]
22    async fn set_permissions_mode(&self, permissions_mode: u32) -> io::Result<&Self>;
23    #[cfg(unix)]
24    async fn add_permissions_mode(&self, permissions_mode: u32) -> io::Result<&Self>;
25    #[cfg(unix)]
26    async fn remove_permissions_mode(&self, permissions_mode: u32) -> io::Result<&Self>;
27}
28
29impl FileExt for File {
30    #[inline]
31    async fn open_if_exists(path: impl AsRef<Path> + Send) -> io::Result<Option<Self>> {
32        match Self::open(path).await {
33            Ok(file) => Ok(Some(file)),
34            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
35            Err(err) => Err(err),
36        }
37    }
38
39    #[inline]
40    async fn create_if_not_exists(path: impl AsRef<Path> + Send) -> io::Result<Option<Self>> {
41        let mut options = Self::options();
42
43        options.write(true).create_new(true);
44
45        options.open_if_not_exists(path).await
46    }
47
48    #[inline]
49    async fn create_new_if_not_exists(path: impl AsRef<Path> + Send) -> io::Result<Option<Self>> {
50        match Self::create_new(path).await {
51            Ok(file) => Ok(Some(file)),
52            Err(err) if err.kind() == io::ErrorKind::AlreadyExists => Ok(None),
53            Err(err) => Err(err),
54        }
55    }
56
57    #[cfg(unix)]
58    #[inline]
59    async fn set_permissions_mode(&self, permissions_mode: u32) -> io::Result<&Self> {
60        let metadata = self.metadata().await?;
61
62        let mut permissions = metadata.permissions();
63
64        permissions.set_mode(permissions_mode);
65
66        self.set_permissions(permissions).await?;
67
68        Ok(self)
69    }
70
71    #[cfg(unix)]
72    #[inline]
73    async fn add_permissions_mode(&self, permissions_mode: u32) -> io::Result<&Self> {
74        let metadata = self.metadata().await?;
75
76        let mut permissions = metadata.permissions();
77
78        permissions.set_mode(permissions.mode() | permissions_mode);
79
80        self.set_permissions(permissions).await?;
81
82        Ok(self)
83    }
84
85    #[cfg(unix)]
86    #[inline]
87    async fn remove_permissions_mode(&self, permissions_mode: u32) -> io::Result<&Self> {
88        let metadata = self.metadata().await?;
89
90        let mut permissions = metadata.permissions();
91
92        permissions.set_mode(permissions.mode() & !permissions_mode);
93
94        self.set_permissions(permissions).await?;
95
96        Ok(self)
97    }
98}
99
100#[trait_variant::make(Send)]
101pub trait OpenOptionsExt {
102    async fn open_if_exists(&self, path: impl AsRef<Path> + Send) -> io::Result<Option<File>>;
103
104    async fn open_if_not_exists(&self, path: impl AsRef<Path> + Send) -> io::Result<Option<File>>;
105}
106
107impl OpenOptionsExt for OpenOptions {
108    #[inline]
109    async fn open_if_exists(&self, path: impl AsRef<Path> + Send) -> io::Result<Option<File>> {
110        match self.open(path).await {
111            Ok(file) => Ok(Some(file)),
112            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
113            Err(err) => Err(err),
114        }
115    }
116
117    #[inline]
118    async fn open_if_not_exists(&self, path: impl AsRef<Path> + Send) -> io::Result<Option<File>> {
119        match self.open(path).await {
120            Ok(file) => Ok(Some(file)),
121            Err(err) if err.kind() == io::ErrorKind::AlreadyExists => Ok(None),
122            Err(err) => Err(err),
123        }
124    }
125}