dir_structure/vfs/
fs_vfs.rs

1//! A [`Vfs`] and [`WriteSupportingVfs`] implementation built upon the [`std::fs`] APIs.
2//!
3//! Main item is the [`FsVfs`] struct.
4
5use std::fs;
6use std::path::Path;
7use std::path::PathBuf;
8use std::pin::Pin;
9
10use crate::error::Result;
11use crate::error::VfsResult;
12use crate::error::WrapIoError;
13use crate::traits::vfs::DirEntryInfo;
14use crate::traits::vfs::DirEntryKind;
15use crate::traits::vfs::DirWalker;
16use crate::traits::vfs::PathType;
17use crate::traits::vfs::Vfs;
18use crate::traits::vfs::VfsCore;
19use crate::traits::vfs::WriteSupportingVfs;
20
21/// A [`Vfs`] and [`WriteSupportingVfs`] implementation built upon the [`std::fs`] APIs.
22#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
23pub struct FsVfs;
24
25impl VfsCore for FsVfs {
26    type Path = Path;
27}
28
29impl<'a> Vfs<'a> for FsVfs {
30    type DirWalk<'b>
31        = imp::FsDirWalker
32    where
33        'a: 'b,
34        Self: 'b;
35
36    type RFile = fs::File;
37
38    fn open_read(self: Pin<&Self>, path: &Self::Path) -> VfsResult<Self::RFile, Self> {
39        fs::File::open(path).wrap_io_error_with(path)
40    }
41
42    fn read(self: Pin<&Self>, path: &Self::Path) -> VfsResult<Vec<u8>, Self> {
43        fs::read(path).wrap_io_error_with(path)
44    }
45
46    fn read_string(self: Pin<&Self>, path: &Self::Path) -> VfsResult<String, Self> {
47        fs::read_to_string(path).wrap_io_error_with(path)
48    }
49
50    fn exists(self: Pin<&Self>, path: &Self::Path) -> VfsResult<bool, Self> {
51        Ok(path.exists())
52    }
53
54    fn is_dir(self: Pin<&Self>, path: &Self::Path) -> VfsResult<bool, Self> {
55        Ok(path.is_dir())
56    }
57
58    fn walk_dir<'b>(self: Pin<&'b Self>, path: &Self::Path) -> VfsResult<Self::DirWalk<'b>, Self>
59    where
60        'a: 'b,
61    {
62        fs::read_dir(path)
63            .wrap_io_error_with(path)
64            .map(|read_dir| imp::FsDirWalker(read_dir, path.to_path_buf()))
65    }
66}
67
68impl<'a> WriteSupportingVfs<'a> for FsVfs {
69    type WFile = fs::File;
70
71    fn open_write(self: Pin<&Self>, path: &Self::Path) -> VfsResult<Self::WFile, Self> {
72        fs::File::create(path).wrap_io_error_with(path)
73    }
74
75    fn write(self: Pin<&Self>, path: &Self::Path, data: &[u8]) -> VfsResult<(), Self> {
76        fs::write(path, data).wrap_io_error_with(path)
77    }
78
79    fn create_dir(self: Pin<&Self>, path: &Self::Path) -> VfsResult<(), Self> {
80        fs::create_dir(path).wrap_io_error_with(path)
81    }
82
83    fn create_dir_all(self: Pin<&Self>, path: &Self::Path) -> VfsResult<(), Self> {
84        fs::create_dir_all(path).wrap_io_error_with(path)
85    }
86
87    fn remove_dir_all(self: Pin<&Self>, path: &Self::Path) -> VfsResult<(), Self> {
88        fs::remove_dir_all(path).wrap_io_error_with(path)
89    }
90
91    fn create_parent_dir(self: Pin<&Self>, path: &Self::Path) -> VfsResult<(), Self> {
92        if let Some(parent) = path.parent()
93            && !self.exists(parent)?
94        {
95            self.create_dir_all(parent)?;
96        }
97        Ok(())
98    }
99}
100
101mod imp {
102    use std::io;
103
104    use super::*;
105
106    /// The [`DirWalker`] implementation for the file system.
107    pub struct FsDirWalker(pub(super) fs::ReadDir, pub(super) PathBuf);
108
109    impl<'a> DirWalker<'a> for FsDirWalker {
110        type P = Path;
111
112        fn next(
113            &mut self,
114        ) -> Option<Result<DirEntryInfo<Self::P>, <Self::P as PathType>::OwnedPath>> {
115            self.0.next().map(|entry| {
116                <io::Result<_> as WrapIoError<Self::P>>::wrap_io_error(
117                    entry.and_then(|e| {
118                        Ok(DirEntryInfo {
119                            name: e.file_name(),
120                            path: e.path(),
121                            kind: if e.file_type()?.is_dir() {
122                                DirEntryKind::Directory
123                            } else {
124                                DirEntryKind::File
125                            },
126                        })
127                    }),
128                    || self.1.clone(),
129                )
130            })
131        }
132    }
133}