1use core::str;
2use std::borrow::Cow;
3use std::env::VarError;
4use std::ffi::OsStr;
5use std::ffi::OsString;
6use std::io;
7use std::io::Error;
8use std::io::ErrorKind;
9use std::path::Path;
10use std::path::PathBuf;
11use std::time::SystemTime;
12
13pub mod boxed;
14pub mod ctx;
15pub mod impls;
16
17pub use sys_traits_macros::auto_impl;
18
19pub use self::ctx::FsFileWithPathsInErrors;
20pub use self::ctx::OperationError;
21pub use self::ctx::OperationErrorKind;
22pub use self::ctx::PathsInErrorsExt;
23pub use self::ctx::SysWithPathsInErrors;
24
25use self::boxed::BoxedFsFile;
26use self::boxed::BoxedFsMetadataValue;
27
28pub trait EnvCurrentDir {
33 fn env_current_dir(&self) -> io::Result<PathBuf>;
34}
35
36pub trait BaseEnvSetCurrentDir {
39 #[doc(hidden)]
40 fn base_env_set_current_dir(&self, path: &Path) -> io::Result<()>;
41}
42
43pub trait EnvSetCurrentDir: BaseEnvSetCurrentDir {
44 #[inline]
45 fn env_set_current_dir(&self, path: impl AsRef<Path>) -> io::Result<()> {
46 self.base_env_set_current_dir(path.as_ref())
47 }
48}
49
50impl<T: BaseEnvSetCurrentDir> EnvSetCurrentDir for T {}
51
52pub trait BaseEnvVar {
55 #[doc(hidden)]
56 fn base_env_var_os(&self, key: &OsStr) -> Option<OsString>;
57}
58
59pub trait EnvVar: BaseEnvVar {
60 #[inline]
61 fn env_var_os(&self, key: impl AsRef<OsStr>) -> Option<OsString> {
62 self.base_env_var_os(key.as_ref())
63 }
64
65 fn env_var(&self, key: impl AsRef<OsStr>) -> Result<String, VarError> {
66 match self.env_var_os(key) {
67 Some(val) => val.into_string().map_err(VarError::NotUnicode),
68 None => Err(VarError::NotPresent),
69 }
70 }
71
72 fn env_var_path(&self, key: impl AsRef<OsStr>) -> Option<PathBuf> {
74 self
75 .env_var_os(key)
76 .and_then(|h| if h.is_empty() { None } else { Some(h) })
77 .map(|value| {
78 #[cfg(all(target_arch = "wasm32", feature = "wasm"))]
79 {
80 impls::wasm_string_to_path(value.to_string_lossy().to_string())
81 }
82 #[cfg(any(not(target_arch = "wasm32"), not(feature = "wasm")))]
83 {
84 PathBuf::from(value)
85 }
86 })
87 }
88}
89
90impl<T: BaseEnvVar> EnvVar for T {}
91
92pub trait EnvVars {
95 type EnvVarsOs: Iterator<Item = (OsString, OsString)>;
96
97 fn env_vars_os(&self) -> Self::EnvVarsOs;
98
99 fn env_vars(&self) -> EnvVarsStrings<Self::EnvVarsOs> {
100 EnvVarsStrings(self.env_vars_os())
101 }
102}
103
104pub struct EnvVarsStrings<I>(I);
105
106impl<I: Iterator<Item = (OsString, OsString)>> Iterator for EnvVarsStrings<I> {
107 type Item = (String, String);
108
109 fn next(&mut self) -> Option<Self::Item> {
110 loop {
111 let (k, v) = self.0.next()?;
112 if let (Ok(k), Ok(v)) = (k.into_string(), v.into_string()) {
113 return Some((k, v));
114 }
115 }
116 }
117}
118
119pub trait BaseEnvRemoveVar {
122 #[doc(hidden)]
123 fn base_env_remove_var(&self, key: &OsStr);
124}
125
126pub trait EnvRemoveVar: BaseEnvRemoveVar {
127 fn env_remove_var(&self, key: impl AsRef<OsStr>) {
128 self.base_env_remove_var(key.as_ref())
129 }
130}
131
132impl<T: BaseEnvRemoveVar> EnvRemoveVar for T {}
133
134pub trait BaseEnvSetVar {
137 #[doc(hidden)]
138 fn base_env_set_var(&self, key: &OsStr, value: &OsStr);
139}
140
141pub trait EnvSetVar: BaseEnvSetVar {
142 fn env_set_var(&self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) {
143 self.base_env_set_var(key.as_ref(), value.as_ref())
144 }
145}
146
147impl<T: BaseEnvSetVar> EnvSetVar for T {}
148
149pub trait EnvUmask {
152 fn env_umask(&self) -> io::Result<u32>;
153}
154
155pub trait EnvSetUmask {
158 fn env_set_umask(&self, umask: u32) -> io::Result<u32>;
159}
160
161pub trait EnvCacheDir {
164 fn env_cache_dir(&self) -> Option<PathBuf>;
165}
166
167pub trait EnvHomeDir {
170 fn env_home_dir(&self) -> Option<PathBuf>;
171}
172
173pub trait EnvProgramsDir {
176 fn env_programs_dir(&self) -> Option<PathBuf>;
177}
178
179pub trait EnvTempDir {
182 fn env_temp_dir(&self) -> io::Result<PathBuf>;
183}
184
185#[cfg(windows)]
188type CustomFlagsValue = u32;
189#[cfg(not(windows))]
190type CustomFlagsValue = i32;
191
192#[derive(Default, Debug, Clone)]
193#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
194#[cfg_attr(feature = "serde", serde(default, rename_all = "camelCase"))]
195#[non_exhaustive] pub struct OpenOptions {
197 pub read: bool,
198 pub write: bool,
199 pub create: bool,
200 pub truncate: bool,
201 pub append: bool,
202 pub create_new: bool,
203 pub mode: Option<u32>,
205 pub custom_flags: Option<CustomFlagsValue>,
211 pub access_mode: Option<u32>,
213 pub share_mode: Option<u32>,
215 pub attributes: Option<u32>,
217 pub security_qos_flags: Option<u32>,
219}
220
221impl OpenOptions {
222 pub fn new() -> Self {
223 Self::default()
224 }
225
226 pub fn new_read() -> Self {
227 Self {
228 read: true,
229 write: false,
230 create: false,
231 truncate: false,
232 append: false,
233 create_new: false,
234 ..Default::default()
235 }
236 }
237
238 #[deprecated(note = "use `new_write` instead")]
240 pub fn write() -> Self {
241 Self::new_write()
242 }
243
244 pub fn new_write() -> Self {
245 Self {
246 read: false,
247 write: true,
248 create: true,
249 truncate: true,
250 append: false,
251 create_new: false,
252 ..Default::default()
253 }
254 }
255
256 pub fn new_append() -> Self {
257 Self {
258 read: false,
259 write: true,
260 create: false,
261 truncate: false,
262 append: true,
263 create_new: false,
264 ..Default::default()
265 }
266 }
267
268 #[inline]
269 pub fn read(&mut self) -> &mut Self {
270 self.read = true;
271 self
272 }
273
274 #[inline]
275 pub fn create(&mut self) -> &mut Self {
276 self.create = true;
277 self
278 }
279
280 #[inline]
281 pub fn truncate(&mut self) -> &mut Self {
282 self.truncate = true;
283 self
284 }
285
286 #[inline]
287 pub fn append(&mut self) -> &mut Self {
288 self.append = true;
289 self
290 }
291
292 #[inline]
293 pub fn create_new(&mut self) -> &mut Self {
294 self.create_new = true;
295 self
296 }
297
298 #[inline]
299 pub fn mode(&mut self, mode: u32) -> &mut Self {
300 self.mode = Some(mode);
301 self
302 }
303
304 #[inline]
305 pub fn custom_flags(&mut self, flags: CustomFlagsValue) -> &mut Self {
306 self.custom_flags = Some(flags);
307 self
308 }
309
310 #[inline]
311 pub fn access_mode(&mut self, value: u32) -> &mut Self {
312 self.access_mode = Some(value);
313 self
314 }
315
316 #[inline]
317 pub fn share_mode(&mut self, value: u32) -> &mut Self {
318 self.share_mode = Some(value);
319 self
320 }
321
322 #[inline]
323 pub fn attributes(&mut self, value: u32) -> &mut Self {
324 self.attributes = Some(value);
325 self
326 }
327
328 #[inline]
329 pub fn security_qos_flags(&mut self, value: u32) -> &mut Self {
330 self.security_qos_flags = Some(value);
331 self
332 }
333}
334
335pub trait BaseFsCanonicalize {
338 #[doc(hidden)]
339 fn base_fs_canonicalize(&self, path: &Path) -> io::Result<PathBuf>;
340}
341
342pub trait FsCanonicalize: BaseFsCanonicalize {
343 #[inline]
344 fn fs_canonicalize(&self, path: impl AsRef<Path>) -> io::Result<PathBuf> {
345 self.base_fs_canonicalize(path.as_ref())
346 }
347}
348
349impl<T: BaseFsCanonicalize> FsCanonicalize for T {}
350
351pub trait BaseFsChown {
354 #[doc(hidden)]
355 fn base_fs_chown(
356 &self,
357 path: &Path,
358 uid: Option<u32>,
359 gid: Option<u32>,
360 ) -> io::Result<()>;
361}
362
363pub trait FsChown: BaseFsChown {
364 #[inline]
365 fn fs_chown(
366 &self,
367 path: impl AsRef<Path>,
368 uid: Option<u32>,
369 gid: Option<u32>,
370 ) -> io::Result<()> {
371 self.base_fs_chown(path.as_ref(), uid, gid)
372 }
373}
374
375impl<T: BaseFsChown> FsChown for T {}
376
377pub trait BaseFsSymlinkChown {
380 #[doc(hidden)]
381 fn base_fs_symlink_chown(
382 &self,
383 path: &Path,
384 uid: Option<u32>,
385 gid: Option<u32>,
386 ) -> io::Result<()>;
387}
388
389pub trait FsSymlinkChown: BaseFsSymlinkChown {
390 #[inline]
391 fn fs_symlink_chown(
392 &self,
393 path: impl AsRef<Path>,
394 uid: Option<u32>,
395 gid: Option<u32>,
396 ) -> io::Result<()> {
397 self.base_fs_symlink_chown(path.as_ref(), uid, gid)
398 }
399}
400
401impl<T: BaseFsSymlinkChown> FsSymlinkChown for T {}
402
403pub trait BaseFsCloneFile {
406 #[doc(hidden)]
407 fn base_fs_clone_file(&self, from: &Path, to: &Path) -> io::Result<()>;
408}
409
410pub trait FsCloneFile: BaseFsCloneFile {
411 #[inline]
412 fn fs_clone_file(
413 &self,
414 from: impl AsRef<Path>,
415 to: impl AsRef<Path>,
416 ) -> io::Result<()> {
417 self.base_fs_clone_file(from.as_ref(), to.as_ref())
418 }
419}
420
421impl<T: BaseFsCloneFile> FsCloneFile for T {}
422
423pub trait BaseFsCopy {
426 #[doc(hidden)]
427 fn base_fs_copy(&self, from: &Path, to: &Path) -> io::Result<u64>;
428}
429
430pub trait FsCopy: BaseFsCopy {
431 #[inline]
432 fn fs_copy(
433 &self,
434 from: impl AsRef<Path>,
435 to: impl AsRef<Path>,
436 ) -> io::Result<u64> {
437 self.base_fs_copy(from.as_ref(), to.as_ref())
438 }
439}
440
441impl<T: BaseFsCopy> FsCopy for T {}
442
443#[derive(Default, Debug, Clone, Copy)]
446#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
447#[cfg_attr(feature = "serde", serde(default, rename_all = "camelCase"))]
448#[non_exhaustive] pub struct CreateDirOptions {
450 pub recursive: bool,
451 pub mode: Option<u32>,
453}
454
455impl CreateDirOptions {
456 pub fn new() -> Self {
457 Self::default()
458 }
459
460 pub fn new_recursive() -> Self {
461 Self {
462 recursive: true,
463 ..Default::default()
464 }
465 }
466
467 #[inline]
468 pub fn recursive(&mut self) -> &mut Self {
469 self.recursive = true;
470 self
471 }
472
473 #[inline]
474 pub fn mode(&mut self, mode: u32) -> &mut Self {
475 self.mode = Some(mode);
476 self
477 }
478}
479
480pub trait BaseFsCreateDir {
481 #[doc(hidden)]
482 fn base_fs_create_dir(
483 &self,
484 path: &Path,
485 options: &CreateDirOptions,
486 ) -> io::Result<()>;
487}
488
489pub trait FsCreateDir: BaseFsCreateDir {
490 fn fs_create_dir(
491 &self,
492 path: impl AsRef<Path>,
493 options: &CreateDirOptions,
494 ) -> io::Result<()> {
495 self.base_fs_create_dir(path.as_ref(), options)
496 }
497}
498
499impl<T: BaseFsCreateDir> FsCreateDir for T {}
500
501pub trait FsCreateDirAll: BaseFsCreateDir {
504 fn fs_create_dir_all(&self, path: impl AsRef<Path>) -> io::Result<()> {
505 self.base_fs_create_dir(
506 path.as_ref(),
507 &CreateDirOptions {
508 recursive: true,
509 mode: None,
510 },
511 )
512 }
513}
514
515impl<T: BaseFsCreateDir> FsCreateDirAll for T {}
516
517pub trait BaseFsHardLink {
520 #[doc(hidden)]
521 fn base_fs_hard_link(&self, src: &Path, dst: &Path) -> io::Result<()>;
522}
523
524pub trait FsHardLink: BaseFsHardLink {
525 fn fs_hard_link(
526 &self,
527 src: impl AsRef<Path>,
528 dst: impl AsRef<Path>,
529 ) -> io::Result<()> {
530 self.base_fs_hard_link(src.as_ref(), dst.as_ref())
531 }
532}
533
534impl<T: BaseFsHardLink> FsHardLink for T {}
535
536pub trait BaseFsCreateJunction {
539 #[doc(hidden)]
540 fn base_fs_create_junction(
541 &self,
542 original: &Path,
543 junction: &Path,
544 ) -> io::Result<()>;
545}
546
547pub trait FsCreateJunction: BaseFsCreateJunction {
548 fn fs_create_junction(
550 &self,
551 original: impl AsRef<Path>,
552 junction: impl AsRef<Path>,
553 ) -> io::Result<()> {
554 self.base_fs_create_junction(original.as_ref(), junction.as_ref())
555 }
556}
557
558impl<T: BaseFsCreateJunction> FsCreateJunction for T {}
559
560#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
563pub enum FileType {
564 File,
565 Dir,
566 Symlink,
567 Unknown,
568}
569
570impl FileType {
571 pub fn is_dir(&self) -> bool {
572 *self == Self::Dir
573 }
574
575 pub fn is_file(&self) -> bool {
576 *self == Self::File
577 }
578
579 pub fn is_symlink(&self) -> bool {
580 *self == Self::Symlink
581 }
582}
583
584impl From<std::fs::FileType> for FileType {
585 fn from(file_type: std::fs::FileType) -> Self {
586 if file_type.is_file() {
587 FileType::File
588 } else if file_type.is_dir() {
589 FileType::Dir
590 } else if file_type.is_symlink() {
591 FileType::Symlink
592 } else {
593 FileType::Unknown
594 }
595 }
596}
597
598#[allow(clippy::len_without_is_empty)]
599pub trait FsMetadataValue: std::fmt::Debug {
600 fn file_type(&self) -> FileType;
601 fn len(&self) -> u64;
602 fn accessed(&self) -> io::Result<SystemTime>;
603 fn created(&self) -> io::Result<SystemTime>;
604 fn changed(&self) -> io::Result<SystemTime>;
605 fn modified(&self) -> io::Result<SystemTime>;
606 fn dev(&self) -> io::Result<u64>;
607 fn ino(&self) -> io::Result<u64>;
608 fn mode(&self) -> io::Result<u32>;
609 fn nlink(&self) -> io::Result<u64>;
610 fn uid(&self) -> io::Result<u32>;
611 fn gid(&self) -> io::Result<u32>;
612 fn rdev(&self) -> io::Result<u64>;
613 fn blksize(&self) -> io::Result<u64>;
614 fn blocks(&self) -> io::Result<u64>;
615 fn is_block_device(&self) -> io::Result<bool>;
616 fn is_char_device(&self) -> io::Result<bool>;
617 fn is_fifo(&self) -> io::Result<bool>;
618 fn is_socket(&self) -> io::Result<bool>;
619 fn file_attributes(&self) -> io::Result<u32>;
620}
621
622pub trait BaseFsMetadata {
623 type Metadata: FsMetadataValue;
624
625 #[doc(hidden)]
626 fn base_fs_metadata(&self, path: &Path) -> io::Result<Self::Metadata>;
627
628 #[doc(hidden)]
629 fn base_fs_symlink_metadata(&self, path: &Path)
630 -> io::Result<Self::Metadata>;
631
632 #[doc(hidden)]
633 fn base_fs_exists(&self, path: &Path) -> io::Result<bool> {
634 match self.base_fs_symlink_metadata(path) {
635 Ok(_) => Ok(true),
636 Err(err) => {
637 if err.kind() == ErrorKind::NotFound {
638 Ok(false)
639 } else {
640 Err(err)
641 }
642 }
643 }
644 }
645
646 #[doc(hidden)]
647 fn base_fs_exists_no_err(&self, path: &Path) -> bool {
648 self.base_fs_exists(path).unwrap_or(false)
649 }
650}
651
652pub trait FsMetadata: BaseFsMetadata {
655 #[inline]
656 fn fs_metadata(&self, path: impl AsRef<Path>) -> io::Result<Self::Metadata> {
657 self.base_fs_metadata(path.as_ref())
658 }
659
660 #[inline]
661 fn fs_symlink_metadata(
662 &self,
663 path: impl AsRef<Path>,
664 ) -> io::Result<Self::Metadata> {
665 self.base_fs_symlink_metadata(path.as_ref())
666 }
667
668 #[inline]
669 fn fs_is_file(&self, path: impl AsRef<Path>) -> io::Result<bool> {
670 Ok(self.fs_metadata(path)?.file_type() == FileType::File)
671 }
672
673 #[inline]
674 fn fs_is_file_no_err(&self, path: impl AsRef<Path>) -> bool {
675 self.fs_is_file(path).unwrap_or(false)
676 }
677
678 #[inline]
679 fn fs_is_dir(&self, path: impl AsRef<Path>) -> io::Result<bool> {
680 Ok(self.fs_metadata(path)?.file_type() == FileType::Dir)
681 }
682
683 #[inline]
684 fn fs_is_dir_no_err(&self, path: impl AsRef<Path>) -> bool {
685 self.fs_is_dir(path).unwrap_or(false)
686 }
687
688 #[inline]
689 fn fs_exists(&self, path: impl AsRef<Path>) -> io::Result<bool> {
690 self.base_fs_exists(path.as_ref())
691 }
692
693 #[inline]
694 fn fs_exists_no_err(&self, path: impl AsRef<Path>) -> bool {
695 self.base_fs_exists_no_err(path.as_ref())
696 }
697
698 #[inline]
699 fn fs_is_symlink(&self, path: impl AsRef<Path>) -> io::Result<bool> {
700 Ok(self.fs_symlink_metadata(path)?.file_type() == FileType::Symlink)
701 }
702
703 #[inline]
704 fn fs_is_symlink_no_err(&self, path: impl AsRef<Path>) -> bool {
705 self.fs_is_symlink(path).unwrap_or(false)
706 }
707}
708
709impl<T: BaseFsMetadata> FsMetadata for T {}
710
711pub trait FsFile:
714 std::io::Read
715 + std::io::Write
716 + std::io::Seek
717 + FsFileIsTerminal
718 + FsFileLock
719 + FsFileMetadata
720 + FsFileSetPermissions
721 + FsFileSetTimes
722 + FsFileSetLen
723 + FsFileSyncAll
724 + FsFileSyncData
725 + FsFileAsRaw
726{
727}
728
729pub trait BoxableFsFile: Sized {
730 fn into_boxed(self) -> BoxedFsFile;
731}
732
733impl<T> BoxableFsFile for T
734where
735 T: FsFile + Sized + 'static,
736{
737 fn into_boxed(self) -> BoxedFsFile {
738 BoxedFsFile(Box::new(self))
739 }
740}
741
742pub trait BaseFsOpen {
743 type File: FsFile + Sized + 'static;
746
747 #[doc(hidden)]
748 fn base_fs_open(
749 &self,
750 path: &Path,
751 options: &OpenOptions,
752 ) -> io::Result<Self::File>;
753}
754
755pub trait FsOpen: BaseFsOpen {
756 #[inline]
757 fn fs_open(
758 &self,
759 path: impl AsRef<Path>,
760 options: &OpenOptions,
761 ) -> io::Result<Self::File> {
762 self.base_fs_open(path.as_ref(), options)
763 }
764}
765
766impl<T: BaseFsOpen> FsOpen for T {}
767
768pub trait BaseFsRead {
771 #[doc(hidden)]
772 fn base_fs_read(&self, path: &Path) -> io::Result<Cow<'static, [u8]>>;
773}
774
775pub trait FsRead: BaseFsRead {
776 #[inline]
777 fn fs_read(&self, path: impl AsRef<Path>) -> io::Result<Cow<'static, [u8]>> {
778 self.base_fs_read(path.as_ref())
779 }
780
781 fn fs_read_to_string(
782 &self,
783 path: impl AsRef<Path>,
784 ) -> io::Result<Cow<'static, str>> {
785 let bytes = self.fs_read(path)?;
786 match bytes {
787 Cow::Borrowed(bytes) => str::from_utf8(bytes)
788 .map(Cow::Borrowed)
789 .map_err(|e| e.to_string()),
790 Cow::Owned(bytes) => String::from_utf8(bytes)
791 .map(Cow::Owned)
792 .map_err(|e| e.to_string()),
793 }
794 .map_err(|error_text| Error::new(ErrorKind::InvalidData, error_text))
795 }
796
797 fn fs_read_to_string_lossy(
798 &self,
799 path: impl AsRef<Path>,
800 ) -> io::Result<Cow<'static, str>> {
801 #[inline(always)]
803 fn string_from_utf8_lossy(buf: Vec<u8>) -> String {
804 match String::from_utf8_lossy(&buf) {
805 Cow::Owned(s) => s,
807 Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(buf) },
810 }
811 }
812
813 let bytes = self.fs_read(path)?;
814 match bytes {
815 Cow::Borrowed(bytes) => Ok(String::from_utf8_lossy(bytes)),
816 Cow::Owned(bytes) => Ok(Cow::Owned(string_from_utf8_lossy(bytes))),
817 }
818 }
819}
820
821impl<T: BaseFsRead> FsRead for T {}
822
823pub trait FsDirEntry: std::fmt::Debug {
826 type Metadata: FsMetadataValue;
827
828 fn file_name(&self) -> Cow<'_, OsStr>;
829 fn file_type(&self) -> io::Result<FileType>;
830 fn metadata(&self) -> io::Result<Self::Metadata>;
831 fn path(&self) -> Cow<'_, Path>;
832}
833
834pub trait BaseFsReadDir {
835 type ReadDirEntry: FsDirEntry + 'static;
836
837 #[doc(hidden)]
838 fn base_fs_read_dir(
839 &self,
840 path: &Path,
841 ) -> io::Result<Box<dyn Iterator<Item = io::Result<Self::ReadDirEntry>>>>;
842}
843
844pub trait FsReadDir: BaseFsReadDir {
845 #[inline]
846 fn fs_read_dir(
847 &self,
848 path: impl AsRef<Path>,
849 ) -> io::Result<Box<dyn Iterator<Item = io::Result<Self::ReadDirEntry>>>> {
850 self.base_fs_read_dir(path.as_ref())
851 }
852}
853
854impl<T: BaseFsReadDir> FsReadDir for T {}
855
856pub trait BaseFsReadLink {
859 #[doc(hidden)]
860 fn base_fs_read_link(&self, path: &Path) -> io::Result<PathBuf>;
861}
862
863pub trait FsReadLink: BaseFsReadLink {
864 #[inline]
865 fn fs_read_link(&self, path: impl AsRef<Path>) -> io::Result<PathBuf> {
866 self.base_fs_read_link(path.as_ref())
867 }
868}
869
870impl<T: BaseFsReadLink> FsReadLink for T {}
871
872pub trait BaseFsRemoveDir {
875 #[doc(hidden)]
876 fn base_fs_remove_dir(&self, path: &Path) -> io::Result<()>;
877}
878
879pub trait FsRemoveDir: BaseFsRemoveDir {
880 #[inline]
881 fn fs_remove_dir(&self, path: impl AsRef<Path>) -> io::Result<()> {
882 self.base_fs_remove_dir(path.as_ref())
883 }
884}
885
886impl<T: BaseFsRemoveDir> FsRemoveDir for T {}
887
888pub trait BaseFsRemoveDirAll {
891 #[doc(hidden)]
892 fn base_fs_remove_dir_all(&self, path: &Path) -> io::Result<()>;
893}
894
895pub trait FsRemoveDirAll: BaseFsRemoveDirAll {
896 #[inline]
897 fn fs_remove_dir_all(&self, path: impl AsRef<Path>) -> io::Result<()> {
898 self.base_fs_remove_dir_all(path.as_ref())
899 }
900}
901
902impl<T: BaseFsRemoveDirAll> FsRemoveDirAll for T {}
903
904pub trait BaseFsRemoveFile {
907 #[doc(hidden)]
908 fn base_fs_remove_file(&self, path: &Path) -> io::Result<()>;
909}
910
911pub trait FsRemoveFile: BaseFsRemoveFile {
912 #[inline]
913 fn fs_remove_file(&self, path: impl AsRef<Path>) -> io::Result<()> {
914 self.base_fs_remove_file(path.as_ref())
915 }
916}
917
918impl<T: BaseFsRemoveFile> FsRemoveFile for T {}
919
920pub trait BaseFsRename {
923 #[doc(hidden)]
924 fn base_fs_rename(&self, from: &Path, to: &Path) -> io::Result<()>;
925}
926
927pub trait FsRename: BaseFsRename {
928 #[inline]
929 fn fs_rename(
930 &self,
931 from: impl AsRef<Path>,
932 to: impl AsRef<Path>,
933 ) -> io::Result<()> {
934 self.base_fs_rename(from.as_ref(), to.as_ref())
935 }
936}
937
938impl<T: BaseFsRename> FsRename for T {}
939
940pub trait BaseFsSetFileTimes {
943 #[doc(hidden)]
944 fn base_fs_set_file_times(
945 &self,
946 path: &Path,
947 atime: SystemTime,
948 mtime: SystemTime,
949 ) -> io::Result<()>;
950}
951
952pub trait FsSetFileTimes: BaseFsSetFileTimes {
953 #[inline]
954 fn fs_set_file_times(
955 &self,
956 path: impl AsRef<Path>,
957 atime: SystemTime,
958 mtime: SystemTime,
959 ) -> io::Result<()> {
960 self.base_fs_set_file_times(path.as_ref(), atime, mtime)
961 }
962}
963
964impl<T: BaseFsSetFileTimes> FsSetFileTimes for T {}
965
966pub trait BaseFsSetSymlinkFileTimes {
969 #[doc(hidden)]
970 fn base_fs_set_symlink_file_times(
971 &self,
972 path: &Path,
973 atime: SystemTime,
974 mtime: SystemTime,
975 ) -> io::Result<()>;
976}
977
978pub trait FsSetSymlinkFileTimes: BaseFsSetSymlinkFileTimes {
979 #[inline]
980 fn fs_set_symlink_file_times(
981 &self,
982 path: impl AsRef<Path>,
983 atime: SystemTime,
984 mtime: SystemTime,
985 ) -> io::Result<()> {
986 self.base_fs_set_symlink_file_times(path.as_ref(), atime, mtime)
987 }
988}
989
990impl<T: BaseFsSetSymlinkFileTimes> FsSetSymlinkFileTimes for T {}
991
992pub trait BaseFsSetPermissions {
995 #[doc(hidden)]
996 fn base_fs_set_permissions(&self, path: &Path, mode: u32) -> io::Result<()>;
997}
998
999pub trait FsSetPermissions: BaseFsSetPermissions {
1000 fn fs_set_permissions(
1001 &self,
1002 path: impl AsRef<Path>,
1003 mode: u32,
1004 ) -> io::Result<()> {
1005 self.base_fs_set_permissions(path.as_ref(), mode)
1006 }
1007}
1008
1009impl<T: BaseFsSetPermissions> FsSetPermissions for T {}
1010
1011pub trait BaseFsSymlinkDir {
1014 #[doc(hidden)]
1015 fn base_fs_symlink_dir(&self, original: &Path, link: &Path)
1016 -> io::Result<()>;
1017}
1018
1019pub trait FsSymlinkDir: BaseFsSymlinkDir {
1020 #[inline]
1021 fn fs_symlink_dir(
1022 &self,
1023 original: impl AsRef<Path>,
1024 link: impl AsRef<Path>,
1025 ) -> io::Result<()> {
1026 self.base_fs_symlink_dir(original.as_ref(), link.as_ref())
1027 }
1028}
1029
1030impl<T: BaseFsSymlinkDir> FsSymlinkDir for T {}
1031
1032pub trait BaseFsSymlinkFile {
1035 #[doc(hidden)]
1036 fn base_fs_symlink_file(
1037 &self,
1038 original: &Path,
1039 link: &Path,
1040 ) -> io::Result<()>;
1041}
1042
1043pub trait FsSymlinkFile: BaseFsSymlinkFile {
1044 #[inline]
1045 fn fs_symlink_file(
1046 &self,
1047 original: impl AsRef<Path>,
1048 link: impl AsRef<Path>,
1049 ) -> io::Result<()> {
1050 self.base_fs_symlink_file(original.as_ref(), link.as_ref())
1051 }
1052}
1053
1054impl<T: BaseFsSymlinkFile> FsSymlinkFile for T {}
1055
1056pub trait BaseFsWrite {
1059 #[doc(hidden)]
1060 fn base_fs_write(&self, path: &Path, data: &[u8]) -> io::Result<()>;
1061}
1062
1063pub trait FsWrite: BaseFsWrite {
1064 #[inline]
1065 fn fs_write(
1066 &self,
1067 path: impl AsRef<Path>,
1068 data: impl AsRef<[u8]>,
1069 ) -> io::Result<()> {
1070 self.base_fs_write(path.as_ref(), data.as_ref())
1071 }
1072}
1073
1074impl<T: BaseFsWrite> FsWrite for T {}
1075
1076pub trait FsFileAsRaw {
1079 #[cfg(windows)]
1082 fn fs_file_as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle>;
1083
1084 #[cfg(unix)]
1087 fn fs_file_as_raw_fd(&self) -> Option<std::os::fd::RawFd>;
1088}
1089
1090pub trait FsFileIsTerminal {
1091 fn fs_file_is_terminal(&self) -> bool;
1092}
1093
1094pub enum FsFileLockMode {
1095 Shared,
1096 Exclusive,
1097}
1098
1099pub trait FsFileLock {
1100 fn fs_file_lock(&mut self, mode: FsFileLockMode) -> io::Result<()>;
1101 fn fs_file_try_lock(&mut self, mode: FsFileLockMode) -> io::Result<()>;
1102 fn fs_file_unlock(&mut self) -> io::Result<()>;
1103}
1104
1105pub trait FsFileMetadata {
1106 fn fs_file_metadata(&self) -> io::Result<BoxedFsMetadataValue>;
1111}
1112
1113pub trait FsFileSetLen {
1114 fn fs_file_set_len(&mut self, size: u64) -> io::Result<()>;
1115}
1116
1117pub trait FsFileSetPermissions {
1118 fn fs_file_set_permissions(&mut self, mode: u32) -> io::Result<()>;
1119}
1120
1121#[derive(Debug, Clone, Default)]
1122pub struct FsFileTimes {
1123 pub accessed: Option<SystemTime>,
1124 pub modified: Option<SystemTime>,
1125}
1126
1127impl FsFileTimes {
1128 pub fn new() -> Self {
1129 Self::default()
1130 }
1131
1132 pub fn accessed(&mut self, accessed: SystemTime) -> &mut Self {
1133 self.accessed = Some(accessed);
1134 self
1135 }
1136
1137 pub fn modified(&mut self, accessed: SystemTime) -> &mut Self {
1138 self.modified = Some(accessed);
1139 self
1140 }
1141}
1142
1143pub trait FsFileSetTimes {
1144 fn fs_file_set_times(&mut self, times: FsFileTimes) -> io::Result<()>;
1145}
1146
1147pub trait FsFileSyncAll {
1148 fn fs_file_sync_all(&mut self) -> io::Result<()>;
1149}
1150
1151pub trait FsFileSyncData {
1152 fn fs_file_sync_data(&mut self) -> io::Result<()>;
1153}
1154
1155pub trait SystemTimeNow {
1158 fn sys_time_now(&self) -> std::time::SystemTime;
1159}
1160
1161pub trait SystemRandom {
1162 fn sys_random(&self, buf: &mut [u8]) -> io::Result<()>;
1163
1164 fn sys_random_u8(&self) -> io::Result<u8> {
1165 let mut buf = [0; 1];
1166 self.sys_random(&mut buf)?;
1167 Ok(buf[0])
1168 }
1169
1170 fn sys_random_u32(&self) -> io::Result<u32> {
1171 let mut buf = [0; 4];
1172 self.sys_random(&mut buf)?;
1173 Ok(u32::from_le_bytes(buf))
1174 }
1175
1176 fn sys_random_u64(&self) -> io::Result<u64> {
1177 let mut buf = [0; 8];
1178 self.sys_random(&mut buf)?;
1179 Ok(u64::from_le_bytes(buf))
1180 }
1181}
1182
1183pub trait ProcessExit {
1184 fn process_exit(&self, code: i32) -> !;
1185}
1186
1187pub trait ThreadSleep {
1188 fn thread_sleep(&self, duration: std::time::Duration);
1189}