1use alloc::string::String;
7use alloc::vec::Vec;
8use core::fmt;
9use azul_css::{AzString, U8Vec, EmptyStruct, impl_result, impl_result_inner, impl_vec, impl_vec_clone, impl_vec_debug, impl_vec_mut, impl_option, impl_option_inner};
10
11#[cfg(feature = "std")]
12use std::path::Path;
13
14#[cfg(feature = "std")]
15fn path_to_azstring(p: impl AsRef<Path>) -> AzString {
16 AzString::from(p.as_ref().to_string_lossy().into_owned())
17}
18
19#[derive(Debug, Clone, PartialEq, Eq)]
25#[repr(C)]
26pub struct FileError {
27 pub message: AzString,
29 pub kind: FileErrorKind,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35#[repr(C)]
36pub enum FileErrorKind {
37 NotFound,
39 PermissionDenied,
41 AlreadyExists,
43 InvalidPath,
45 IoError,
47 DirectoryNotEmpty,
49 IsDirectory,
51 IsFile,
53 Other,
55}
56
57impl FileError {
58 pub fn new(kind: FileErrorKind, message: impl Into<String>) -> Self {
59 Self {
60 message: AzString::from(message.into()),
61 kind,
62 }
63 }
64
65 #[cfg(feature = "std")]
66 #[allow(clippy::needless_pass_by_value)]
69 #[must_use] pub fn from_io_error(e: std::io::Error) -> Self {
70 use std::io::ErrorKind;
71
72 let kind = match e.kind() {
73 ErrorKind::NotFound => FileErrorKind::NotFound,
74 ErrorKind::PermissionDenied => FileErrorKind::PermissionDenied,
75 ErrorKind::AlreadyExists => FileErrorKind::AlreadyExists,
76 ErrorKind::IsADirectory => FileErrorKind::IsDirectory,
77 ErrorKind::DirectoryNotEmpty => FileErrorKind::DirectoryNotEmpty,
78 _ => FileErrorKind::IoError,
79 };
80
81 Self {
82 message: AzString::from(e.to_string()),
83 kind,
84 }
85 }
86}
87
88impl fmt::Display for FileError {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 write!(f, "{}", self.message.as_str())
91 }
92}
93
94#[cfg(feature = "std")]
95impl std::error::Error for FileError {}
96
97impl_result!(
99 EmptyStruct,
100 FileError,
101 ResultEmptyStructFileError,
102 copy = false,
103 [Debug, Clone, PartialEq, Eq]
104);
105
106impl_result!(
107 U8Vec,
108 FileError,
109 ResultU8VecFileError,
110 copy = false,
111 [Debug, Clone, PartialEq, Eq]
112);
113
114impl_result!(
115 AzString,
116 FileError,
117 ResultStringFileError,
118 copy = false,
119 [Debug, Clone, PartialEq, Eq]
120);
121
122impl_result!(
123 u64,
124 FileError,
125 Resultu64FileError,
126 copy = false,
127 [Debug, Clone, PartialEq, Eq]
128);
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139#[repr(C)]
140pub enum FileType {
141 File,
143 Directory,
145 Symlink,
147 Other,
149}
150
151#[derive(Copy, Debug, Clone, PartialEq, Eq)]
153#[repr(C)]
154pub struct FileMetadata {
155 pub size: u64,
157 pub file_type: FileType,
159 pub is_readonly: bool,
161 pub modified_secs: u64,
163 pub created_secs: u64,
165}
166
167#[derive(Debug, Clone)]
169#[repr(C)]
170pub struct DirEntry {
171 pub name: AzString,
173 pub path: AzString,
175 pub file_type: FileType,
177}
178
179impl_option!(DirEntry, OptionDirEntry, copy = false, [Debug, Clone]);
181impl_vec!(DirEntry, DirEntryVec, DirEntryVecDestructor, DirEntryVecDestructorType, DirEntryVecSlice, OptionDirEntry);
182impl_vec_clone!(DirEntry, DirEntryVec, DirEntryVecDestructor);
183impl_vec_debug!(DirEntry, DirEntryVec);
184impl_vec_mut!(DirEntry, DirEntryVec);
185
186impl_result!(
188 FileMetadata,
189 FileError,
190 ResultFileMetadataFileError,
191 copy = false,
192 [Debug, Clone, PartialEq, Eq]
193);
194
195impl_result!(
196 DirEntryVec,
197 FileError,
198 ResultDirEntryVecFileError,
199 copy = false,
200 clone = false,
201 [Debug, Clone]
202);
203
204#[cfg(feature = "std")]
210pub fn file_read(path: &str) -> Result<U8Vec, FileError> {
214 let data = std::fs::read(path)
215 .map_err(FileError::from_io_error)?;
216 Ok(U8Vec::from(data))
217}
218
219#[cfg(feature = "std")]
221pub fn file_read_string(path: &str) -> Result<AzString, FileError> {
225 let data = std::fs::read_to_string(path)
226 .map_err(FileError::from_io_error)?;
227 Ok(AzString::from(data))
228}
229
230#[cfg(feature = "std")]
232pub fn file_write(path: &str, data: &[u8]) -> Result<EmptyStruct, FileError> {
236 std::fs::write(path, data)
237 .map(|()| EmptyStruct::default()).map_err(FileError::from_io_error)
238}
239
240#[cfg(feature = "std")]
242pub fn file_write_string(path: &str, data: &str) -> Result<EmptyStruct, FileError> {
246 std::fs::write(path, data.as_bytes())
247 .map(|()| EmptyStruct::default()).map_err(FileError::from_io_error)
248}
249
250#[cfg(feature = "std")]
252pub fn file_append(path: &str, data: &[u8]) -> Result<EmptyStruct, FileError> {
256 use std::fs::OpenOptions;
257 use std::io::Write;
258
259 let mut file = OpenOptions::new()
260 .create(true)
261 .append(true)
262 .open(path)
263 .map_err(FileError::from_io_error)?;
264
265 file.write_all(data)
266 .map(|()| EmptyStruct::default())
267 .map_err(FileError::from_io_error)
268}
269
270#[cfg(feature = "std")]
272pub fn file_copy(from: &str, to: &str) -> Result<u64, FileError> {
276 std::fs::copy(from, to)
277 .map_err(FileError::from_io_error)
278}
279
280#[cfg(feature = "std")]
282pub fn file_rename(from: &str, to: &str) -> Result<EmptyStruct, FileError> {
286 std::fs::rename(from, to)
287 .map(|()| EmptyStruct::default()).map_err(FileError::from_io_error)
288}
289
290#[cfg(feature = "std")]
292pub fn file_delete(path: &str) -> Result<EmptyStruct, FileError> {
296 std::fs::remove_file(path)
297 .map(|()| EmptyStruct::default()).map_err(FileError::from_io_error)
298}
299
300#[cfg(feature = "std")]
302#[must_use] pub fn path_exists(path: &str) -> bool {
303 Path::new(path).exists()
304}
305
306#[cfg(feature = "std")]
308#[must_use] pub fn path_is_file(path: &str) -> bool {
309 Path::new(path).is_file()
310}
311
312#[cfg(feature = "std")]
314#[must_use] pub fn path_is_dir(path: &str) -> bool {
315 Path::new(path).is_dir()
316}
317
318#[cfg(feature = "std")]
320pub fn file_metadata(path: &str) -> Result<FileMetadata, FileError> {
324 let meta = std::fs::symlink_metadata(path)
325 .map_err(FileError::from_io_error)?;
326
327 let file_type = if meta.is_file() {
328 FileType::File
329 } else if meta.is_dir() {
330 FileType::Directory
331 } else if meta.is_symlink() {
332 FileType::Symlink
333 } else {
334 FileType::Other
335 };
336
337 let modified_secs = meta.modified()
338 .ok()
339 .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())
340 .map_or(0, |d| d.as_secs());
341
342 let created_secs = meta.created()
343 .ok()
344 .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())
345 .map_or(0, |d| d.as_secs());
346
347 Ok(FileMetadata {
348 size: meta.len(),
349 file_type,
350 is_readonly: meta.permissions().readonly(),
351 modified_secs,
352 created_secs,
353 })
354}
355
356#[cfg(not(feature = "std"))]
362fn no_std_file_error() -> FileError {
363 FileError::new(FileErrorKind::Other, "file IO requires the `std` feature")
364}
365
366#[cfg(not(feature = "std"))]
368pub fn file_read(_path: &str) -> Result<U8Vec, FileError> {
369 Err(no_std_file_error())
370}
371
372#[cfg(not(feature = "std"))]
374pub fn file_read_string(_path: &str) -> Result<AzString, FileError> {
375 Err(no_std_file_error())
376}
377
378#[cfg(not(feature = "std"))]
380pub fn file_write(_path: &str, _data: &[u8]) -> Result<EmptyStruct, FileError> {
381 Err(no_std_file_error())
382}
383
384#[cfg(not(feature = "std"))]
386pub fn file_write_string(_path: &str, _data: &str) -> Result<EmptyStruct, FileError> {
387 Err(no_std_file_error())
388}
389
390#[cfg(not(feature = "std"))]
392pub fn file_append(_path: &str, _data: &[u8]) -> Result<EmptyStruct, FileError> {
393 Err(no_std_file_error())
394}
395
396#[cfg(not(feature = "std"))]
398pub fn file_copy(_from: &str, _to: &str) -> Result<u64, FileError> {
399 Err(no_std_file_error())
400}
401
402#[cfg(not(feature = "std"))]
404pub fn file_rename(_from: &str, _to: &str) -> Result<EmptyStruct, FileError> {
405 Err(no_std_file_error())
406}
407
408#[cfg(not(feature = "std"))]
410pub fn file_delete(_path: &str) -> Result<EmptyStruct, FileError> {
411 Err(no_std_file_error())
412}
413
414#[cfg(not(feature = "std"))]
416pub fn path_exists(_path: &str) -> bool {
417 false
418}
419
420#[cfg(not(feature = "std"))]
422pub fn path_is_file(_path: &str) -> bool {
423 false
424}
425
426#[cfg(not(feature = "std"))]
428pub fn path_is_dir(_path: &str) -> bool {
429 false
430}
431
432#[cfg(not(feature = "std"))]
434pub fn file_metadata(_path: &str) -> Result<FileMetadata, FileError> {
435 Err(no_std_file_error())
436}
437
438#[cfg(feature = "std")]
444pub fn dir_create(path: &str) -> Result<EmptyStruct, FileError> {
448 std::fs::create_dir(path)
449 .map(|()| EmptyStruct::default()).map_err(FileError::from_io_error)
450}
451
452#[cfg(feature = "std")]
454pub fn dir_create_all(path: &str) -> Result<EmptyStruct, FileError> {
458 std::fs::create_dir_all(path)
459 .map(|()| EmptyStruct::default()).map_err(FileError::from_io_error)
460}
461
462#[cfg(feature = "std")]
464pub fn dir_delete(path: &str) -> Result<EmptyStruct, FileError> {
468 std::fs::remove_dir(path)
469 .map(|()| EmptyStruct::default()).map_err(FileError::from_io_error)
470}
471
472#[cfg(feature = "std")]
474pub fn dir_delete_all(path: &str) -> Result<EmptyStruct, FileError> {
478 std::fs::remove_dir_all(path)
479 .map(|()| EmptyStruct::default()).map_err(FileError::from_io_error)
480}
481
482#[cfg(feature = "std")]
484pub fn dir_list(path: &str) -> Result<DirEntryVec, FileError> {
488 let entries = std::fs::read_dir(path)
489 .map_err(FileError::from_io_error)?;
490
491 let mut result = Vec::new();
492
493 for entry in entries {
494 let entry = entry.map_err(FileError::from_io_error)?;
495 let file_type = entry.file_type()
496 .map(|ft| {
497 if ft.is_file() {
498 FileType::File
499 } else if ft.is_dir() {
500 FileType::Directory
501 } else if ft.is_symlink() {
502 FileType::Symlink
503 } else {
504 FileType::Other
505 }
506 })
507 .unwrap_or(FileType::Other);
508
509 result.push(DirEntry {
510 name: path_to_azstring(entry.file_name()),
511 path: path_to_azstring(entry.path()),
512 file_type,
513 });
514 }
515
516 Ok(DirEntryVec::from_vec(result))
517}
518
519#[cfg(not(feature = "std"))]
521pub fn dir_create(_path: &str) -> Result<EmptyStruct, FileError> {
522 Err(no_std_file_error())
523}
524
525#[cfg(not(feature = "std"))]
527pub fn dir_create_all(_path: &str) -> Result<EmptyStruct, FileError> {
528 Err(no_std_file_error())
529}
530
531#[cfg(not(feature = "std"))]
533pub fn dir_delete(_path: &str) -> Result<EmptyStruct, FileError> {
534 Err(no_std_file_error())
535}
536
537#[cfg(not(feature = "std"))]
539pub fn dir_delete_all(_path: &str) -> Result<EmptyStruct, FileError> {
540 Err(no_std_file_error())
541}
542
543#[cfg(not(feature = "std"))]
545pub fn dir_list(_path: &str) -> Result<DirEntryVec, FileError> {
546 Err(no_std_file_error())
547}
548
549#[cfg(feature = "std")]
555#[must_use] pub fn path_join(base: &str, path: &str) -> AzString {
556 let joined = Path::new(base).join(path);
557 path_to_azstring(joined)
558}
559
560#[cfg(feature = "std")]
562pub fn path_parent(path: &str) -> Option<AzString> {
563 Path::new(path).parent()
564 .map(path_to_azstring)
565}
566
567#[cfg(feature = "std")]
569pub fn path_file_name(path: &str) -> Option<AzString> {
570 Path::new(path).file_name()
571 .map(path_to_azstring)
572}
573
574#[cfg(feature = "std")]
576pub fn path_extension(path: &str) -> Option<AzString> {
577 Path::new(path).extension()
578 .map(path_to_azstring)
579}
580
581#[cfg(feature = "std")]
583pub fn path_canonicalize(path: &str) -> Result<AzString, FileError> {
587 let canonical = std::fs::canonicalize(path)
588 .map_err(FileError::from_io_error)?;
589 Ok(path_to_azstring(canonical))
590}
591
592#[cfg(feature = "std")]
598#[must_use] pub fn temp_dir() -> AzString {
599 path_to_azstring(std::env::temp_dir())
600}
601
602#[cfg(not(feature = "std"))]
604pub fn path_join(_base: &str, _path: &str) -> AzString {
605 AzString::from_const_str("")
606}
607
608#[cfg(not(feature = "std"))]
610pub fn path_parent(_path: &str) -> Option<AzString> {
611 None
612}
613
614#[cfg(not(feature = "std"))]
616pub fn path_file_name(_path: &str) -> Option<AzString> {
617 None
618}
619
620#[cfg(not(feature = "std"))]
622pub fn path_extension(_path: &str) -> Option<AzString> {
623 None
624}
625
626#[cfg(not(feature = "std"))]
628pub fn path_canonicalize(_path: &str) -> Result<AzString, FileError> {
629 Err(no_std_file_error())
630}
631
632#[cfg(not(feature = "std"))]
634pub fn temp_dir() -> AzString {
635 AzString::from_const_str("")
636}
637
638#[derive(Debug, Clone, PartialEq, Eq, Hash)]
646#[repr(C)]
647pub struct FilePath {
648 pub inner: AzString,
649}
650
651impl_result!(
653 FilePath,
654 FileError,
655 ResultFilePathFileError,
656 copy = false,
657 [Debug, Clone, PartialEq, Eq]
658);
659
660impl_option!(FilePath, OptionFilePath, copy = false, [Clone, Debug, PartialEq, Eq]);
662
663impl Default for FilePath {
664 fn default() -> Self {
665 Self { inner: AzString::from_const_str("") }
666 }
667}
668
669impl FilePath {
670 #[must_use] pub const fn new(path: AzString) -> Self {
672 Self { inner: path }
673 }
674
675 #[must_use] pub fn empty() -> Self {
677 Self::default()
678 }
679
680 #[must_use] pub fn from_str(s: &str) -> Self {
682 Self { inner: AzString::from(String::from(s)) }
683 }
684
685 #[cfg(feature = "std")]
687 #[must_use] pub fn get_temp_dir() -> Self {
688 Self { inner: temp_dir() }
689 }
690
691 #[cfg(feature = "std")]
693 pub fn get_current_dir() -> Result<Self, FileError> {
697 match std::env::current_dir() {
698 Ok(p) => Ok(Self { inner: path_to_azstring(p) }),
699 Err(e) => Err(FileError::from_io_error(e)),
700 }
701 }
702
703 #[cfg(all(feature = "std", feature = "extra"))]
705 #[must_use] pub fn get_home_dir() -> Option<Self> {
706 dirs::home_dir().map(|p| Self { inner: path_to_azstring(p) })
707 }
708
709 #[cfg(all(feature = "std", feature = "extra"))]
711 #[must_use] pub fn get_cache_dir() -> Option<Self> {
712 dirs::cache_dir().map(|p| Self { inner: path_to_azstring(p) })
713 }
714
715 #[cfg(all(feature = "std", feature = "extra"))]
717 #[must_use] pub fn get_config_dir() -> Option<Self> {
718 dirs::config_dir().map(|p| Self { inner: path_to_azstring(p) })
719 }
720
721 #[cfg(all(feature = "std", feature = "extra"))]
723 #[must_use] pub fn get_config_local_dir() -> Option<Self> {
724 dirs::config_local_dir().map(|p| Self { inner: path_to_azstring(p) })
725 }
726
727 #[cfg(all(feature = "std", feature = "extra"))]
729 #[must_use] pub fn get_data_dir() -> Option<Self> {
730 dirs::data_dir().map(|p| Self { inner: path_to_azstring(p) })
731 }
732
733 #[cfg(all(feature = "std", feature = "extra"))]
735 #[must_use] pub fn get_data_local_dir() -> Option<Self> {
736 dirs::data_local_dir().map(|p| Self { inner: path_to_azstring(p) })
737 }
738
739 #[cfg(all(feature = "std", feature = "extra"))]
741 #[must_use] pub fn get_desktop_dir() -> Option<Self> {
742 dirs::desktop_dir().map(|p| Self { inner: path_to_azstring(p) })
743 }
744
745 #[cfg(all(feature = "std", feature = "extra"))]
747 #[must_use] pub fn get_document_dir() -> Option<Self> {
748 dirs::document_dir().map(|p| Self { inner: path_to_azstring(p) })
749 }
750
751 #[cfg(all(feature = "std", feature = "extra"))]
753 #[must_use] pub fn get_download_dir() -> Option<Self> {
754 dirs::download_dir().map(|p| Self { inner: path_to_azstring(p) })
755 }
756
757 #[cfg(all(feature = "std", feature = "extra"))]
759 #[must_use] pub fn get_executable_dir() -> Option<Self> {
760 dirs::executable_dir().map(|p| Self { inner: path_to_azstring(p) })
761 }
762
763 #[cfg(all(feature = "std", feature = "extra"))]
765 #[must_use] pub fn get_font_dir() -> Option<Self> {
766 dirs::font_dir().map(|p| Self { inner: path_to_azstring(p) })
767 }
768
769 #[cfg(all(feature = "std", feature = "extra"))]
771 #[must_use] pub fn get_picture_dir() -> Option<Self> {
772 dirs::picture_dir().map(|p| Self { inner: path_to_azstring(p) })
773 }
774
775 #[cfg(all(feature = "std", feature = "extra"))]
777 #[must_use] pub fn get_preference_dir() -> Option<Self> {
778 dirs::preference_dir().map(|p| Self { inner: path_to_azstring(p) })
779 }
780
781 #[cfg(all(feature = "std", feature = "extra"))]
783 #[must_use] pub fn get_public_dir() -> Option<Self> {
784 dirs::public_dir().map(|p| Self { inner: path_to_azstring(p) })
785 }
786
787 #[cfg(all(feature = "std", feature = "extra"))]
789 #[must_use] pub fn get_runtime_dir() -> Option<Self> {
790 dirs::runtime_dir().map(|p| Self { inner: path_to_azstring(p) })
791 }
792
793 #[cfg(all(feature = "std", feature = "extra"))]
795 #[must_use] pub fn get_state_dir() -> Option<Self> {
796 dirs::state_dir().map(|p| Self { inner: path_to_azstring(p) })
797 }
798
799 #[cfg(all(feature = "std", feature = "extra"))]
801 #[must_use] pub fn get_audio_dir() -> Option<Self> {
802 dirs::audio_dir().map(|p| Self { inner: path_to_azstring(p) })
803 }
804
805 #[cfg(all(feature = "std", feature = "extra"))]
807 #[must_use] pub fn get_video_dir() -> Option<Self> {
808 dirs::video_dir().map(|p| Self { inner: path_to_azstring(p) })
809 }
810
811 #[cfg(all(feature = "std", feature = "extra"))]
813 #[must_use] pub fn get_template_dir() -> Option<Self> {
814 dirs::template_dir().map(|p| Self { inner: path_to_azstring(p) })
815 }
816
817 #[cfg(feature = "std")]
819 #[must_use] pub fn join(&self, other: &Self) -> Self {
820 Self { inner: path_join(self.inner.as_str(), other.inner.as_str()) }
821 }
822
823 #[cfg(feature = "std")]
825 #[must_use] pub fn join_str(&self, component: &AzString) -> Self {
826 Self { inner: path_join(self.inner.as_str(), component.as_str()) }
827 }
828
829 #[cfg(feature = "std")]
831 #[must_use] pub fn parent(&self) -> Option<Self> {
832 path_parent(self.inner.as_str()).map(|p| Self { inner: p })
833 }
834
835 #[cfg(feature = "std")]
837 #[must_use] pub fn file_name(&self) -> Option<AzString> {
838 path_file_name(self.inner.as_str())
839 }
840
841 #[cfg(feature = "std")]
843 #[must_use] pub fn extension(&self) -> Option<AzString> {
844 path_extension(self.inner.as_str())
845 }
846
847 #[cfg(feature = "std")]
849 #[must_use] pub fn exists(&self) -> bool {
850 path_exists(self.inner.as_str())
851 }
852
853 #[cfg(feature = "std")]
855 #[must_use] pub fn is_file(&self) -> bool {
856 path_is_file(self.inner.as_str())
857 }
858
859 #[cfg(feature = "std")]
861 #[must_use] pub fn is_dir(&self) -> bool {
862 path_is_dir(self.inner.as_str())
863 }
864
865 #[cfg(feature = "std")]
867 #[must_use] pub fn is_absolute(&self) -> bool {
868 Path::new(self.inner.as_str()).is_absolute()
869 }
870
871 #[cfg(feature = "std")]
873 pub fn create_dir_all(&self) -> Result<EmptyStruct, FileError> {
877 dir_create_all(self.inner.as_str())
878 }
879
880 #[cfg(feature = "std")]
882 pub fn create_dir(&self) -> Result<EmptyStruct, FileError> {
886 dir_create(self.inner.as_str())
887 }
888
889 #[cfg(feature = "std")]
891 pub fn remove_file(&self) -> Result<EmptyStruct, FileError> {
895 file_delete(self.inner.as_str())
896 }
897
898 #[cfg(feature = "std")]
900 pub fn remove_dir(&self) -> Result<EmptyStruct, FileError> {
904 dir_delete(self.inner.as_str())
905 }
906
907 #[cfg(feature = "std")]
909 pub fn remove_dir_all(&self) -> Result<EmptyStruct, FileError> {
913 dir_delete_all(self.inner.as_str())
914 }
915
916 #[cfg(feature = "std")]
918 pub fn read_bytes(&self) -> Result<U8Vec, FileError> {
922 file_read(self.inner.as_str())
923 }
924
925 #[cfg(feature = "std")]
927 pub fn read_string(&self) -> Result<AzString, FileError> {
931 file_read_string(self.inner.as_str())
932 }
933
934 #[cfg(feature = "std")]
936 pub fn write_bytes(&self, data: &U8Vec) -> Result<EmptyStruct, FileError> {
940 file_write(self.inner.as_str(), data.as_ref())
941 }
942
943 #[cfg(feature = "std")]
945 pub fn write_string(&self, data: &AzString) -> Result<EmptyStruct, FileError> {
949 file_write_string(self.inner.as_str(), data.as_str())
950 }
951
952 #[cfg(feature = "std")]
954 pub fn copy_to(&self, dest: &Self) -> Result<u64, FileError> {
958 file_copy(self.inner.as_str(), dest.inner.as_str())
959 }
960
961 #[cfg(feature = "std")]
963 pub fn rename_to(&self, dest: &Self) -> Result<EmptyStruct, FileError> {
967 file_rename(self.inner.as_str(), dest.inner.as_str())
968 }
969
970 #[must_use] pub fn as_str(&self) -> &str {
972 self.inner.as_str()
973 }
974
975 #[must_use] pub fn as_string(&self) -> AzString {
977 self.inner.clone()
978 }
979
980 #[cfg(feature = "std")]
982 pub fn read_dir(&self) -> Result<DirEntryVec, FileError> {
986 dir_list(self.inner.as_str())
987 }
988
989 #[cfg(feature = "std")]
991 pub fn metadata(&self) -> Result<FileMetadata, FileError> {
995 file_metadata(self.inner.as_str())
996 }
997
998 #[cfg(feature = "std")]
1000 pub fn canonicalize(&self) -> Result<Self, FileError> {
1004 path_canonicalize(self.inner.as_str()).map(|p| Self { inner: p })
1005 }
1006}
1007
1008impl From<String> for FilePath {
1009 fn from(s: String) -> Self {
1010 Self { inner: AzString::from(s) }
1011 }
1012}
1013
1014impl From<&str> for FilePath {
1015 fn from(s: &str) -> Self {
1016 Self { inner: AzString::from(String::from(s)) }
1017 }
1018}
1019
1020impl From<AzString> for FilePath {
1021 fn from(s: AzString) -> Self {
1022 Self { inner: s }
1023 }
1024}
1025
1026#[cfg(test)]
1027mod tests {
1028 use super::*;
1029
1030 #[test]
1031 #[cfg(feature = "std")]
1032 fn test_temp_dir() {
1033 let temp = temp_dir();
1034 assert!(!temp.as_str().is_empty());
1035 }
1036
1037 #[test]
1038 #[cfg(feature = "std")]
1039 fn test_path_join() {
1040 let joined = path_join("/home/user", "file.txt");
1041 assert!(joined.as_str().contains("file.txt"));
1042 }
1043}