1use std::io;
59use std::pin::Pin;
60use std::task::Context;
61use std::task::Poll;
62
63use futures::AsyncWrite;
64use futures::Stream;
65use futures::io::AsyncRead;
66use futures::io::AsyncSeek;
67use pin_project::pin_project;
68
69use crate::error::Error;
70use crate::error::Result;
71use crate::error::VfsResult;
72#[cfg(feature = "image")]
73use crate::image::ImgFormat;
74use crate::prelude::*;
75use crate::traits::vfs::DirEntryInfo;
76use crate::traits::vfs::OwnedPathType;
77use crate::traits::vfs::PathType;
78use crate::traits::vfs::VfsCore;
79
80pub trait VfsAsync: VfsCore + Send + Sync + Unpin {
86 type RFile: AsyncRead + Send + Unpin;
88 type OpenReadFuture: Future<Output = VfsResult<Self::RFile, Self>> + Send + Unpin;
90
91 fn open_read(
93 self: Pin<&Self>,
94 path: <<Self as VfsCore>::Path as PathType>::OwnedPath,
95 ) -> Self::OpenReadFuture;
96
97 type ReadFuture<'a>: Future<Output = VfsResult<Vec<u8>, Self>> + Send + Unpin + 'a
99 where
100 Self: 'a;
101
102 fn read<'a>(
104 self: Pin<&'a Self>,
105 path: <<Self as VfsCore>::Path as PathType>::OwnedPath,
106 ) -> Self::ReadFuture<'a>;
107
108 type ReadStringFuture<'a>: Future<Output = VfsResult<String, Self>> + Send + Unpin + 'a
110 where
111 Self: 'a;
112
113 fn read_string<'a>(
115 self: Pin<&'a Self>,
116 path: <<Self as VfsCore>::Path as PathType>::OwnedPath,
117 ) -> Self::ReadStringFuture<'a>;
118
119 type ExistsFuture<'a>: Future<Output = VfsResult<bool, Self>> + Send + 'a
121 where
122 Self: 'a;
123
124 fn exists<'a>(
126 self: Pin<&'a Self>,
127 path: <<Self as VfsCore>::Path as PathType>::OwnedPath,
128 ) -> Self::ExistsFuture<'a>;
129
130 type IsDirFuture<'a>: Future<Output = VfsResult<bool, Self>> + Send + 'a
132 where
133 Self: 'a;
134
135 fn is_dir<'a>(
137 self: Pin<&'a Self>,
138 path: <<Self as VfsCore>::Path as PathType>::OwnedPath,
139 ) -> Self::IsDirFuture<'a>;
140
141 type DirWalk<'a>: Stream<Item = VfsResult<DirEntryInfo<<Self as VfsCore>::Path>, Self>>
143 + Send
144 + 'a
145 where
146 Self: 'a;
147
148 type DirWalkFuture<'a>: Future<Output = VfsResult<Self::DirWalk<'a>, Self>> + Send + 'a
150 where
151 Self: 'a;
152
153 fn walk_dir<'a>(
155 self: Pin<&'a Self>,
156 path: <<Self as VfsCore>::Path as PathType>::OwnedPath,
157 ) -> Self::DirWalkFuture<'a>;
158}
159
160pub trait VfsAsyncWithSeekRead: VfsAsync
166where
167 Self::RFile: AsyncSeek + Send + Unpin,
168{
169}
170
171impl<T: VfsAsync> VfsAsyncWithSeekRead for T where T::RFile: AsyncSeek + Send + Unpin {}
172
173pub trait VfsAsyncExt: VfsAsync {
175 fn read_typed_async_pinned<'a, T: ReadFromAsync<'a, Self>>(
181 self: Pin<&'a Self>,
182 path: impl Into<<<Self as VfsCore>::Path as PathType>::OwnedPath>,
183 ) -> T::Future {
184 T::read_from_async(path.into(), self)
185 }
186
187 fn read_typed_async<'a, T: ReadFromAsync<'a, Self>>(
192 &'a self,
193 path: impl Into<<<Self as VfsCore>::Path as PathType>::OwnedPath>,
194 ) -> T::Future {
195 Pin::new(self).read_typed_async_pinned::<T>(path)
196 }
197}
198
199impl<V: VfsAsync + ?Sized> VfsAsyncExt for V {}
201
202pub trait WriteSupportingVfsAsync: VfsAsync {
204 type WFile: AsyncWrite + Send + Unpin;
206
207 type OpenWriteFuture: Future<Output = VfsResult<Self::WFile, Self>> + Send + Unpin;
209
210 fn open_write(
212 self: Pin<&Self>,
213 path: <<Self as VfsCore>::Path as PathType>::OwnedPath,
214 ) -> Self::OpenWriteFuture;
215
216 type WriteFuture<'a>: Future<Output = VfsResult<(), Self>> + Send + Unpin + 'a
218 where
219 Self: 'a;
220
221 fn write<'d, 'a: 'd>(
223 self: Pin<&'a Self>,
224 path: <<Self as VfsCore>::Path as PathType>::OwnedPath,
225 data: &'d [u8],
226 ) -> Self::WriteFuture<'d>;
227
228 type RemoveDirAllFuture<'a>: Future<Output = VfsResult<(), Self>> + Send + 'a
230 where
231 Self: 'a;
232
233 fn remove_dir_all<'a>(
235 self: Pin<&'a Self>,
236 path: <<Self as VfsCore>::Path as PathType>::OwnedPath,
237 ) -> Self::RemoveDirAllFuture<'a>;
238
239 type CreateDirFuture<'a>: Future<Output = VfsResult<(), Self>> + Send + 'a
241 where
242 Self: 'a;
243 fn create_dir<'a>(
245 self: Pin<&'a Self>,
246 path: <<Self as VfsCore>::Path as PathType>::OwnedPath,
247 ) -> Self::CreateDirFuture<'a>;
248
249 type CreateDirAllFuture<'a>: Future<Output = VfsResult<(), Self>> + Send + 'a
251 where
252 Self: 'a;
253 fn create_dir_all<'a>(
255 self: Pin<&'a Self>,
256 path: <<Self as VfsCore>::Path as PathType>::OwnedPath,
257 ) -> Self::CreateDirAllFuture<'a>;
258
259 type CreateParentDirFuture<'a>: Future<Output = VfsResult<(), Self>> + Send + 'a
261 where
262 Self: 'a;
263 fn create_parent_dir<'a>(
265 self: Pin<&'a Self>,
266 path: <<Self as VfsCore>::Path as PathType>::OwnedPath,
267 ) -> Self::CreateParentDirFuture<'a>;
268}
269
270pub trait VfsAsyncWithSeekWrite: WriteSupportingVfsAsync
274where
275 Self::WFile: AsyncSeek + Send + Unpin,
276{
277}
278
279impl<T: WriteSupportingVfsAsync> VfsAsyncWithSeekWrite for T where T::WFile: AsyncSeek + Send + Unpin
280{}
281
282pub trait WriteSupportingVfsAsyncExt: WriteSupportingVfsAsync {
284 fn write_typed_async_ref_pinned<'r, 'a: 'r, T: WriteToAsyncRef<'a, Self>>(
290 self: Pin<&'r Self>,
291 path: impl Into<<<Self as VfsCore>::Path as PathType>::OwnedPath>,
292 value: &'r T,
293 ) -> T::Future<'r> {
294 T::write_to_async_ref(value, path.into(), self)
295 }
296
297 fn write_typed_async_ref<'r, 'a: 'r, T: WriteToAsyncRef<'a, Self>>(
302 &'r self,
303 path: impl Into<<<Self as VfsCore>::Path as PathType>::OwnedPath>,
304 data: &'r T,
305 ) -> T::Future<'r>
306 where
307 Self: Unpin,
308 {
309 Pin::new(self).write_typed_async_ref_pinned(path, data)
310 }
311
312 fn write_typed_async_pinned<'a, T: WriteToAsync<'a, Self>>(
318 self: Pin<&'a Self>,
319 path: impl Into<<<Self as VfsCore>::Path as PathType>::OwnedPath>,
320 value: T,
321 ) -> T::Future {
322 value.write_to_async(path.into(), self)
323 }
324
325 fn write_typed_async<'a, T: WriteToAsync<'a, Self>>(
330 &'a self,
331 path: impl Into<<<Self as VfsCore>::Path as PathType>::OwnedPath>,
332 value: T,
333 ) -> T::Future
334 where
335 Self: Unpin,
336 {
337 Pin::new(self).write_typed_async_pinned(path, value)
338 }
339}
340
341impl<V: WriteSupportingVfsAsync + ?Sized> WriteSupportingVfsAsyncExt for V {}
343
344#[pin_project(project_replace = CreateParentDirDefaultFutureProjOwn)]
345#[doc(hidden)]
346pub enum CreateParentDirDefaultFuture<'a, Vfs: WriteSupportingVfsAsync + 'a>
347where
348 for<'f> Vfs::ExistsFuture<'f>: Future<Output = VfsResult<bool, Vfs>> + Unpin,
349 for<'f> Vfs::CreateDirAllFuture<'f>: Future<Output = VfsResult<(), Vfs>> + Unpin,
350{
351 Poison,
352 Start {
353 vfs: Pin<&'a Vfs>,
354 path: <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
355 },
356 ExistsFuture {
357 vfs: Pin<&'a Vfs>,
358 path: <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
359 exists_future: Vfs::ExistsFuture<'a>,
360 },
361 CreateDirAllFuture {
362 vfs: Pin<&'a Vfs>,
363 create_dir_all_future: Vfs::CreateDirAllFuture<'a>,
364 },
365}
366
367impl<'a, Vfs: WriteSupportingVfsAsync + 'a> Future for CreateParentDirDefaultFuture<'a, Vfs>
368where
369 for<'f> Vfs::ExistsFuture<'f>: Future<Output = VfsResult<bool, Vfs>> + Unpin,
370 for<'f> Vfs::CreateDirAllFuture<'f>: Future<Output = VfsResult<(), Vfs>> + Unpin,
371{
372 type Output = VfsResult<(), Vfs>;
373
374 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
375 let this = self.as_mut().project_replace(Self::Poison);
376 match this {
377 CreateParentDirDefaultFutureProjOwn::Start { vfs, path } => {
378 self.project_replace(Self::ExistsFuture {
379 exists_future: vfs.exists(path.clone()),
380 vfs,
381 path,
382 });
383 cx.waker().wake_by_ref();
384 Poll::Pending
385 }
386 CreateParentDirDefaultFutureProjOwn::ExistsFuture {
387 vfs,
388 path,
389 mut exists_future,
390 } => match Pin::new(&mut exists_future).poll(cx) {
391 Poll::Ready(Ok(true)) => Poll::Ready(Ok(())),
392 Poll::Ready(Ok(false)) => {
393 self.project_replace(Self::CreateDirAllFuture {
394 create_dir_all_future: vfs.create_dir_all(path),
395 vfs,
396 });
397 cx.waker().wake_by_ref();
398 Poll::Pending
399 }
400 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
401 Poll::Pending => {
402 self.project_replace(Self::ExistsFuture {
403 vfs,
404 path,
405 exists_future,
406 });
407 Poll::Pending
408 }
409 },
410 CreateParentDirDefaultFutureProjOwn::CreateDirAllFuture {
411 vfs,
412 mut create_dir_all_future,
413 } => match Pin::new(&mut create_dir_all_future).poll(cx) {
414 Poll::Ready(Ok(())) => Poll::Ready(Ok(())),
415 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
416 Poll::Pending => {
417 self.project_replace(Self::CreateDirAllFuture {
418 vfs,
419 create_dir_all_future,
420 });
421 Poll::Pending
422 }
423 },
424 CreateParentDirDefaultFutureProjOwn::Poison => {
425 panic!("CreateParentDirDefaultFuture polled after completion")
426 }
427 }
428 }
429}
430
431#[pin_project(project = IoErrorWrapperFutureProj)]
432#[doc(hidden)]
433pub struct IoErrorWrapperFuture<T, F: Future<Output = io::Result<T>>, P: OwnedPathType> {
434 #[pin]
435 future: F,
436 path: P,
437}
438
439impl<T, F, P> IoErrorWrapperFuture<T, F, P>
440where
441 F: Future<Output = io::Result<T>>,
442 P: OwnedPathType,
443{
444 pub fn new(path: P, future: F) -> Self {
445 Self { future, path }
446 }
447}
448
449impl<T, F, P> Future for IoErrorWrapperFuture<T, F, P>
450where
451 F: Future<Output = io::Result<T>>,
452 P: OwnedPathType + Clone,
453{
454 type Output = Result<T, P>;
455
456 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
457 let this = self.as_mut().project();
458 match this.future.poll(cx) {
459 Poll::Ready(Ok(value)) => Poll::Ready(Ok(value)),
460 Poll::Ready(Err(e)) => {
461 let path = self.path.clone();
462 Poll::Ready(Err(Error::Io(path, e)))
463 }
464 Poll::Pending => Poll::Pending,
465 }
466 }
467}
468
469#[cfg(feature = "image")]
471#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
472pub trait ReadImageFromAsync<T>: VfsAsync
473where
474 T: ImgFormat,
475{
476 type ReadImageFuture<'a>: Future<Output = VfsResult<T, Self>> + Send + Unpin + 'a
478 where
479 Self: 'a;
480
481 fn read_image_async<'a>(
483 self: Pin<&'a Self>,
484 path: <Self::Path as PathType>::OwnedPath,
485 ) -> Self::ReadImageFuture<'a>;
486}
487
488#[cfg(feature = "image")]
489#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
490impl<'vfs, Vfs, T> ReadFromAsync<'vfs, Vfs> for T
491where
492 Vfs: VfsAsync + ReadImageFromAsync<T> + 'vfs,
493 T: ImgFormat + Send + 'vfs,
494{
495 type Future = <Vfs as ReadImageFromAsync<T>>::ReadImageFuture<'vfs>;
496
497 fn read_from_async(
498 path: <Vfs::Path as PathType>::OwnedPath,
499 vfs: Pin<&'vfs Vfs>,
500 ) -> Self::Future {
501 Vfs::read_image_async(vfs, path)
502 }
503}
504
505#[cfg(feature = "image")]
507#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
508pub trait WriteImageToAsync<'a>: WriteSupportingVfsAsync {
509 type WriteImageFuture: Future<Output = VfsResult<(), Self>> + Send + Unpin + 'a;
511
512 fn write_image_async(
514 self: Pin<&'a Self>,
515 path: <Self::Path as PathType>::OwnedPath,
516 image: image::DynamicImage,
517 format: image::ImageFormat,
518 ) -> Self::WriteImageFuture;
519}
520
521#[cfg(feature = "image")]
523#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
524impl<'a, Vfs> WriteToAsync<'a, Vfs> for (image::DynamicImage, image::ImageFormat)
525where
526 Vfs: WriteSupportingVfsAsync + WriteImageToAsync<'a> + 'a,
527{
528 type Future = Vfs::WriteImageFuture;
529
530 fn write_to_async(
531 self,
532 path: <Vfs::Path as PathType>::OwnedPath,
533 vfs: Pin<&'a Vfs>,
534 ) -> Self::Future {
535 let (image, format) = self;
536 vfs.write_image_async(path, image, format)
537 }
538}
539
540#[cfg(feature = "image")]
542#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
543pub trait WriteImageToAsyncRef<'a>: WriteSupportingVfsAsync {
544 type WriteImageRefFuture: Future<Output = VfsResult<(), Self>> + Send + Unpin + 'a;
546
547 fn write_image_async_ref(
549 self: Pin<&'a Self>,
550 path: <Self::Path as PathType>::OwnedPath,
551 image: &'a image::DynamicImage,
552 format: image::ImageFormat,
553 ) -> Self::WriteImageRefFuture;
554}
555
556#[cfg(feature = "image")]
558#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
559impl<'a, Vfs: 'a> WriteToAsync<'a, Vfs> for (&'a image::DynamicImage, image::ImageFormat)
560where
561 Vfs: WriteSupportingVfsAsync + WriteImageToAsyncRef<'a>,
562{
563 type Future = Vfs::WriteImageRefFuture;
564
565 fn write_to_async(
566 self,
567 path: <Vfs::Path as PathType>::OwnedPath,
568 vfs: Pin<&'a Vfs>,
569 ) -> Self::Future {
570 let (image, format) = self;
571 vfs.write_image_async_ref(path, image, format)
572 }
573}