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 impls;
15
16pub trait EnvCurrentDir {
21 fn env_current_dir(&self) -> io::Result<PathBuf>;
22}
23
24pub trait BaseEnvSetCurrentDir {
27 #[doc(hidden)]
28 fn base_env_set_current_dir(&self, path: &Path) -> io::Result<()>;
29}
30
31pub trait EnvSetCurrentDir: BaseEnvSetCurrentDir {
32 #[inline]
33 fn env_set_current_dir(&self, path: impl AsRef<Path>) -> io::Result<()> {
34 self.base_env_set_current_dir(path.as_ref())
35 }
36}
37
38impl<T: BaseEnvSetCurrentDir> EnvSetCurrentDir for T {}
39
40pub trait BaseEnvVar {
43 #[doc(hidden)]
44 fn base_env_var_os(&self, key: &OsStr) -> Option<OsString>;
45}
46
47pub trait EnvVar: BaseEnvVar {
48 #[inline]
49 fn env_var_os(&self, key: impl AsRef<OsStr>) -> Option<OsString> {
50 self.base_env_var_os(key.as_ref())
51 }
52
53 fn env_var(&self, key: impl AsRef<OsStr>) -> Result<String, VarError> {
54 match self.env_var_os(key) {
55 Some(val) => val.into_string().map_err(VarError::NotUnicode),
56 None => Err(VarError::NotPresent),
57 }
58 }
59
60 fn env_var_path(&self, key: impl AsRef<OsStr>) -> Option<PathBuf> {
62 self
63 .env_var_os(key)
64 .and_then(|h| if h.is_empty() { None } else { Some(h) })
65 .map(|value| {
66 #[cfg(all(target_arch = "wasm32", feature = "wasm"))]
67 {
68 impls::wasm_string_to_path(value.to_string_lossy().to_string())
69 }
70 #[cfg(any(not(target_arch = "wasm32"), not(feature = "wasm")))]
71 {
72 PathBuf::from(value)
73 }
74 })
75 }
76}
77
78impl<T: BaseEnvVar> EnvVar for T {}
79
80pub trait BaseEnvSetVar {
83 #[doc(hidden)]
84 fn base_env_set_var(&self, key: &OsStr, value: &OsStr);
85}
86
87pub trait EnvSetVar: BaseEnvSetVar {
88 fn env_set_var(&self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) {
89 self.base_env_set_var(key.as_ref(), value.as_ref())
90 }
91}
92
93impl<T: BaseEnvSetVar> EnvSetVar for T {}
94
95pub trait EnvUmask {
98 fn env_umask(&self) -> io::Result<u32>;
99}
100
101pub trait EnvSetUmask {
104 fn env_set_umask(&self, umask: u32) -> io::Result<u32>;
105}
106
107pub trait EnvCacheDir {
110 fn env_cache_dir(&self) -> Option<PathBuf>;
111}
112
113pub trait EnvHomeDir {
116 fn env_home_dir(&self) -> Option<PathBuf>;
117}
118
119pub trait EnvTempDir {
122 fn env_temp_dir(&self) -> io::Result<PathBuf>;
123}
124
125#[cfg(windows)]
128type CustomFlagsValue = u32;
129#[cfg(not(windows))]
130type CustomFlagsValue = i32;
131
132#[derive(Default, Debug, Clone)]
133#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
134#[cfg_attr(feature = "serde", serde(default, rename_all = "camelCase"))]
135#[non_exhaustive] pub struct OpenOptions {
137 pub read: bool,
138 pub write: bool,
139 pub create: bool,
140 pub truncate: bool,
141 pub append: bool,
142 pub create_new: bool,
143 pub mode: Option<u32>,
145 pub custom_flags: Option<CustomFlagsValue>,
151 pub access_mode: Option<u32>,
153 pub share_mode: Option<u32>,
155 pub attributes: Option<u32>,
157 pub security_qos_flags: Option<u32>,
159}
160
161impl OpenOptions {
162 pub fn new() -> Self {
163 Self::default()
164 }
165
166 pub fn new_read() -> Self {
167 Self {
168 read: true,
169 write: false,
170 create: false,
171 truncate: false,
172 append: false,
173 create_new: false,
174 ..Default::default()
175 }
176 }
177
178 #[deprecated(note = "use `new_write` instead")]
180 pub fn write() -> Self {
181 Self::new_write()
182 }
183
184 pub fn new_write() -> Self {
185 Self {
186 read: false,
187 write: true,
188 create: true,
189 truncate: true,
190 append: false,
191 create_new: false,
192 ..Default::default()
193 }
194 }
195
196 pub fn new_append() -> Self {
197 Self {
198 read: false,
199 write: true,
200 create: false,
201 truncate: false,
202 append: true,
203 create_new: false,
204 ..Default::default()
205 }
206 }
207
208 #[inline]
209 pub fn read(&mut self) -> &mut Self {
210 self.read = true;
211 self
212 }
213
214 #[inline]
215 pub fn create(&mut self) -> &mut Self {
216 self.create = true;
217 self
218 }
219
220 #[inline]
221 pub fn truncate(&mut self) -> &mut Self {
222 self.truncate = true;
223 self
224 }
225
226 #[inline]
227 pub fn append(&mut self) -> &mut Self {
228 self.append = true;
229 self
230 }
231
232 #[inline]
233 pub fn create_new(&mut self) -> &mut Self {
234 self.create_new = true;
235 self
236 }
237
238 #[inline]
239 pub fn mode(&mut self, mode: u32) -> &mut Self {
240 self.mode = Some(mode);
241 self
242 }
243
244 #[inline]
245 pub fn custom_flags(&mut self, flags: CustomFlagsValue) -> &mut Self {
246 self.custom_flags = Some(flags);
247 self
248 }
249
250 #[inline]
251 pub fn access_mode(&mut self, value: u32) -> &mut Self {
252 self.access_mode = Some(value);
253 self
254 }
255
256 #[inline]
257 pub fn share_mode(&mut self, value: u32) -> &mut Self {
258 self.share_mode = Some(value);
259 self
260 }
261
262 #[inline]
263 pub fn attributes(&mut self, value: u32) -> &mut Self {
264 self.attributes = Some(value);
265 self
266 }
267
268 #[inline]
269 pub fn security_qos_flags(&mut self, value: u32) -> &mut Self {
270 self.security_qos_flags = Some(value);
271 self
272 }
273}
274
275pub trait BaseFsCanonicalize {
278 #[doc(hidden)]
279 fn base_fs_canonicalize(&self, path: &Path) -> io::Result<PathBuf>;
280}
281
282pub trait FsCanonicalize: BaseFsCanonicalize {
283 #[inline]
284 fn fs_canonicalize(&self, path: impl AsRef<Path>) -> io::Result<PathBuf> {
285 self.base_fs_canonicalize(path.as_ref())
286 }
287}
288
289impl<T: BaseFsCanonicalize> FsCanonicalize for T {}
290
291pub trait BaseFsChown {
294 #[doc(hidden)]
295 fn base_fs_chown(
296 &self,
297 path: &Path,
298 uid: Option<u32>,
299 gid: Option<u32>,
300 ) -> io::Result<()>;
301}
302
303pub trait FsChown: BaseFsChown {
304 #[inline]
305 fn fs_chown(
306 &self,
307 path: impl AsRef<Path>,
308 uid: Option<u32>,
309 gid: Option<u32>,
310 ) -> io::Result<()> {
311 self.base_fs_chown(path.as_ref(), uid, gid)
312 }
313}
314
315impl<T: BaseFsChown> FsChown for T {}
316
317pub trait BaseFsSymlinkChown {
320 #[doc(hidden)]
321 fn base_fs_symlink_chown(
322 &self,
323 path: &Path,
324 uid: Option<u32>,
325 gid: Option<u32>,
326 ) -> io::Result<()>;
327}
328
329pub trait FsSymlinkChown: BaseFsSymlinkChown {
330 #[inline]
331 fn fs_symlink_chown(
332 &self,
333 path: impl AsRef<Path>,
334 uid: Option<u32>,
335 gid: Option<u32>,
336 ) -> io::Result<()> {
337 self.base_fs_symlink_chown(path.as_ref(), uid, gid)
338 }
339}
340
341impl<T: BaseFsSymlinkChown> FsSymlinkChown for T {}
342
343pub trait BaseFsCloneFile {
346 #[doc(hidden)]
347 fn base_fs_clone_file(&self, from: &Path, to: &Path) -> io::Result<()>;
348}
349
350pub trait FsCloneFile: BaseFsCloneFile {
351 #[inline]
352 fn fs_clone_file(
353 &self,
354 from: impl AsRef<Path>,
355 to: impl AsRef<Path>,
356 ) -> io::Result<()> {
357 self.base_fs_clone_file(from.as_ref(), to.as_ref())
358 }
359}
360
361impl<T: BaseFsCloneFile> FsCloneFile for T {}
362
363pub trait BaseFsCopy {
366 #[doc(hidden)]
367 fn base_fs_copy(&self, from: &Path, to: &Path) -> io::Result<u64>;
368}
369
370pub trait FsCopy: BaseFsCopy {
371 #[inline]
372 fn fs_copy(
373 &self,
374 from: impl AsRef<Path>,
375 to: impl AsRef<Path>,
376 ) -> io::Result<u64> {
377 self.base_fs_copy(from.as_ref(), to.as_ref())
378 }
379}
380
381impl<T: BaseFsCopy> FsCopy for T {}
382
383#[derive(Default, Debug, Clone, Copy)]
386#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
387#[cfg_attr(feature = "serde", serde(default, rename_all = "camelCase"))]
388#[non_exhaustive] pub struct CreateDirOptions {
390 pub recursive: bool,
391 pub mode: Option<u32>,
393}
394
395impl CreateDirOptions {
396 pub fn new() -> Self {
397 Self::default()
398 }
399
400 pub fn new_recursive() -> Self {
401 Self {
402 recursive: true,
403 ..Default::default()
404 }
405 }
406
407 #[inline]
408 pub fn recursive(&mut self) -> &mut Self {
409 self.recursive = true;
410 self
411 }
412
413 #[inline]
414 pub fn mode(&mut self, mode: u32) -> &mut Self {
415 self.mode = Some(mode);
416 self
417 }
418}
419
420pub trait BaseFsCreateDir {
421 #[doc(hidden)]
422 fn base_fs_create_dir(
423 &self,
424 path: &Path,
425 options: &CreateDirOptions,
426 ) -> io::Result<()>;
427}
428
429pub trait FsCreateDir: BaseFsCreateDir {
430 fn fs_create_dir(
431 &self,
432 path: impl AsRef<Path>,
433 options: &CreateDirOptions,
434 ) -> io::Result<()> {
435 self.base_fs_create_dir(path.as_ref(), options)
436 }
437}
438
439impl<T: BaseFsCreateDir> FsCreateDir for T {}
440
441pub trait FsCreateDirAll: BaseFsCreateDir {
444 fn fs_create_dir_all(&self, path: impl AsRef<Path>) -> io::Result<()> {
445 self.base_fs_create_dir(
446 path.as_ref(),
447 &CreateDirOptions {
448 recursive: true,
449 mode: None,
450 },
451 )
452 }
453}
454
455impl<T: BaseFsCreateDir> FsCreateDirAll for T {}
456
457pub trait BaseFsHardLink {
460 #[doc(hidden)]
461 fn base_fs_hard_link(&self, src: &Path, dst: &Path) -> io::Result<()>;
462}
463
464pub trait FsHardLink: BaseFsHardLink {
465 fn fs_hard_link(
466 &self,
467 src: impl AsRef<Path>,
468 dst: impl AsRef<Path>,
469 ) -> io::Result<()> {
470 self.base_fs_hard_link(src.as_ref(), dst.as_ref())
471 }
472}
473
474impl<T: BaseFsHardLink> FsHardLink for T {}
475
476#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
479pub enum FileType {
480 File,
481 Dir,
482 Symlink,
483 Unknown,
484}
485
486impl FileType {
487 pub fn is_dir(&self) -> bool {
488 *self == Self::Dir
489 }
490
491 pub fn is_file(&self) -> bool {
492 *self == Self::File
493 }
494
495 pub fn is_symlink(&self) -> bool {
496 *self == Self::Symlink
497 }
498}
499
500impl From<std::fs::FileType> for FileType {
501 fn from(file_type: std::fs::FileType) -> Self {
502 if file_type.is_file() {
503 FileType::File
504 } else if file_type.is_dir() {
505 FileType::Dir
506 } else if file_type.is_symlink() {
507 FileType::Symlink
508 } else {
509 FileType::Unknown
510 }
511 }
512}
513
514#[allow(clippy::len_without_is_empty)]
515pub trait FsMetadataValue: std::fmt::Debug {
516 fn file_type(&self) -> FileType;
517 fn len(&self) -> u64;
518 fn accessed(&self) -> io::Result<SystemTime>;
519 fn created(&self) -> io::Result<SystemTime>;
520 fn changed(&self) -> io::Result<SystemTime>;
521 fn modified(&self) -> io::Result<SystemTime>;
522 fn dev(&self) -> io::Result<u64>;
523 fn ino(&self) -> io::Result<u64>;
524 fn mode(&self) -> io::Result<u32>;
525 fn nlink(&self) -> io::Result<u64>;
526 fn uid(&self) -> io::Result<u32>;
527 fn gid(&self) -> io::Result<u32>;
528 fn rdev(&self) -> io::Result<u64>;
529 fn blksize(&self) -> io::Result<u64>;
530 fn blocks(&self) -> io::Result<u64>;
531 fn is_block_device(&self) -> io::Result<bool>;
532 fn is_char_device(&self) -> io::Result<bool>;
533 fn is_fifo(&self) -> io::Result<bool>;
534 fn is_socket(&self) -> io::Result<bool>;
535 fn file_attributes(&self) -> io::Result<u32>;
536}
537
538pub trait BaseFsMetadata {
539 type Metadata: FsMetadataValue;
540
541 #[doc(hidden)]
542 fn base_fs_metadata(&self, path: &Path) -> io::Result<Self::Metadata>;
543
544 #[doc(hidden)]
545 fn base_fs_symlink_metadata(&self, path: &Path)
546 -> io::Result<Self::Metadata>;
547
548 #[doc(hidden)]
549 fn base_fs_exists(&self, path: &Path) -> io::Result<bool> {
550 match self.base_fs_symlink_metadata(path) {
551 Ok(_) => Ok(true),
552 Err(err) => {
553 if err.kind() == ErrorKind::NotFound {
554 Ok(false)
555 } else {
556 Err(err)
557 }
558 }
559 }
560 }
561
562 #[doc(hidden)]
563 fn base_fs_exists_no_err(&self, path: &Path) -> bool {
564 self.base_fs_exists(path).unwrap_or(false)
565 }
566}
567
568pub trait FsMetadata: BaseFsMetadata {
571 #[inline]
572 fn fs_metadata(&self, path: impl AsRef<Path>) -> io::Result<Self::Metadata> {
573 self.base_fs_metadata(path.as_ref())
574 }
575
576 #[inline]
577 fn fs_symlink_metadata(
578 &self,
579 path: impl AsRef<Path>,
580 ) -> io::Result<Self::Metadata> {
581 self.base_fs_symlink_metadata(path.as_ref())
582 }
583
584 #[inline]
585 fn fs_is_file(&self, path: impl AsRef<Path>) -> io::Result<bool> {
586 Ok(self.fs_metadata(path)?.file_type() == FileType::File)
587 }
588
589 #[inline]
590 fn fs_is_file_no_err(&self, path: impl AsRef<Path>) -> bool {
591 self.fs_is_file(path).unwrap_or(false)
592 }
593
594 #[inline]
595 fn fs_is_dir(&self, path: impl AsRef<Path>) -> io::Result<bool> {
596 Ok(self.fs_metadata(path)?.file_type() == FileType::Dir)
597 }
598
599 #[inline]
600 fn fs_is_dir_no_err(&self, path: impl AsRef<Path>) -> bool {
601 self.fs_is_dir(path).unwrap_or(false)
602 }
603
604 #[inline]
605 fn fs_exists(&self, path: impl AsRef<Path>) -> io::Result<bool> {
606 self.base_fs_exists(path.as_ref())
607 }
608
609 #[inline]
610 fn fs_exists_no_err(&self, path: impl AsRef<Path>) -> bool {
611 self.base_fs_exists_no_err(path.as_ref())
612 }
613
614 #[inline]
615 fn fs_is_symlink(&self, path: impl AsRef<Path>) -> io::Result<bool> {
616 Ok(self.fs_symlink_metadata(path)?.file_type() == FileType::Symlink)
617 }
618
619 #[inline]
620 fn fs_is_symlink_no_err(&self, path: impl AsRef<Path>) -> bool {
621 self.fs_is_symlink(path).unwrap_or(false)
622 }
623}
624
625impl<T: BaseFsMetadata> FsMetadata for T {}
626
627pub trait FsFile:
630 std::io::Read
631 + std::io::Write
632 + std::io::Seek
633 + FsFileIsTerminal
634 + FsFileLock
635 + FsFileSetPermissions
636 + FsFileSetTimes
637 + FsFileSetLen
638 + FsFileSyncAll
639 + FsFileSyncData
640 + FsFileAsRaw
641{
642}
643
644pub trait BaseFsOpen {
645 type File: FsFile;
648
649 #[doc(hidden)]
650 fn base_fs_open(
651 &self,
652 path: &Path,
653 options: &OpenOptions,
654 ) -> io::Result<Self::File>;
655}
656
657pub trait FsOpen: BaseFsOpen {
658 #[inline]
659 fn fs_open(
660 &self,
661 path: impl AsRef<Path>,
662 options: &OpenOptions,
663 ) -> io::Result<Self::File> {
664 self.base_fs_open(path.as_ref(), options)
665 }
666}
667
668impl<T: BaseFsOpen> FsOpen for T {}
669
670pub trait BaseFsRead {
673 #[doc(hidden)]
674 fn base_fs_read(&self, path: &Path) -> io::Result<Cow<'static, [u8]>>;
675}
676
677pub trait FsRead: BaseFsRead {
678 #[inline]
679 fn fs_read(&self, path: impl AsRef<Path>) -> io::Result<Cow<'static, [u8]>> {
680 self.base_fs_read(path.as_ref())
681 }
682
683 fn fs_read_to_string(
684 &self,
685 path: impl AsRef<Path>,
686 ) -> io::Result<Cow<'static, str>> {
687 let bytes = self.fs_read(path)?;
688 match bytes {
689 Cow::Borrowed(bytes) => str::from_utf8(bytes)
690 .map(Cow::Borrowed)
691 .map_err(|e| e.to_string()),
692 Cow::Owned(bytes) => String::from_utf8(bytes)
693 .map(Cow::Owned)
694 .map_err(|e| e.to_string()),
695 }
696 .map_err(|error_text| Error::new(ErrorKind::InvalidData, error_text))
697 }
698
699 fn fs_read_to_string_lossy(
700 &self,
701 path: impl AsRef<Path>,
702 ) -> io::Result<Cow<'static, str>> {
703 #[inline(always)]
705 fn string_from_utf8_lossy(buf: Vec<u8>) -> String {
706 match String::from_utf8_lossy(&buf) {
707 Cow::Owned(s) => s,
709 Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(buf) },
712 }
713 }
714
715 let bytes = self.fs_read(path)?;
716 match bytes {
717 Cow::Borrowed(bytes) => Ok(String::from_utf8_lossy(bytes)),
718 Cow::Owned(bytes) => Ok(Cow::Owned(string_from_utf8_lossy(bytes))),
719 }
720 }
721}
722
723impl<T: BaseFsRead> FsRead for T {}
724
725pub trait FsDirEntry: std::fmt::Debug {
728 type Metadata: FsMetadataValue;
729
730 fn file_name(&self) -> Cow<OsStr>;
731 fn file_type(&self) -> io::Result<FileType>;
732 fn metadata(&self) -> io::Result<Self::Metadata>;
733 fn path(&self) -> Cow<Path>;
734}
735
736pub trait BaseFsReadDir {
737 type ReadDirEntry: FsDirEntry + 'static;
738
739 #[doc(hidden)]
740 fn base_fs_read_dir(
741 &self,
742 path: &Path,
743 ) -> io::Result<Box<dyn Iterator<Item = io::Result<Self::ReadDirEntry>> + '_>>;
744}
745
746pub trait FsReadDir: BaseFsReadDir {
747 #[inline]
748 fn fs_read_dir(
749 &self,
750 path: impl AsRef<Path>,
751 ) -> io::Result<Box<dyn Iterator<Item = io::Result<Self::ReadDirEntry>> + '_>>
752 {
753 self.base_fs_read_dir(path.as_ref())
754 }
755}
756
757impl<T: BaseFsReadDir> FsReadDir for T {}
758
759pub trait BaseFsReadLink {
762 #[doc(hidden)]
763 fn base_fs_read_link(&self, path: &Path) -> io::Result<PathBuf>;
764}
765
766pub trait FsReadLink: BaseFsReadLink {
767 #[inline]
768 fn fs_read_link(&self, path: impl AsRef<Path>) -> io::Result<PathBuf> {
769 self.base_fs_read_link(path.as_ref())
770 }
771}
772
773impl<T: BaseFsReadLink> FsReadLink for T {}
774
775pub trait BaseFsRemoveDir {
778 #[doc(hidden)]
779 fn base_fs_remove_dir(&self, path: &Path) -> io::Result<()>;
780}
781
782pub trait FsRemoveDir: BaseFsRemoveDir {
783 #[inline]
784 fn fs_remove_dir(&self, path: impl AsRef<Path>) -> io::Result<()> {
785 self.base_fs_remove_dir(path.as_ref())
786 }
787}
788
789impl<T: BaseFsRemoveDir> FsRemoveDir for T {}
790
791pub trait BaseFsRemoveDirAll {
794 #[doc(hidden)]
795 fn base_fs_remove_dir_all(&self, path: &Path) -> io::Result<()>;
796}
797
798pub trait FsRemoveDirAll: BaseFsRemoveDirAll {
799 #[inline]
800 fn fs_remove_dir_all(&self, path: impl AsRef<Path>) -> io::Result<()> {
801 self.base_fs_remove_dir_all(path.as_ref())
802 }
803}
804
805impl<T: BaseFsRemoveDirAll> FsRemoveDirAll for T {}
806
807pub trait BaseFsRemoveFile {
810 #[doc(hidden)]
811 fn base_fs_remove_file(&self, path: &Path) -> io::Result<()>;
812}
813
814pub trait FsRemoveFile: BaseFsRemoveFile {
815 #[inline]
816 fn fs_remove_file(&self, path: impl AsRef<Path>) -> io::Result<()> {
817 self.base_fs_remove_file(path.as_ref())
818 }
819}
820
821impl<T: BaseFsRemoveFile> FsRemoveFile for T {}
822
823pub trait BaseFsRename {
826 #[doc(hidden)]
827 fn base_fs_rename(&self, from: &Path, to: &Path) -> io::Result<()>;
828}
829
830pub trait FsRename: BaseFsRename {
831 #[inline]
832 fn fs_rename(
833 &self,
834 from: impl AsRef<Path>,
835 to: impl AsRef<Path>,
836 ) -> io::Result<()> {
837 self.base_fs_rename(from.as_ref(), to.as_ref())
838 }
839}
840
841impl<T: BaseFsRename> FsRename for T {}
842
843pub trait BaseFsSetFileTimes {
846 #[doc(hidden)]
847 fn base_fs_set_file_times(
848 &self,
849 path: &Path,
850 atime: SystemTime,
851 mtime: SystemTime,
852 ) -> io::Result<()>;
853}
854
855pub trait FsSetFileTimes: BaseFsSetFileTimes {
856 #[inline]
857 fn fs_set_file_times(
858 &self,
859 path: impl AsRef<Path>,
860 atime: SystemTime,
861 mtime: SystemTime,
862 ) -> io::Result<()> {
863 self.base_fs_set_file_times(path.as_ref(), atime, mtime)
864 }
865}
866
867impl<T: BaseFsSetFileTimes> FsSetFileTimes for T {}
868
869pub trait BaseFsSetSymlinkFileTimes {
872 #[doc(hidden)]
873 fn base_fs_set_symlink_file_times(
874 &self,
875 path: &Path,
876 atime: SystemTime,
877 mtime: SystemTime,
878 ) -> io::Result<()>;
879}
880
881pub trait FsSetSymlinkFileTimes: BaseFsSetSymlinkFileTimes {
882 #[inline]
883 fn fs_set_symlink_file_times(
884 &self,
885 path: impl AsRef<Path>,
886 atime: SystemTime,
887 mtime: SystemTime,
888 ) -> io::Result<()> {
889 self.base_fs_set_symlink_file_times(path.as_ref(), atime, mtime)
890 }
891}
892
893impl<T: BaseFsSetSymlinkFileTimes> FsSetSymlinkFileTimes for T {}
894
895pub trait BaseFsSetPermissions {
898 #[doc(hidden)]
899 fn base_fs_set_permissions(&self, path: &Path, mode: u32) -> io::Result<()>;
900}
901
902pub trait FsSetPermissions: BaseFsSetPermissions {
903 fn fs_set_permissions(
904 &self,
905 path: impl AsRef<Path>,
906 mode: u32,
907 ) -> io::Result<()> {
908 self.base_fs_set_permissions(path.as_ref(), mode)
909 }
910}
911
912impl<T: BaseFsSetPermissions> FsSetPermissions for T {}
913
914pub trait BaseFsSymlinkDir {
917 #[doc(hidden)]
918 fn base_fs_symlink_dir(&self, original: &Path, link: &Path)
919 -> io::Result<()>;
920}
921
922pub trait FsSymlinkDir: BaseFsSymlinkDir {
923 #[inline]
924 fn fs_symlink_dir(
925 &self,
926 original: impl AsRef<Path>,
927 link: impl AsRef<Path>,
928 ) -> io::Result<()> {
929 self.base_fs_symlink_dir(original.as_ref(), link.as_ref())
930 }
931}
932
933impl<T: BaseFsSymlinkDir> FsSymlinkDir for T {}
934
935pub trait BaseFsSymlinkFile {
938 #[doc(hidden)]
939 fn base_fs_symlink_file(
940 &self,
941 original: &Path,
942 link: &Path,
943 ) -> io::Result<()>;
944}
945
946pub trait FsSymlinkFile: BaseFsSymlinkFile {
947 #[inline]
948 fn fs_symlink_file(
949 &self,
950 original: impl AsRef<Path>,
951 link: impl AsRef<Path>,
952 ) -> io::Result<()> {
953 self.base_fs_symlink_file(original.as_ref(), link.as_ref())
954 }
955}
956
957impl<T: BaseFsSymlinkFile> FsSymlinkFile for T {}
958
959pub trait BaseFsWrite {
962 #[doc(hidden)]
963 fn base_fs_write(&self, path: &Path, data: &[u8]) -> io::Result<()>;
964}
965
966pub trait FsWrite: BaseFsWrite {
967 #[inline]
968 fn fs_write(
969 &self,
970 path: impl AsRef<Path>,
971 data: impl AsRef<[u8]>,
972 ) -> io::Result<()> {
973 self.base_fs_write(path.as_ref(), data.as_ref())
974 }
975}
976
977impl<T: BaseFsWrite> FsWrite for T {}
978
979pub trait FsFileAsRaw {
982 #[cfg(windows)]
985 fn fs_file_as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle>;
986
987 #[cfg(unix)]
990 fn fs_file_as_raw_fd(&self) -> Option<std::os::fd::RawFd>;
991}
992
993pub trait FsFileIsTerminal {
994 fn fs_file_is_terminal(&self) -> bool;
995}
996
997pub enum FsFileLockMode {
998 Shared,
999 Exclusive,
1000}
1001
1002pub trait FsFileLock {
1003 fn fs_file_lock(&mut self, mode: FsFileLockMode) -> io::Result<()>;
1004 fn fs_file_try_lock(&mut self, mode: FsFileLockMode) -> io::Result<()>;
1005 fn fs_file_unlock(&mut self) -> io::Result<()>;
1006}
1007
1008pub trait FsFileSetLen {
1009 fn fs_file_set_len(&mut self, size: u64) -> io::Result<()>;
1010}
1011
1012pub trait FsFileSetPermissions {
1013 fn fs_file_set_permissions(&mut self, mode: u32) -> io::Result<()>;
1014}
1015
1016#[derive(Debug, Clone, Default)]
1017pub struct FsFileTimes {
1018 pub accessed: Option<SystemTime>,
1019 pub modified: Option<SystemTime>,
1020}
1021
1022impl FsFileTimes {
1023 pub fn new() -> Self {
1024 Self::default()
1025 }
1026
1027 pub fn accessed(&mut self, accessed: SystemTime) -> &mut Self {
1028 self.accessed = Some(accessed);
1029 self
1030 }
1031
1032 pub fn modified(&mut self, accessed: SystemTime) -> &mut Self {
1033 self.modified = Some(accessed);
1034 self
1035 }
1036}
1037
1038pub trait FsFileSetTimes {
1039 fn fs_file_set_times(&mut self, times: FsFileTimes) -> io::Result<()>;
1040}
1041
1042pub trait FsFileSyncAll {
1043 fn fs_file_sync_all(&mut self) -> io::Result<()>;
1044}
1045
1046pub trait FsFileSyncData {
1047 fn fs_file_sync_data(&mut self) -> io::Result<()>;
1048}
1049
1050pub trait SystemTimeNow {
1053 fn sys_time_now(&self) -> std::time::SystemTime;
1054}
1055
1056pub trait SystemRandom {
1057 fn sys_random(&self, buf: &mut [u8]) -> io::Result<()>;
1058
1059 fn sys_random_u8(&self) -> io::Result<u8> {
1060 let mut buf = [0; 1];
1061 self.sys_random(&mut buf)?;
1062 Ok(buf[0])
1063 }
1064
1065 fn sys_random_u32(&self) -> io::Result<u32> {
1066 let mut buf = [0; 4];
1067 self.sys_random(&mut buf)?;
1068 Ok(u32::from_le_bytes(buf))
1069 }
1070
1071 fn sys_random_u64(&self) -> io::Result<u64> {
1072 let mut buf = [0; 8];
1073 self.sys_random(&mut buf)?;
1074 Ok(u64::from_le_bytes(buf))
1075 }
1076}
1077
1078pub trait ThreadSleep {
1079 fn thread_sleep(&self, duration: std::time::Duration);
1080}