1use std::borrow::Cow;
2use std::ffi::OsStr;
3use std::io;
4use std::path::Path;
5use std::time::SystemTime;
6
7use crate::BaseFsMetadata;
8use crate::BaseFsOpen;
9use crate::BaseFsReadDir;
10use crate::FileType;
11use crate::FsDirEntry;
12use crate::FsFile;
13use crate::FsFileAsRaw;
14use crate::FsFileIsTerminal;
15use crate::FsFileLock;
16use crate::FsFileLockMode;
17use crate::FsFileSetLen;
18use crate::FsFileSetPermissions;
19use crate::FsFileSetTimes;
20use crate::FsFileSyncAll;
21use crate::FsFileSyncData;
22use crate::FsFileTimes;
23use crate::FsMetadataValue;
24use crate::OpenOptions;
25
26pub struct BoxedFsFile(pub Box<dyn FsFile + 'static>);
29
30impl io::Read for BoxedFsFile {
31 #[inline]
32 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
33 self.0.read(buf)
34 }
35}
36
37impl io::Seek for BoxedFsFile {
38 #[inline]
39 fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
40 self.0.seek(pos)
41 }
42}
43
44impl io::Write for BoxedFsFile {
45 #[inline]
46 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
47 self.0.write(buf)
48 }
49
50 #[inline]
51 fn flush(&mut self) -> io::Result<()> {
52 self.0.flush()
53 }
54}
55
56impl FsFileAsRaw for BoxedFsFile {
57 #[cfg(windows)]
58 #[inline]
59 fn fs_file_as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> {
60 self.0.fs_file_as_raw_handle()
61 }
62
63 #[cfg(unix)]
66 #[inline]
67 fn fs_file_as_raw_fd(&self) -> Option<std::os::fd::RawFd> {
68 self.0.fs_file_as_raw_fd()
69 }
70}
71
72impl FsFileIsTerminal for BoxedFsFile {
73 #[inline]
74 fn fs_file_is_terminal(&self) -> bool {
75 self.0.fs_file_is_terminal()
76 }
77}
78
79impl FsFileLock for BoxedFsFile {
80 #[inline]
81 fn fs_file_lock(&mut self, mode: FsFileLockMode) -> io::Result<()> {
82 self.0.fs_file_lock(mode)
83 }
84 #[inline]
85 fn fs_file_try_lock(&mut self, mode: FsFileLockMode) -> io::Result<()> {
86 self.0.fs_file_try_lock(mode)
87 }
88 #[inline]
89 fn fs_file_unlock(&mut self) -> io::Result<()> {
90 self.0.fs_file_unlock()
91 }
92}
93
94impl FsFileSetLen for BoxedFsFile {
95 #[inline]
96 fn fs_file_set_len(&mut self, size: u64) -> io::Result<()> {
97 self.0.fs_file_set_len(size)
98 }
99}
100
101impl FsFileSetPermissions for BoxedFsFile {
102 #[inline]
103 fn fs_file_set_permissions(&mut self, perm: u32) -> io::Result<()> {
104 self.0.fs_file_set_permissions(perm)
105 }
106}
107
108impl FsFileSetTimes for BoxedFsFile {
109 #[inline]
110 fn fs_file_set_times(&mut self, times: FsFileTimes) -> io::Result<()> {
111 self.0.fs_file_set_times(times)
112 }
113}
114
115impl FsFileSyncAll for BoxedFsFile {
116 #[inline]
117 fn fs_file_sync_all(&mut self) -> io::Result<()> {
118 self.0.fs_file_sync_all()
119 }
120}
121
122impl FsFileSyncData for BoxedFsFile {
123 #[inline]
124 fn fs_file_sync_data(&mut self) -> io::Result<()> {
125 self.0.fs_file_sync_data()
126 }
127}
128
129impl FsFile for BoxedFsFile {}
130
131pub trait FsOpenBoxed {
132 fn fs_open_boxed(
133 &self,
134 path: &Path,
135 open_options: &OpenOptions,
136 ) -> io::Result<BoxedFsFile>;
137}
138
139impl<TFile: FsFile + 'static, T: BaseFsOpen<File = TFile>> FsOpenBoxed for T {
140 fn fs_open_boxed(
141 &self,
142 path: &Path,
143 open_options: &OpenOptions,
144 ) -> io::Result<BoxedFsFile> {
145 self
146 .base_fs_open(path, open_options)
147 .map(|file| BoxedFsFile(Box::new(file)))
148 }
149}
150
151#[derive(Debug)]
154pub struct BoxedFsMetadataValue(pub Box<dyn FsMetadataValue>);
155
156impl BoxedFsMetadataValue {
157 pub fn new<T: FsMetadataValue + 'static>(metadata: T) -> Self {
158 Self(Box::new(metadata))
159 }
160}
161
162impl FsMetadataValue for BoxedFsMetadataValue {
163 #[inline]
164 fn file_type(&self) -> FileType {
165 self.0.file_type()
166 }
167
168 #[inline]
169 fn len(&self) -> u64 {
170 self.0.len()
171 }
172
173 #[inline]
174 fn accessed(&self) -> io::Result<SystemTime> {
175 self.0.accessed()
176 }
177
178 #[inline]
179 fn changed(&self) -> io::Result<SystemTime> {
180 self.0.changed()
181 }
182
183 #[inline]
184 fn created(&self) -> io::Result<SystemTime> {
185 self.0.created()
186 }
187
188 #[inline]
189 fn modified(&self) -> io::Result<SystemTime> {
190 self.0.modified()
191 }
192
193 #[inline]
194 fn dev(&self) -> io::Result<u64> {
195 self.0.dev()
196 }
197
198 #[inline]
199 fn ino(&self) -> io::Result<u64> {
200 self.0.ino()
201 }
202
203 #[inline]
204 fn mode(&self) -> io::Result<u32> {
205 self.0.mode()
206 }
207
208 #[inline]
209 fn nlink(&self) -> io::Result<u64> {
210 self.0.nlink()
211 }
212
213 #[inline]
214 fn uid(&self) -> io::Result<u32> {
215 self.0.uid()
216 }
217
218 #[inline]
219 fn gid(&self) -> io::Result<u32> {
220 self.0.gid()
221 }
222
223 #[inline]
224 fn rdev(&self) -> io::Result<u64> {
225 self.0.rdev()
226 }
227
228 #[inline]
229 fn blksize(&self) -> io::Result<u64> {
230 self.0.blksize()
231 }
232
233 #[inline]
234 fn blocks(&self) -> io::Result<u64> {
235 self.0.blocks()
236 }
237
238 #[inline]
239 fn is_block_device(&self) -> io::Result<bool> {
240 self.0.is_block_device()
241 }
242
243 #[inline]
244 fn is_char_device(&self) -> io::Result<bool> {
245 self.0.is_char_device()
246 }
247
248 #[inline]
249 fn is_fifo(&self) -> io::Result<bool> {
250 self.0.is_fifo()
251 }
252
253 #[inline]
254 fn is_socket(&self) -> io::Result<bool> {
255 self.0.is_socket()
256 }
257
258 #[inline]
259 fn file_attributes(&self) -> io::Result<u32> {
260 self.0.file_attributes()
261 }
262}
263
264pub trait FsMetadataBoxed {
265 fn fs_metadata_boxed(&self, path: &Path) -> io::Result<BoxedFsMetadataValue>;
266 fn fs_symlink_metadata_boxed(
267 &self,
268 path: &Path,
269 ) -> io::Result<BoxedFsMetadataValue>;
270}
271
272impl<T: BaseFsMetadata + 'static> FsMetadataBoxed for T {
273 fn fs_metadata_boxed(&self, path: &Path) -> io::Result<BoxedFsMetadataValue> {
274 let metadata = self.base_fs_metadata(path)?;
275 Ok(BoxedFsMetadataValue(Box::new(metadata)))
276 }
277
278 fn fs_symlink_metadata_boxed(
279 &self,
280 path: &Path,
281 ) -> io::Result<BoxedFsMetadataValue> {
282 let metadata = self.base_fs_symlink_metadata(path)?;
283 Ok(BoxedFsMetadataValue(Box::new(metadata)))
284 }
285}
286
287#[derive(Debug)]
290struct MappedMetadataFsDirEntry<T: FsDirEntry + 'static>(T);
291
292impl<T: FsDirEntry + 'static> FsDirEntry for MappedMetadataFsDirEntry<T> {
293 type Metadata = BoxedFsMetadataValue;
294
295 #[inline]
296 fn file_name(&self) -> Cow<OsStr> {
297 self.0.file_name()
298 }
299
300 #[inline]
301 fn file_type(&self) -> io::Result<FileType> {
302 self.0.file_type()
303 }
304
305 #[inline]
306 fn metadata(&self) -> io::Result<Self::Metadata> {
307 self
308 .0
309 .metadata()
310 .map(|metadata| BoxedFsMetadataValue(Box::new(metadata)))
311 }
312
313 #[inline]
314 fn path(&self) -> Cow<Path> {
315 self.0.path()
316 }
317}
318
319#[derive(Debug)]
320pub struct BoxedFsDirEntry(
321 pub Box<dyn FsDirEntry<Metadata = BoxedFsMetadataValue>>,
322);
323
324impl BoxedFsDirEntry {
325 pub fn new<T: FsDirEntry + 'static>(entry: T) -> Self {
326 Self(Box::new(MappedMetadataFsDirEntry(entry)))
327 }
328}
329
330impl FsDirEntry for BoxedFsDirEntry {
331 type Metadata = BoxedFsMetadataValue;
332
333 #[inline]
334 fn file_name(&self) -> Cow<OsStr> {
335 self.0.file_name()
336 }
337
338 #[inline]
339 fn file_type(&self) -> io::Result<FileType> {
340 self.0.file_type()
341 }
342
343 #[inline]
344 fn metadata(&self) -> io::Result<Self::Metadata> {
345 self.0.metadata()
346 }
347
348 #[inline]
349 fn path(&self) -> Cow<Path> {
350 self.0.path()
351 }
352}
353
354pub trait FsReadDirBoxed {
355 fn fs_read_dir_boxed(
356 &self,
357 path: &Path,
358 ) -> io::Result<Box<dyn Iterator<Item = io::Result<BoxedFsDirEntry>> + '_>>;
359}
360
361impl<T: BaseFsReadDir> FsReadDirBoxed for T {
362 fn fs_read_dir_boxed(
363 &self,
364 path: &Path,
365 ) -> io::Result<Box<dyn Iterator<Item = io::Result<BoxedFsDirEntry>> + '_>>
366 {
367 let iter = self.base_fs_read_dir(path)?;
368 Ok(Box::new(
369 iter.map(|result| result.map(BoxedFsDirEntry::new)),
370 ))
371 }
372}