1use crate::fs::{DirBuilder, File, Metadata, OpenOptions, ReadDir};
2#[cfg(target_os = "wasi")]
3use async_std::os::wasi::{
4    fs::OpenOptionsExt,
5    io::{AsRawFd, IntoRawFd},
6};
7use async_std::path::{Path, PathBuf};
8use async_std::task::spawn_blocking;
9use async_std::{fs, io};
10use cap_primitives::fs::{
11    canonicalize, copy, create_dir, hard_link, open, open_ambient_dir, open_dir, open_parent_dir,
12    read_base_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, remove_open_dir,
13    remove_open_dir_all, rename, set_permissions, stat, DirOptions, FollowSymlinks, Permissions,
14};
15use cap_primitives::AmbientAuthority;
16use io_lifetimes::raw::{AsRawFilelike, FromRawFilelike};
17#[cfg(not(windows))]
18use io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
19use io_lifetimes::{AsFilelike, FromFilelike};
20#[cfg(windows)]
21use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle};
22use std::fmt;
23use std::mem::ManuallyDrop;
24#[cfg(unix)]
25use {
26    crate::os::unix::net::{UnixDatagram, UnixListener, UnixStream},
27    async_std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd},
28    cap_primitives::fs::symlink,
29};
30#[cfg(windows)]
31use {
32    async_std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle},
33    cap_primitives::fs::{symlink_dir, symlink_file},
34    io_extras::os::windows::{
35        AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, IntoRawHandleOrSocket,
36        OwnedHandleOrSocket, RawHandleOrSocket,
37    },
38};
39
40#[derive(Clone)]
51pub struct Dir {
52    std_file: fs::File,
53}
54
55impl Dir {
56    #[inline]
65    pub fn from_std_file(std_file: fs::File) -> Self {
66        Self { std_file }
67    }
68
69    #[inline]
71    pub fn into_std_file(self) -> fs::File {
72        self.std_file
73    }
74
75    #[inline]
80    pub async fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
81        self.open_with(path, OpenOptions::new().read(true)).await
82    }
83
84    #[inline]
91    pub async fn open_with<P: AsRef<Path>>(
92        &self,
93        path: P,
94        options: &OpenOptions,
95    ) -> io::Result<File> {
96        self._open_with(path.as_ref(), options).await
97    }
98
99    #[cfg(not(target_os = "wasi"))]
100    async fn _open_with(&self, path: &Path, options: &OpenOptions) -> io::Result<File> {
101        let path = path.to_path_buf();
102        let clone = self.clone();
103        let options = options.clone();
104        let file = spawn_blocking(move || {
105            open(
106                &*clone.as_filelike_view::<std::fs::File>(),
107                path.as_ref(),
108                &options,
109            )
110        })
111        .await?
112        .into();
113        Ok(File::from_std(file))
114    }
115
116    #[cfg(target_os = "wasi")]
117    async fn _open_with(
118        file: &std::fs::File,
119        path: &Path,
120        options: &OpenOptions,
121    ) -> io::Result<File> {
122        let file = options.open_at(&self.std_file, path)?.into();
123        Ok(File::from_std(file))
124    }
125
126    #[inline]
128    pub async fn open_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<Self> {
129        let path = path.as_ref().to_path_buf();
130        let clone = self.clone();
131        let dir = spawn_blocking(move || {
132            open_dir(&clone.as_filelike_view::<std::fs::File>(), path.as_ref())
133        })
134        .await?
135        .into();
136        Ok(Self::from_std_file(dir))
137    }
138
139    #[inline]
146    pub fn create_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
147        self._create_dir_one(path.as_ref(), &DirOptions::new())
148    }
149
150    #[inline]
158    pub fn create_dir_all<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
159        self._create_dir_all(path.as_ref(), &DirOptions::new())
160    }
161
162    #[inline]
169    pub fn create_dir_with<P: AsRef<Path>>(
170        &self,
171        path: P,
172        dir_builder: &DirBuilder,
173    ) -> io::Result<()> {
174        let options = dir_builder.options();
175        if dir_builder.is_recursive() {
176            self._create_dir_all(path.as_ref(), options)
177        } else {
178            self._create_dir_one(path.as_ref(), options)
179        }
180    }
181
182    #[inline]
183    fn _create_dir_one(&self, path: &Path, dir_options: &DirOptions) -> io::Result<()> {
184        create_dir(
185            &self.as_filelike_view::<std::fs::File>(),
186            path.as_ref(),
187            dir_options,
188        )
189    }
190
191    fn _create_dir_all(&self, path: &Path, dir_options: &DirOptions) -> io::Result<()> {
192        if path == Path::new("") {
193            return Ok(());
194        }
195
196        match self._create_dir_one(path, dir_options) {
197            Ok(()) => return Ok(()),
198            Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
199            Err(_) if self.is_dir_blocking(path) => return Ok(()),
200            Err(e) => return Err(e),
201        }
202        match path.parent() {
203            Some(p) => self._create_dir_all(p, dir_options)?,
204            None => {
205                return Err(io::Error::new(
206                    io::ErrorKind::Other,
207                    "failed to create whole tree",
208                ))
209            }
210        }
211        match self._create_dir_one(path, dir_options) {
212            Ok(()) => Ok(()),
213            Err(_) if self.is_dir_blocking(path) => Ok(()),
214            Err(e) => Err(e),
215        }
216    }
217
218    #[inline]
223    pub async fn create<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
224        self.open_with(
225            path,
226            OpenOptions::new().write(true).create(true).truncate(true),
227        )
228        .await
229    }
230
231    #[inline]
238    pub async fn canonicalize<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> {
239        let path = path.as_ref().to_path_buf();
240        let clone = self.clone();
241        spawn_blocking(move || {
242            canonicalize(&clone.as_filelike_view::<std::fs::File>(), path.as_ref())
243        })
244        .await
245        .map(PathBuf::from)
246    }
247
248    #[inline]
255    pub async fn copy<P: AsRef<Path>, Q: AsRef<Path>>(
256        &self,
257        from: P,
258        to_dir: &Self,
259        to: Q,
260    ) -> io::Result<u64> {
261        let from = from.as_ref().to_path_buf();
262        let to = to.as_ref().to_path_buf();
263        let from_clone = self.clone();
264        let to_clone = to_dir.clone();
265        spawn_blocking(move || {
266            copy(
267                &from_clone.as_filelike_view::<std::fs::File>(),
268                from.as_ref(),
269                &to_clone.as_filelike_view::<std::fs::File>(),
270                to.as_ref(),
271            )
272        })
273        .await
274    }
275
276    #[inline]
281    pub async fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(
282        &self,
283        src: P,
284        dst_dir: &Self,
285        dst: Q,
286    ) -> io::Result<()> {
287        let dst = dst.as_ref().to_path_buf();
288        let src = src.as_ref().to_path_buf();
289        let src_clone = self.clone();
290        let dst_clone = dst_dir.clone();
291        spawn_blocking(move || {
292            hard_link(
293                &src_clone.as_filelike_view::<std::fs::File>(),
294                src.as_ref(),
295                &dst_clone.as_filelike_view::<std::fs::File>(),
296                dst.as_ref(),
297            )
298        })
299        .await
300    }
301
302    #[inline]
308    pub async fn metadata<P: AsRef<Path>>(&self, path: P) -> io::Result<Metadata> {
309        let path = path.as_ref().to_path_buf();
310        let clone = self.clone();
311        spawn_blocking(move || {
312            stat(
313                &clone.as_filelike_view::<std::fs::File>(),
314                path.as_ref(),
315                FollowSymlinks::Yes,
316            )
317        })
318        .await
319    }
320
321    #[inline]
323    fn metadata_blocking<P: AsRef<Path>>(&self, path: P) -> io::Result<Metadata> {
324        let path = path.as_ref().to_path_buf();
325        stat(
326            &self.as_filelike_view::<std::fs::File>(),
327            path.as_ref(),
328            FollowSymlinks::Yes,
329        )
330    }
331
332    #[inline]
337    pub async fn dir_metadata(&self) -> io::Result<Metadata> {
338        let clone = self.clone();
339        spawn_blocking(move || metadata_from(&*clone.as_filelike_view::<std::fs::File>())).await
340    }
341
342    #[inline]
344    pub async fn entries(&self) -> io::Result<ReadDir> {
345        let clone = self.clone();
346        spawn_blocking(move || read_base_dir(&clone.as_filelike_view::<std::fs::File>()))
347            .await
348            .map(|inner| ReadDir { inner })
349    }
350
351    #[inline]
356    pub async fn read_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<ReadDir> {
357        let path = path.as_ref().to_path_buf();
358        let clone = self.clone();
359        spawn_blocking(move || read_dir(&clone.as_filelike_view::<std::fs::File>(), path.as_ref()))
360            .await
361            .map(|inner| ReadDir { inner })
362    }
363
364    #[inline]
369    pub async fn read<P: AsRef<Path>>(&self, path: P) -> io::Result<Vec<u8>> {
370        use async_std::prelude::*;
371        let mut file = self.open(path).await?;
372        let mut bytes = Vec::with_capacity(initial_buffer_size(&file).await);
373        file.read_to_end(&mut bytes).await?;
374        Ok(bytes)
375    }
376
377    #[inline]
382    pub async fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> {
383        let path = path.as_ref().to_path_buf();
384        let clone = self.clone();
385        spawn_blocking(move || read_link(&clone.as_filelike_view::<std::fs::File>(), path.as_ref()))
386            .await
387            .map(PathBuf::from)
388    }
389
390    #[inline]
395    pub async fn read_to_string<P: AsRef<Path>>(&self, path: P) -> io::Result<String> {
396        use async_std::prelude::*;
397        let mut s = String::new();
398        self.open(path).await?.read_to_string(&mut s).await?;
399        Ok(s)
400    }
401
402    #[inline]
407    pub async fn remove_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
408        let path = path.as_ref().to_path_buf();
409        let clone = self.clone();
410        spawn_blocking(move || {
411            remove_dir(&clone.as_filelike_view::<std::fs::File>(), path.as_ref())
412        })
413        .await
414    }
415
416    #[inline]
422    pub async fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
423        let path = path.as_ref().to_path_buf();
424        let clone = self.clone();
425        spawn_blocking(move || {
426            remove_dir_all(&clone.as_filelike_view::<std::fs::File>(), path.as_ref())
427        })
428        .await
429    }
430
431    #[inline]
437    pub async fn remove_open_dir(self) -> io::Result<()> {
438        let file = std::fs::File::from_into_filelike(self.std_file);
439        spawn_blocking(move || remove_open_dir(file)).await
440    }
441
442    #[inline]
449    pub async fn remove_open_dir_all(self) -> io::Result<()> {
450        let file = std::fs::File::from_into_filelike(self.std_file);
451        spawn_blocking(move || remove_open_dir_all(file)).await
452    }
453
454    #[inline]
459    pub async fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
460        let path = path.as_ref().to_path_buf();
461        let clone = self.clone();
462        spawn_blocking(move || {
463            remove_file(&clone.as_filelike_view::<std::fs::File>(), path.as_ref())
464        })
465        .await
466    }
467
468    #[inline]
474    pub async fn rename<P: AsRef<Path>, Q: AsRef<Path>>(
475        &self,
476        from: P,
477        to_dir: &Self,
478        to: Q,
479    ) -> io::Result<()> {
480        let from = from.as_ref().to_path_buf();
481        let to = to.as_ref().to_path_buf();
482        let clone = self.clone();
483        let to_clone = to_dir.clone();
484        spawn_blocking(move || {
485            rename(
486                &clone.as_filelike_view::<std::fs::File>(),
487                from.as_ref(),
488                &to_clone.as_filelike_view::<std::fs::File>(),
489                to.as_ref(),
490            )
491        })
492        .await
493    }
494
495    pub async fn set_permissions<P: AsRef<Path>>(
502        &self,
503        path: P,
504        perm: Permissions,
505    ) -> io::Result<()> {
506        let path = path.as_ref().to_path_buf();
507        let clone = self.clone();
508        spawn_blocking(move || {
509            set_permissions(
510                &clone.as_filelike_view::<std::fs::File>(),
511                path.as_ref(),
512                perm,
513            )
514        })
515        .await
516    }
517
518    #[inline]
523    pub async fn symlink_metadata<P: AsRef<Path>>(&self, path: P) -> io::Result<Metadata> {
524        let path = path.as_ref().to_path_buf();
525        let clone = self.clone();
526        spawn_blocking(move || {
527            stat(
528                &clone.as_filelike_view::<std::fs::File>(),
529                path.as_ref(),
530                FollowSymlinks::No,
531            )
532        })
533        .await
534    }
535
536    #[inline]
541    pub async fn write<P: AsRef<Path>, C: AsRef<[u8]>>(
542        &self,
543        path: P,
544        contents: C,
545    ) -> io::Result<()> {
546        use async_std::prelude::*;
547        let mut file = self.create(path).await?;
548        file.write_all(contents.as_ref()).await
549    }
550
551    #[cfg(not(windows))]
568    #[inline]
569    pub async fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(
570        &self,
571        original: P,
572        link: Q,
573    ) -> io::Result<()> {
574        let original = original.as_ref().to_path_buf();
575        let link = link.as_ref().to_path_buf();
576        let clone = self.clone();
577        spawn_blocking(move || {
578            symlink(
579                original.as_ref(),
580                &clone.as_filelike_view::<std::fs::File>(),
581                link.as_ref(),
582            )
583        })
584        .await
585    }
586
587    #[cfg(windows)]
604    #[inline]
605    pub async fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(
606        &self,
607        original: P,
608        link: Q,
609    ) -> io::Result<()> {
610        let original = original.as_ref().to_path_buf();
611        let link = link.as_ref().to_path_buf();
612        let clone = self.clone();
613        spawn_blocking(move || {
614            symlink_file(
615                original.as_ref(),
616                &clone.as_filelike_view::<std::fs::File>(),
617                link.as_ref(),
618            )
619        })
620        .await
621    }
622
623    #[cfg(windows)]
640    #[inline]
641    pub async fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(
642        &self,
643        original: P,
644        link: Q,
645    ) -> io::Result<()> {
646        let original = original.as_ref().to_path_buf();
647        let link = link.as_ref().to_path_buf();
648        let clone = self.clone();
649        spawn_blocking(move || {
650            symlink_dir(
651                original.as_ref(),
652                &clone.as_filelike_view::<std::fs::File>(),
653                link.as_ref(),
654            )
655        })
656        .await
657    }
658
659    #[doc(alias = "bind")]
668    #[cfg(unix)]
669    #[inline]
670    pub async fn bind_unix_listener<P: AsRef<Path>>(&self, path: P) -> io::Result<UnixListener> {
671        todo!(
672            "Dir::bind_unix_listener({:?}, {})",
673            self.std_file,
674            path.as_ref().display()
675        )
676    }
677
678    #[doc(alias = "connect")]
687    #[cfg(unix)]
688    #[inline]
689    pub async fn connect_unix_stream<P: AsRef<Path>>(&self, path: P) -> io::Result<UnixStream> {
690        todo!(
691            "Dir::connect_unix_stream({:?}, {})",
692            self.std_file,
693            path.as_ref().display()
694        )
695    }
696
697    #[doc(alias = "bind")]
706    #[cfg(unix)]
707    #[inline]
708    pub async fn bind_unix_datagram<P: AsRef<Path>>(&self, path: P) -> io::Result<UnixDatagram> {
709        todo!(
710            "Dir::bind_unix_datagram({:?}, {})",
711            self.std_file,
712            path.as_ref().display()
713        )
714    }
715
716    #[doc(alias = "connect")]
726    #[cfg(unix)]
727    #[inline]
728    pub async fn connect_unix_datagram<P: AsRef<Path>>(
729        &self,
730        _unix_datagram: &UnixDatagram,
731        path: P,
732    ) -> io::Result<()> {
733        todo!(
734            "Dir::connect_unix_datagram({:?}, {})",
735            self.std_file,
736            path.as_ref().display()
737        )
738    }
739
740    #[doc(alias = "send_to")]
750    #[cfg(unix)]
751    #[inline]
752    pub async fn send_to_unix_datagram_addr<P: AsRef<Path>>(
753        &self,
754        _unix_datagram: &UnixDatagram,
755        buf: &[u8],
756        path: P,
757    ) -> io::Result<usize> {
758        todo!(
759            "Dir::send_to_unix_datagram_addr({:?}, {:?}, {})",
760            self.std_file,
761            buf,
762            path.as_ref().display()
763        )
764    }
765
766    #[inline]
773    pub async fn exists<P: AsRef<Path>>(&self, path: P) -> bool {
774        self.metadata(path).await.is_ok()
775    }
776
777    #[inline]
784    pub async fn try_exists<P: AsRef<Path>>(&self, path: P) -> io::Result<bool> {
785        match self.metadata(path.as_ref()).await {
786            Ok(_) => Ok(true),
787            Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),
788            Err(e) => Err(e),
789        }
790    }
791
792    #[inline]
798    pub async fn is_file<P: AsRef<Path>>(&self, path: P) -> bool {
799        self.metadata(path)
800            .await
801            .map(|m| m.is_file())
802            .unwrap_or(false)
803    }
804
805    #[inline]
812    pub async fn is_dir<P: AsRef<Path>>(&self, path: P) -> bool {
813        self.metadata(path)
814            .await
815            .map(|m| m.is_dir())
816            .unwrap_or(false)
817    }
818
819    #[inline]
821    fn is_dir_blocking<P: AsRef<Path>>(&self, path: P) -> bool {
822        self.metadata_blocking(path)
823            .map(|m| m.is_dir())
824            .unwrap_or(false)
825    }
826
827    #[inline]
835    pub async fn open_ambient_dir<P: AsRef<Path>>(
836        path: P,
837        ambient_authority: AmbientAuthority,
838    ) -> io::Result<Self> {
839        let path = path.as_ref().to_path_buf();
840        spawn_blocking(move || open_ambient_dir(path.as_ref(), ambient_authority))
841            .await
842            .map(|f| Self::from_std_file(f.into()))
843    }
844
845    #[inline]
852    pub async fn open_parent_dir(&self, ambient_authority: AmbientAuthority) -> io::Result<Self> {
853        let clone = self.clone();
854        let dir = spawn_blocking(move || {
855            open_parent_dir(
856                &*clone.as_filelike_view::<std::fs::File>(),
857                ambient_authority,
858            )
859        })
860        .await?
861        .into();
862        Ok(Self::from_std_file(dir))
863    }
864
865    #[inline]
873    pub async fn create_ambient_dir_all<P: AsRef<Path>>(
874        path: P,
875        ambient_authority: AmbientAuthority,
876    ) -> io::Result<()> {
877        let _ = ambient_authority;
878        let path = path.as_ref().to_path_buf();
879        fs::create_dir_all(path).await
880    }
881
882    pub async fn reopen_dir<Filelike: AsFilelike + Send>(dir: &Filelike) -> io::Result<Self> {
889        let raw_filelike = dir.as_filelike_view::<std::fs::File>().as_raw_filelike();
893        let file = ManuallyDrop::new(unsafe { std::fs::File::from_raw_filelike(raw_filelike) });
896        let dir = spawn_blocking(move || {
897            cap_primitives::fs::open_dir(&*file, std::path::Component::CurDir.as_ref())
898        })
899        .await?
900        .into();
901        Ok(Self::from_std_file(dir))
902    }
903}
904
905#[cfg(not(target_os = "wasi"))]
906#[inline]
907fn metadata_from(file: &std::fs::File) -> io::Result<Metadata> {
908    Metadata::from_file(file)
909}
910
911#[cfg(target_os = "wasi")]
912#[inline]
913fn metadata_from(file: &std::fs::File) -> io::Result<Metadata> {
914    file.metadata()
915}
916
917unsafe impl io_lifetimes::views::FilelikeViewType for Dir {}
919
920#[cfg(not(windows))]
921impl FromRawFd for Dir {
922    #[inline]
923    unsafe fn from_raw_fd(fd: RawFd) -> Self {
924        Self::from_std_file(fs::File::from_raw_fd(fd))
925    }
926}
927
928#[cfg(not(windows))]
929impl From<OwnedFd> for Dir {
930    #[inline]
931    fn from(fd: OwnedFd) -> Self {
932        Self::from_std_file(fs::File::from(fd))
933    }
934}
935
936#[cfg(windows)]
937impl FromRawHandle for Dir {
938    #[inline]
941    unsafe fn from_raw_handle(handle: RawHandle) -> Self {
942        Self::from_std_file(fs::File::from_raw_handle(handle))
943    }
944}
945
946#[cfg(windows)]
947impl From<OwnedHandle> for Dir {
948    #[inline]
949    fn from(handle: OwnedHandle) -> Self {
950        Self::from_std_file(fs::File::from(handle))
951    }
952}
953
954#[cfg(not(windows))]
955impl AsRawFd for Dir {
956    #[inline]
957    fn as_raw_fd(&self) -> RawFd {
958        self.std_file.as_raw_fd()
959    }
960}
961
962#[cfg(not(windows))]
963impl AsFd for Dir {
964    #[inline]
965    fn as_fd(&self) -> BorrowedFd<'_> {
966        self.std_file.as_fd()
967    }
968}
969
970#[cfg(windows)]
971impl AsRawHandle for Dir {
972    #[inline]
973    fn as_raw_handle(&self) -> RawHandle {
974        self.std_file.as_raw_handle()
975    }
976}
977
978#[cfg(windows)]
979impl AsHandle for Dir {
980    #[inline]
981    fn as_handle(&self) -> BorrowedHandle<'_> {
982        self.std_file.as_handle()
983    }
984}
985
986#[cfg(windows)]
987impl AsRawHandleOrSocket for Dir {
988    #[inline]
989    fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
990        self.std_file.as_raw_handle_or_socket()
991    }
992}
993
994#[cfg(windows)]
995impl AsHandleOrSocket for Dir {
996    #[inline]
997    fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> {
998        self.std_file.as_handle_or_socket()
999    }
1000}
1001
1002#[cfg(not(windows))]
1003impl IntoRawFd for Dir {
1004    #[inline]
1005    fn into_raw_fd(self) -> RawFd {
1006        self.std_file.into_raw_fd()
1007    }
1008}
1009
1010#[cfg(not(windows))]
1011impl From<Dir> for OwnedFd {
1012    #[inline]
1013    fn from(dir: Dir) -> OwnedFd {
1014        dir.std_file.into()
1015    }
1016}
1017
1018#[cfg(windows)]
1019impl IntoRawHandle for Dir {
1020    #[inline]
1021    fn into_raw_handle(self) -> RawHandle {
1022        self.std_file.into_raw_handle()
1023    }
1024}
1025
1026#[cfg(windows)]
1027impl From<Dir> for OwnedHandle {
1028    #[inline]
1029    fn from(dir: Dir) -> OwnedHandle {
1030        dir.std_file.into()
1031    }
1032}
1033
1034#[cfg(windows)]
1035impl IntoRawHandleOrSocket for Dir {
1036    #[inline]
1037    fn into_raw_handle_or_socket(self) -> RawHandleOrSocket {
1038        self.std_file.into_raw_handle_or_socket()
1039    }
1040}
1041
1042#[cfg(windows)]
1043impl From<Dir> for OwnedHandleOrSocket {
1044    #[inline]
1045    fn from(dir: Dir) -> Self {
1046        dir.std_file.into()
1047    }
1048}
1049
1050async fn initial_buffer_size(file: &File) -> usize {
1056    file.metadata()
1060        .await
1061        .map(|m| m.len() as usize + 1)
1062        .unwrap_or(0)
1063}
1064
1065impl fmt::Debug for Dir {
1066    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1068        let mut b = f.debug_struct("Dir");
1069        #[cfg(not(windows))]
1070        b.field("fd", &self.std_file.as_raw_fd());
1071        #[cfg(windows)]
1072        b.field("handle", &self.std_file.as_raw_handle());
1073        b.finish()
1074    }
1075}