tauri_plugin_fs/
file_path.rs1use std::{
6 convert::Infallible,
7 path::{Path, PathBuf},
8 str::FromStr,
9};
10
11use serde::Serialize;
12use tauri::path::SafePathBuf;
13
14use crate::{Error, Result};
15
16#[derive(Debug, Serialize, Clone)]
19#[serde(untagged)]
20pub enum FilePath {
21 Url(url::Url),
23 Path(PathBuf),
25}
26
27#[derive(Debug, Clone, Serialize)]
30pub enum SafeFilePath {
31 Url(url::Url),
33 Path(SafePathBuf),
35}
36
37impl FilePath {
38 #[inline]
42 pub fn as_path(&self) -> Option<&Path> {
43 match self {
44 Self::Url(_) => None,
45 Self::Path(p) => Some(p),
46 }
47 }
48
49 #[inline]
54 pub fn into_path(self) -> Result<PathBuf> {
55 match self {
56 Self::Url(url) => url
57 .to_file_path()
58 .map(PathBuf::from)
59 .map_err(|_| Error::InvalidPathUrl),
60 Self::Path(p) => Ok(p),
61 }
62 }
63
64 #[inline]
67 pub fn simplified(self) -> Self {
68 match self {
69 Self::Url(url) => Self::Url(url),
70 Self::Path(p) => Self::Path(dunce::simplified(&p).to_path_buf()),
71 }
72 }
73}
74
75impl SafeFilePath {
76 #[inline]
80 pub fn as_path(&self) -> Option<&Path> {
81 match self {
82 Self::Url(_) => None,
83 Self::Path(p) => Some(p.as_ref()),
84 }
85 }
86
87 #[inline]
92 pub fn into_path(self) -> Result<PathBuf> {
93 match self {
94 Self::Url(url) => url
95 .to_file_path()
96 .map(PathBuf::from)
97 .map_err(|_| Error::InvalidPathUrl),
98 Self::Path(p) => Ok(p.as_ref().to_owned()),
99 }
100 }
101
102 #[inline]
105 pub fn simplified(self) -> Self {
106 match self {
107 Self::Url(url) => Self::Url(url),
108 Self::Path(p) => {
109 Self::Path(SafePathBuf::new(dunce::simplified(p.as_ref()).to_path_buf()).unwrap())
111 }
112 }
113 }
114}
115
116impl std::fmt::Display for FilePath {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 match self {
119 Self::Url(u) => u.fmt(f),
120 Self::Path(p) => p.display().fmt(f),
121 }
122 }
123}
124
125impl std::fmt::Display for SafeFilePath {
126 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127 match self {
128 Self::Url(u) => u.fmt(f),
129 Self::Path(p) => p.display().fmt(f),
130 }
131 }
132}
133
134impl<'de> serde::Deserialize<'de> for FilePath {
135 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
136 where
137 D: serde::Deserializer<'de>,
138 {
139 struct FilePathVisitor;
140
141 impl serde::de::Visitor<'_> for FilePathVisitor {
142 type Value = FilePath;
143
144 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
145 formatter.write_str("a string representing an file URL or a path")
146 }
147
148 fn visit_str<E>(self, s: &str) -> std::result::Result<Self::Value, E>
149 where
150 E: serde::de::Error,
151 {
152 FilePath::from_str(s).map_err(|e| {
153 serde::de::Error::invalid_value(
154 serde::de::Unexpected::Str(s),
155 &e.to_string().as_str(),
156 )
157 })
158 }
159 }
160
161 deserializer.deserialize_str(FilePathVisitor)
162 }
163}
164
165impl<'de> serde::Deserialize<'de> for SafeFilePath {
166 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
167 where
168 D: serde::Deserializer<'de>,
169 {
170 struct SafeFilePathVisitor;
171
172 impl serde::de::Visitor<'_> for SafeFilePathVisitor {
173 type Value = SafeFilePath;
174
175 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
176 formatter.write_str("a string representing an file URL or a path")
177 }
178
179 fn visit_str<E>(self, s: &str) -> std::result::Result<Self::Value, E>
180 where
181 E: serde::de::Error,
182 {
183 SafeFilePath::from_str(s).map_err(|e| {
184 serde::de::Error::invalid_value(
185 serde::de::Unexpected::Str(s),
186 &e.to_string().as_str(),
187 )
188 })
189 }
190 }
191
192 deserializer.deserialize_str(SafeFilePathVisitor)
193 }
194}
195
196impl FromStr for FilePath {
197 type Err = Infallible;
198 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
199 if let Ok(url) = url::Url::from_str(s) {
200 if url.scheme().len() != 1 {
201 return Ok(Self::Url(url));
202 }
203 }
204 Ok(Self::Path(PathBuf::from(s)))
205 }
206}
207
208impl FromStr for SafeFilePath {
209 type Err = Error;
210 fn from_str(s: &str) -> Result<Self> {
211 if let Ok(url) = url::Url::from_str(s) {
212 if url.scheme().len() != 1 {
213 return Ok(Self::Url(url));
214 }
215 }
216
217 SafePathBuf::new(s.into())
218 .map(SafeFilePath::Path)
219 .map_err(Error::UnsafePathBuf)
220 }
221}
222
223impl From<PathBuf> for FilePath {
224 fn from(value: PathBuf) -> Self {
225 Self::Path(value)
226 }
227}
228
229impl TryFrom<PathBuf> for SafeFilePath {
230 type Error = Error;
231 fn try_from(value: PathBuf) -> Result<Self> {
232 SafePathBuf::new(value)
233 .map(SafeFilePath::Path)
234 .map_err(Error::UnsafePathBuf)
235 }
236}
237
238impl From<&Path> for FilePath {
239 fn from(value: &Path) -> Self {
240 Self::Path(value.to_owned())
241 }
242}
243
244impl TryFrom<&Path> for SafeFilePath {
245 type Error = Error;
246 fn try_from(value: &Path) -> Result<Self> {
247 SafePathBuf::new(value.to_path_buf())
248 .map(SafeFilePath::Path)
249 .map_err(Error::UnsafePathBuf)
250 }
251}
252
253impl From<&PathBuf> for FilePath {
254 fn from(value: &PathBuf) -> Self {
255 Self::Path(value.to_owned())
256 }
257}
258
259impl TryFrom<&PathBuf> for SafeFilePath {
260 type Error = Error;
261 fn try_from(value: &PathBuf) -> Result<Self> {
262 SafePathBuf::new(value.to_owned())
263 .map(SafeFilePath::Path)
264 .map_err(Error::UnsafePathBuf)
265 }
266}
267
268impl From<url::Url> for FilePath {
269 fn from(value: url::Url) -> Self {
270 Self::Url(value)
271 }
272}
273
274impl From<url::Url> for SafeFilePath {
275 fn from(value: url::Url) -> Self {
276 Self::Url(value)
277 }
278}
279
280impl TryFrom<FilePath> for PathBuf {
281 type Error = Error;
282 fn try_from(value: FilePath) -> Result<Self> {
283 value.into_path()
284 }
285}
286
287impl TryFrom<SafeFilePath> for PathBuf {
288 type Error = Error;
289 fn try_from(value: SafeFilePath) -> Result<Self> {
290 value.into_path()
291 }
292}
293
294impl From<SafeFilePath> for FilePath {
295 fn from(value: SafeFilePath) -> Self {
296 match value {
297 SafeFilePath::Url(url) => FilePath::Url(url),
298 SafeFilePath::Path(p) => FilePath::Path(p.as_ref().to_owned()),
299 }
300 }
301}
302
303impl TryFrom<FilePath> for SafeFilePath {
304 type Error = Error;
305
306 fn try_from(value: FilePath) -> Result<Self> {
307 match value {
308 FilePath::Url(url) => Ok(SafeFilePath::Url(url)),
309 FilePath::Path(p) => SafePathBuf::new(p)
310 .map(SafeFilePath::Path)
311 .map_err(Error::UnsafePathBuf),
312 }
313 }
314}