devela 0.27.0

A development layer of coherence.
Documentation
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
// devela::sys::fs::fs_path
//
//! Defines the `FsPath` wrapper.
//
// TOC
// - unix methods
//   - traverse symbolic links
//   - optionally traverse symbolic links
// - windows methods
// - from/into Path/PathBuf

use crate::PathBuf;

#[doc = crate::_tags!(fs namespace)]
/// A more featureful wrapper over [`PathBuf`].
///
/// # Table of contents
/// - [General methods](#general-methods)
/// - [Methods that traverse symbolic links](#methods-that-traverse-symbolic-links)
/// - [Methods that *optionally* traverse symbolic links](#methods-that-optionally-traverse-symbolic-links)
/// - [`unix` methods that traverse symbolic links](#unix-methods-that-traverse-symbolic-links)
/// - [`unix` methods that *optionally* traverse symbolic links](#unix-methods-that-optionally-traverse-symbolic-links)
/// - [`windows` methods](#windows-methods)
///
/// # Symlink traversal
/// Most methods traverse symbolic links along the path,
/// while the `_ts` suffixed variants can do so, optionally.
///
/// ```
/// # use devela::FsPath;
/// # fn main() {
/// # let some_path = FsPath::new("some_path");
/// assert_eq![some_path.exists(), some_path.exists_ts(true)];
/// # }
/// ```
#[must_use]
#[derive(Debug, Clone)]
pub struct FsPath {
    /// The inner `PathBuf`.
    pub path: PathBuf,
}

mod methods {
    use crate::{
        Cow, Env, FileMetadata, FilePermissions, FileType, Fs, FsPath, IoError, IoErrorKind,
        IoResult, Path, PathBuf, PathDisplay, SystemTime,
    };

    /// # General methods.
    #[rustfmt::skip]
    impl FsPath {
        /// Returns a `FsPath` from what could've been a [`Path`].
        pub fn new<P: AsRef<Path>>(path: P) -> Self { Self { path: path.as_ref().to_path_buf() } }

        /// Returns the current working directory.
        ///
        /// Calls `std::env::`[`current_dir`][std::env::current_dir] under the hood.
        pub fn from_current_dir() -> IoResult<Self> { Ok(Self { path: Env::current_dir()? }) }

        /// Retuns the path of `CARGO_MANIFEST_DIR`.
        pub fn from_manifest_dir() -> Self {
            Self {
                path: PathBuf::from(Env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"))
            }
        }

        /// Retuns the path of `CARGO_MANIFEST_PATH`.
        pub fn from_manifest_path() -> Self {
            Self {
                path: PathBuf::from(Env::var("CARGO_MANIFEST_PATH").expect("CARGO_MANIFEST_PATH not set"))
            }
        }

        /// Returns a temporary directory.
        ///
        /// Calls `std::env::`[`temp_dir`][std::env::temp_dir] under the hood.
        pub fn from_temp_dir() -> Self { Self { path: Env::temp_dir() } }


        /// Resolves a given path relative to the nearest `Cargo.toml` directory.
        ///
        /// This function searches for the nearest `Cargo.toml` file starting from the
        /// current working directory and traversing upwards through its ancestors.
        /// Once the `Cargo.toml` is found, the provided `path` is appended to its directory.
        ///
        /// # Errors
        /// Returns an error if it can't find any `Cargo.toml` file,
        /// or if it encounters an invalid path during the search process.
        ///
        /// # Examples
        /// ```
        /// use devela::FsPath;
        /// match FsPath::from_crate_root("") {
        ///     Ok(p) => println!("Current crate root is {:?}", p),
        ///     Err(e) => println!("Error obtaining crate root {:?}", e)
        /// };
        /// ```
        #[cfg(not(miri))] // unsupported operation: getcwd not available when isolation is enabled
        pub fn from_crate_root<P: AsRef<Path>>(path: P) -> IoResult<Self> {
            let current_path = Env::current_dir()?;
            let mut root_path = current_path.clone();

            for p in current_path.as_path().ancestors() {
                let has_cargo = Fs::read_dir(p)?.any(|p| p.unwrap().file_name() == *"Cargo.toml");
                if has_cargo {
                    return Ok(Self { path: root_path.join(path.as_ref()) });
                }
                root_path.pop();
            }
            Err(IoError::new(IoErrorKind::NotFound, "Ran out of places to find Cargo.toml"))
        }

        /// Returns the canonical, absolute form of the path with all intermediate
        /// components normalized and symbolic links resolved.
        ///
        /// Calls `std::fs::`[`canonicalize`][std::fs::canonicalize] under the hood.
        pub fn canonicalize(&self) -> IoResult<FsPath> {
            self.path.canonicalize().map(|path| Self { path })
        }

        /// Reads a symbolic link, returning the file that the link points to.
        ///
        /// This function will return an error in the following situations,
        /// but is not limited to just these cases:
        /// - path is not a symbolic link.
        /// - path does not exist.
        ///
        /// Calls `std::fs::`[`read_link`][std::fs::read_link] under the hood.
        pub fn read_link(&self) -> IoResult<FsPath> {
            self.path.read_link().map(|path| Self { path })
        }

        /// Is this path absolute?
        pub fn is_absolute(&self) -> bool { self.path.is_absolute() }

        /// Is this path relative?
        pub fn is_relative(&self) -> bool { self.path.is_relative() }

        /// Returns the path without its final component, if there is one.
        ///
        /// Returns `None` if the path terminates in a root or prefix.
        pub fn parent(&self) -> Option<FsPath> { self.path.parent().map(|o| o.into()) }

        /// Truncates `self` to [`self.parent`].
        ///
        /// Returns `false` and does nothing if [`self.parent`] is `None`.
        /// Otherwise, returns `true`.
        ///
        /// [`self.parent`]: FsPath#method.parent
        pub fn pop(&mut self) -> bool { self.path.pop() }

        /// Extends `self` with `path`.
        ///
        /// If `path` is absolute, it replaces the current path.
        ///
        /// Calls `std::path::`[`PathBuf::push`] under the hood.
        pub fn push<P: AsRef<Path>>(&mut self, path: P) { self.path.push(path); }

        /// Returns an object that implements [`Display`][core::fmt::Display].
        pub fn display(&self) -> PathDisplay<'_> { self.as_path().display() }

        /// Yields a [`&str`] slice if the FsPath is valid unicode.
        pub fn to_str(&self) -> Option<&str> { self.path.to_str() }

        /// Converts a `FsPath` to a `Cow<str>`.
        ///
        /// Any non-Unicode sequences are replaced with [`U+FFFD REPLACEMENT CHARACTER`][0].
        ///
        /// [0]: https://doc.rust-lang.org/1.62.1/std/char/constant.REPLACEMENT_CHARACTER.html
        pub fn to_string_lossy(&self) -> Cow<'_, str> { self.path.to_string_lossy() }

        /// Returns the inner [`PathBuf`].
        pub fn into_inner(self) -> PathBuf { self.into() }

        /// Returns an exclusive reference to the inner `PathBuf`.
        pub fn into_ref_mut(&mut self) -> &mut PathBuf { self.into() }

        /// Coerces the inner [`PathBuf`] to a [`Path`] slice.
        pub fn as_path(&self) -> &Path { self.into() }
    }

    /// # Methods that traverse symbolic links
    #[rustfmt::skip]
    impl FsPath {
        /* methods that coerce to bool */

        /// Does this path exist?
        pub fn exists(&self) -> bool { self.path.exists() }
        /// Is this a file?
        pub fn is_file(&self) -> bool { self.path.is_file() }
        /// Is this a directory?
        pub fn is_dir(&self) -> bool { self.path.is_dir() }
        /// Is this a symbolic link?
        pub fn is_symlink(&self) -> bool { self.metadata().is_ok_and(|m| m.is_symlink()) }

        /* methods that return IoResult */

        /// Returns the metadata.
        pub fn metadata(&self) -> IoResult<FileMetadata> { self.path.metadata() }
        /// Returns the `FileType`.
        pub fn file_type(&self) -> IoResult<FileType> { Ok(self.metadata()?.file_type()) }
        /// Returns the size of the file, in bytes.
        pub fn len(&self) -> IoResult<u64> { Ok(self.metadata()?.len()) }
        /// Returns true if the file size equals zero.
        pub fn is_empty(&self) -> IoResult<bool> { Ok(self.len()? == 0) }
        /// Returns the time of creation.
        pub fn created(&self) -> IoResult<SystemTime> { self.metadata()?.created() }
        /// Returns the time of access.
        pub fn accessed(&self) -> IoResult<SystemTime> { self.metadata()?.accessed() }
        /// Returns the time of modification.
        pub fn modified(&self) -> IoResult<SystemTime> { self.metadata()?.modified() }

        // permissions

        /// Returns the permissions of the file.
        pub fn permissions(&self) -> IoResult<FilePermissions> {
            Ok(self.metadata()?.permissions())
        }
        /// Is this a read-only file?
        pub fn is_readonly(&self) -> IoResult<bool> { Ok(self.permissions()?.readonly()) }
        /// Sets the read-only flag, returning the previous read-only state.
        pub fn set_readonly(&mut self, readonly: bool) -> IoResult<bool> {
            let prev = self.is_readonly()?;
            self.permissions()?.set_readonly(readonly);
            Ok(prev)
        }
    }

    /// # Methods that *optionally* traverse symbolic links
    impl FsPath {
        /* methods that coerce to bool */

        /// Does this path exist?
        pub fn exists_ts(&self, traverse: bool) -> bool {
            self.metadata_ts(traverse).is_ok()
        }
        /// Is this a file?
        pub fn is_file_ts(&self, traverse: bool) -> bool {
            self.metadata_ts(traverse).is_ok_and(|m| m.is_file())
        }
        /// Is this a directory?
        pub fn is_dir_ts(&self, traverse: bool) -> bool {
            self.metadata_ts(traverse).is_ok_and(|m| m.is_dir())
        }
        /// Is this a symbolic link?
        pub fn is_symlink_ts(&self, traverse: bool) -> bool {
            self.metadata_ts(traverse).is_ok_and(|m| m.is_symlink())
        }

        /* methods that return IoResult */

        /// Returns the metadata that *optionally* traverses symbolic links.
        pub fn metadata_ts(&self, traverse: bool) -> IoResult<FileMetadata> {
            if traverse { self.path.metadata() } else { self.path.symlink_metadata() }
        }

        /// Returns the `FileType`.
        pub fn file_type_ts(&self, traverse: bool) -> IoResult<FileType> {
            Ok(self.metadata_ts(traverse)?.file_type())
        }

        /// Returns the size of the file, in bytes.
        #[allow(clippy::len_without_is_empty)]
        pub fn len_ts(&self, traverse: bool) -> IoResult<u64> {
            Ok(self.metadata_ts(traverse)?.len())
        }

        /// Returns true if the file size equals zero.
        pub fn is_empty_ts(&self, traverse: bool) -> IoResult<bool> {
            Ok(self.len_ts(traverse)? == 0)
        }
        /// Returns the time of creation.
        pub fn created_ts(&self, traverse: bool) -> IoResult<SystemTime> {
            self.metadata_ts(traverse)?.created()
        }
        /// Returns the time of access.
        pub fn accessed_ts(&self, traverse: bool) -> IoResult<SystemTime> {
            self.metadata_ts(traverse)?.accessed()
        }
        /// Returns the time of modification.
        pub fn modified_ts(&self, traverse: bool) -> IoResult<SystemTime> {
            self.metadata_ts(traverse)?.modified()
        }

        // permissions

        /// Returns the permissions of the file.
        pub fn permissions_ts(&self, traverse: bool) -> IoResult<FilePermissions> {
            Ok(self.metadata_ts(traverse)?.permissions())
        }

        /// Is this a read-only file?
        pub fn is_readonly_ts(&self, traverse: bool) -> IoResult<bool> {
            Ok(self.permissions_ts(traverse)?.readonly())
        }

        /// Sets the read-only flag, returning the previous read-only state.
        pub fn set_readonly_ts(&mut self, readonly: bool, traverse: bool) -> IoResult<bool> {
            let prev = self.is_readonly_ts(traverse)?;
            self.permissions_ts(traverse)?.set_readonly(readonly);
            Ok(prev)
        }
    }
}

// - https://doc.rust-lang.org/std/os/linux/fs/trait.MetadataExt.html
// - https://doc.rust-lang.org/std/fs/struct.Metadata.html#impl-MetadataExt-1
//
// - https://doc.rust-lang.org/std/os/unix/fs/trait.MetadataExt.html
// - https://doc.rust-lang.org/std/fs/struct.Metadata.html#impl-MetadataExt
#[cfg(unix)]
mod unix {
    use super::FsPath;
    use crate::IoResult;
    use std::os::unix::fs::MetadataExt;

    /// # `unix` methods that traverse symbolic links
    #[rustfmt::skip]
    impl FsPath {
        /// Returns the ID of the device containing the file.
        pub fn dev(&self) -> IoResult<u64> { Ok(self.metadata()?.dev()) }
        /// Returns the inode number.
        pub fn ino(&self) -> IoResult<u64> { Ok(self.metadata()?.ino()) }
        /// Returns the rights applied to this file.
        pub fn mode(&self) -> IoResult<u32> { Ok(self.metadata()?.mode()) }
        /// Returns the number of hard links pointing to this file.
        pub fn nlink(&self) -> IoResult<u64> { Ok(self.metadata()?.nlink()) }
        /// Returns the user ID of the owner of this file.
        pub fn uid(&self) -> IoResult<u32> { Ok(self.metadata()?.uid()) }
        /// Returns the group ID of the owner of this file.
        pub fn gid(&self) -> IoResult<u32> { Ok(self.metadata()?.gid()) }
        /// Returns the device ID of this file (if it is a special one).
        pub fn rdev(&self) -> IoResult<u64> { Ok(self.metadata()?.rdev()) }
        /// Returns the total size of this file in bytes.
        pub fn size(&self) -> IoResult<u64> { Ok(self.metadata()?.size()) }
        /// Returns the last access time of the file, in seconds since Unix Epoch.
        pub fn atime(&self) -> IoResult<i64> { Ok(self.metadata()?.atime()) }
        /// Returns the last access time of the file, in nanoseconds since atime.
        pub fn atime_nsec(&self) -> IoResult<i64> { Ok(self.metadata()?.atime_nsec()) }
        /// Returns the last modification time of the file, in seconds since Unix Epoch.
        pub fn mtime(&self) -> IoResult<i64> { Ok(self.metadata()?.mtime()) }
        /// Returns the last modification time of the file, in nanoseconds since mtime.
        pub fn mtime_nsec(&self) -> IoResult<i64> { Ok(self.metadata()?.mtime_nsec()) }
        /// Returns the last status change time of the file, in seconds since Unix Epoch.
        pub fn ctime(&self) -> IoResult<i64> { Ok(self.metadata()?.ctime()) }
        /// Returns the last status change time of the file, in nanoseconds since ctime.
        pub fn ctime_nsec(&self) -> IoResult<i64> { Ok(self.metadata()?.ctime_nsec()) }
        /// Returns the block size for filesystem I/O.
        pub fn blksize(&self) -> IoResult<u64> { Ok(self.metadata()?.blksize()) }
        /// Returns the number of blocks allocated to the file, in 512-byte units.
        pub fn blocks(&self) -> IoResult<u64> { Ok(self.metadata()?.blocks()) }
    }

    /// # `unix` methods that *optionally* traverse symbolic links
    impl FsPath {
        /// Returns the ID of the device containing the file.
        pub fn dev_ts(&self, traverse: bool) -> IoResult<u64> {
            Ok(self.metadata_ts(traverse)?.dev())
        }
        /// Returns the inode number.
        pub fn ino_ts(&self, traverse: bool) -> IoResult<u64> {
            Ok(self.metadata_ts(traverse)?.ino())
        }
        /// Returns the rights applied to this file.
        pub fn mode_ts(&self, traverse: bool) -> IoResult<u32> {
            Ok(self.metadata_ts(traverse)?.mode())
        }
        /// Returns the number of hard links pointing to this file.
        pub fn nlink_ts(&self, traverse: bool) -> IoResult<u64> {
            Ok(self.metadata_ts(traverse)?.nlink())
        }
        /// Returns the user ID of the owner of this file.
        pub fn uid_ts(&self, traverse: bool) -> IoResult<u32> {
            Ok(self.metadata_ts(traverse)?.uid())
        }
        /// Returns the group ID of the owner of this file.
        pub fn gid_ts(&self, traverse: bool) -> IoResult<u32> {
            Ok(self.metadata_ts(traverse)?.gid())
        }
        /// Returns the device ID of this file (if it is a special one).
        pub fn rdev_ts(&self, traverse: bool) -> IoResult<u64> {
            Ok(self.metadata_ts(traverse)?.rdev())
        }
        /// Returns the total size of this file in bytes.
        pub fn size_ts(&self, traverse: bool) -> IoResult<u64> {
            Ok(self.metadata_ts(traverse)?.size())
        }
        /// Returns the last access time of the file, in seconds since Unix Epoch.
        pub fn atime_ts(&self, traverse: bool) -> IoResult<i64> {
            Ok(self.metadata_ts(traverse)?.atime())
        }
        /// Returns the last access time of the file, in nanoseconds since atime.
        pub fn atime_nsec_ts(&self, traverse: bool) -> IoResult<i64> {
            Ok(self.metadata_ts(traverse)?.atime_nsec())
        }
        /// Returns the last modification time of the file, in seconds since Unix Epoch.
        pub fn mtime_ts(&self, traverse: bool) -> IoResult<i64> {
            Ok(self.metadata_ts(traverse)?.mtime())
        }
        /// Returns the last modification time of the file, in nanoseconds since mtime.
        pub fn mtime_nsec_ts(&self, traverse: bool) -> IoResult<i64> {
            Ok(self.metadata_ts(traverse)?.mtime_nsec())
        }
        /// Returns the last status change time of the file, in seconds since Unix Epoch.
        pub fn ctime_ts(&self, traverse: bool) -> IoResult<i64> {
            Ok(self.metadata_ts(traverse)?.ctime())
        }
        /// Returns the last status change time of the file, in nanoseconds since ctime.
        pub fn ctime_nsec_ts(&self, traverse: bool) -> IoResult<i64> {
            Ok(self.metadata_ts(traverse)?.ctime_nsec())
        }
        /// Returns the block size for filesystem I/O.
        pub fn blksize_ts(&self, traverse: bool) -> IoResult<u64> {
            Ok(self.metadata_ts(traverse)?.blksize())
        }
        /// Returns the number of blocks allocated to the file, in 512-byte units.
        pub fn blocks_ts(&self, traverse: bool) -> IoResult<u64> {
            Ok(self.metadata_ts(traverse)?.blocks())
        }
    }
}

// https://doc.rust-lang.org/std/os/linux/fs/trait.MetadataExt.html
// https://doc.rust-lang.org/std/fs/struct.Metadata.html#impl-MetadataExt-3
#[cfg(any(windows, doc))]
#[rustfmt::skip]
mod windows {
    use super::FsPath;
    use crate::IoResult;

    #[cfg(windows)]
    use std::os::windows::fs::MetadataExt;
    // Mockup:
    #[cfg(not(windows))]
    crate::items! {
        // https://doc.rust-lang.org/std/os/windows/fs/trait.MetadataExt.html
        #[allow(missing_docs, dead_code)]
        trait MetadataExt {
            fn file_attributes(&self) -> u32 {0}
            fn creation_time(&self) -> u64 {0}
            fn last_access_time(&self) -> u64 {0}
            fn last_write_time(&self) -> u64 {0}
            fn file_size(&self) -> u64 {0}
            fn volume_serial_number(&self) -> Option<u32> {None}
            fn number_of_links(&self) -> Option<u32> {None}
            fn file_index(&self) -> Option<u64> {None}
            fn change_time(&self) -> Option<u64> {None}
        }
        impl MetadataExt for crate::FileMetadata {}
    }

    /// # `windows` methods
    impl FsPath {
        /// Returns the value of the dwFileAttributes field of this metadata.
        pub fn file_attributes(&self) -> IoResult<u32> { Ok(self.metadata()?.file_attributes()) }
        /// Returns the value of the ftCreationTime field of this metadata.
        pub fn creation_time(&self) -> IoResult<u64> { Ok(self.metadata()?.creation_time()) }
        /// Returns the value of the ftLastAccessTime field of this metadata.
        pub fn last_access_time(&self) -> IoResult<u64> { Ok(self.metadata()?.last_access_time()) }
        /// Returns the value of the ftLastWriteTime field of this metadata.
        pub fn last_write_time(&self) -> IoResult<u64> { Ok(self.metadata()?.last_write_time()) }
        /// Returns the value of the nFileSize{High,Low} fields of this metadata.
        pub fn file_size(&self) -> IoResult<u64> { Ok(self.metadata()?.file_size()) }
    }
}

#[rustfmt::skip]
mod std_impls {
    use super::{FsPath, PathBuf};
    use crate::Path;

    // From<PathBuf>
    impl From<PathBuf> for FsPath { fn from(path: PathBuf) -> Self { Self { path } } }
    impl From<&PathBuf> for FsPath { fn from(path: &PathBuf) -> Self { Self::new(path) } }
    impl From<&mut PathBuf> for FsPath { fn from(path: &mut PathBuf) -> Self { Self::new(path) } }
    // Into<PathBuf>
    impl From<FsPath> for PathBuf { fn from(fspath: FsPath) -> Self { fspath.path } }
    impl From<&FsPath> for PathBuf { fn from(fspath: &FsPath) -> Self { fspath.path.clone() } }
    impl From<&mut FsPath> for PathBuf { fn from(fspath: &mut FsPath)
        -> Self { fspath.path.clone() } }
    impl<'a> From<&'a FsPath> for &'a PathBuf { fn from(fspath: &'a FsPath)
        -> Self { &fspath.path } }
    impl<'a> From<&'a mut FsPath> for &'a mut PathBuf { fn from(fspath: &'a mut FsPath)
        -> Self { &mut fspath.path } }
    // From<Path>
    impl From<&Path> for FsPath { fn from(path: &Path) -> Self { Self::new(path) } }
    impl From<&mut Path> for FsPath { fn from(path: &mut Path) -> Self { Self::new(path) } }
    // Into<Path>
    impl<'a> From<&'a FsPath> for &'a Path { fn from(fspath: &'a FsPath)
        -> Self { fspath.path.as_path() } }
    impl<'a> From<&'a mut FsPath> for &'a Path { fn from(fspath: &'a mut FsPath)
        -> Self { fspath.path.as_path() } }
}