1use core::fmt;
6use core::fmt::Debug;
7use core::hash;
8use std::io;
9use std::marker;
10use std::pin::Pin;
11#[cfg(feature = "async")]
12use std::task::Context;
13#[cfg(feature = "async")]
14use std::task::Poll;
15
16#[cfg(feature = "async")]
17use pin_project::pin_project;
18
19use crate::error::Error;
20use crate::error::Result;
21use crate::error::VfsResult;
22use crate::prelude::*;
23#[cfg(feature = "async")]
24use crate::traits::async_vfs::VfsAsync;
25#[cfg(feature = "async")]
26use crate::traits::async_vfs::WriteSupportingVfsAsync;
27#[cfg(feature = "resolve-path")]
28use crate::traits::resolve::DynamicHasField;
29#[cfg(feature = "resolve-path")]
30use crate::traits::resolve::HAS_FIELD_MAX_LEN;
31#[cfg(feature = "resolve-path")]
32use crate::traits::resolve::HasField;
33use crate::traits::vfs;
34#[cfg(feature = "resolve-path")]
35use crate::traits::vfs::OwnedPathType;
36use crate::traits::vfs::PathType;
37use crate::traits::vfs::VfsCore;
38use crate::vfs::fs_vfs;
39
40#[derive(Clone)]
49#[cfg_attr(feature = "assert_eq", derive(assert_eq::AssertEq))]
50pub struct DeferredRead<'a, T, Vfs: VfsCore = fs_vfs::FsVfs, const CHECK_ON_READ: bool = false>(
51 pub <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
52 #[cfg_attr(feature = "assert_eq", assert_eq(ignore))] Pin<&'a Vfs>,
53 #[cfg_attr(feature = "assert_eq", assert_eq(ignore))] marker::PhantomData<T>,
54);
55
56impl<'a, const CHECK_ON_READ: bool, T, Vfs: VfsCore> hash::Hash
57 for DeferredRead<'a, T, Vfs, CHECK_ON_READ>
58where
59 T: hash::Hash,
60 <Vfs::Path as PathType>::OwnedPath: hash::Hash,
61{
62 fn hash<H: hash::Hasher>(&self, state: &mut H) {
63 self.0.hash(state);
64 }
66}
67
68impl<'a, const CHECK_ON_READ: bool, T, Vfs: VfsCore<Path = P>, P> Debug
69 for DeferredRead<'a, T, Vfs, CHECK_ON_READ>
70where
71 T: Debug,
72 P: PathType + ?Sized,
73 P::OwnedPath: Debug,
74{
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 use std::any::type_name;
77 write!(
78 f,
79 "deferred{} {} @ {:?} (vfs = {})",
80 if CHECK_ON_READ { "[checked]" } else { "" },
81 type_name::<T>(),
82 self.0,
83 type_name::<Vfs>()
84 )
85 }
86}
87
88impl<'a, const CHECK_ON_READ: bool, T, Vfs: vfs::Vfs<'a>> ReadFrom<'a, Vfs>
89 for DeferredRead<'a, T, Vfs, CHECK_ON_READ>
90where
91 T: ReadFrom<'a, Vfs>,
92{
93 fn read_from(path: &Vfs::Path, vfs: Pin<&'a Vfs>) -> VfsResult<Self, Vfs>
94 where
95 Self: Sized,
96 {
97 if CHECK_ON_READ && !vfs.exists(path)? {
98 return Err(Error::Io(path.owned(), io::ErrorKind::NotFound.into()));
99 }
100
101 Ok(Self(path.owned(), vfs, marker::PhantomData))
102 }
103}
104
105#[cfg(feature = "async")]
106#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
107impl<'a, const CHECK_ON_READ: bool, T, Vfs: VfsAsync<Path = P> + 'static, P: PathType + ?Sized + 'a>
108 ReadFromAsync<'a, Vfs> for DeferredRead<'a, T, Vfs, CHECK_ON_READ>
109where
110 T: Send + ReadFromAsync<'a, Vfs> + 'static,
111{
112 type Future
113 = Pin<Box<dyn Future<Output = VfsResult<Self, Vfs>> + Send + 'a>>
114 where
115 Self: 'a;
116
117 fn read_from_async(path: P::OwnedPath, vfs: Pin<&'a Vfs>) -> Self::Future {
118 Box::pin(async move {
119 if CHECK_ON_READ && !vfs.exists(path.clone()).await? {
120 return Err(Error::Io(path, io::ErrorKind::NotFound.into()));
121 }
122
123 Ok(Self(path, vfs, marker::PhantomData))
124 })
125 }
126}
127
128impl<'a, const CHECK_ON_READ: bool, T, Vfs: vfs::Vfs<'a, Path = P>, P: PathType + ?Sized + 'a>
129 DeferredRead<'a, T, Vfs, CHECK_ON_READ>
130where
131 T: ReadFrom<'a, Vfs>,
132{
133 #[cfg_attr(feature = "derive", doc = "```rust")]
143 #[cfg_attr(not(feature = "derive"), doc = "```rust,compile_fail")]
144 pub fn perform_read(&self) -> VfsResult<T, Vfs> {
173 T::read_from(self.0.as_ref(), self.1)
174 }
175}
176
177#[cfg(feature = "async")]
178#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
179impl<'a, const CHECK_ON_READ: bool, T, Vfs: VfsAsync<Path = P> + 'a, P: PathType + ?Sized + 'a>
180 DeferredRead<'a, T, Vfs, CHECK_ON_READ>
181where
182 T: ReadFromAsync<'a, Vfs> + Send + 'static,
183{
184 pub async fn perform_read_async(&self) -> VfsResult<T, Vfs> {
193 T::read_from_async(self.0.clone(), self.1).await
194 }
195}
196
197impl<
198 'a,
199 't,
200 const CHECK_ON_READ: bool,
201 T,
202 P: PathType + ?Sized + 'a,
203 SelfVfs: vfs::Vfs<'a, Path = P>,
204 TargetVfs: vfs::WriteSupportingVfs<'t, Path = P>,
205> WriteTo<'t, TargetVfs> for DeferredRead<'a, T, SelfVfs, CHECK_ON_READ>
206where
207 T: ReadFrom<'a, SelfVfs> + WriteTo<'t, TargetVfs>,
208{
209 fn write_to(&self, path: &P, vfs: Pin<&'t TargetVfs>) -> Result<(), P::OwnedPath> {
210 if path == self.0.as_ref() {
211 return Ok(());
219 }
220
221 let r = self.perform_read()?;
222 r.write_to(path, vfs)
223 }
224}
225
226#[cfg(feature = "async")]
227#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
228#[pin_project(project_replace = DeferredReadWriteFutureProj)]
229#[doc(hidden)]
230pub enum DeferredReadWriteFuture<
231 'a,
232 T,
233 P: PathType + ?Sized + 'a,
234 SelfVfs: VfsAsync<Path = P> + 'a,
235 TargetVfs: WriteSupportingVfsAsync<Path = P> + 'a,
236> where
237 T: ReadFromAsync<'a, SelfVfs> + WriteToAsync<'a, TargetVfs> + Send + 'static,
238 <T as ReadFromAsync<'a, SelfVfs>>::Future: Future<Output = VfsResult<T, SelfVfs>> + Unpin + 'a,
239 <T as WriteToAsync<'a, TargetVfs>>::Future:
240 Future<Output = VfsResult<(), TargetVfs>> + Unpin + 'a,
241{
242 Poisson,
243 SamePath,
244 Reading {
245 self_vfs: Pin<&'a SelfVfs>,
246 target_vfs: Pin<&'a TargetVfs>,
247 inner: <T as ReadFromAsync<'a, SelfVfs>>::Future,
248 path: P::OwnedPath,
249 },
250 Writing {
251 inner: <T as WriteToAsync<'a, TargetVfs>>::Future,
252 },
253}
254
255#[cfg(feature = "async")]
256#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
257impl<
258 'a,
259 T,
260 P: PathType + ?Sized + 'a,
261 SelfVfs: VfsAsync<Path = P> + 'a,
262 TargetVfs: WriteSupportingVfsAsync<Path = P> + 'a,
263> Future for DeferredReadWriteFuture<'a, T, P, SelfVfs, TargetVfs>
264where
265 T: ReadFromAsync<'a, SelfVfs> + WriteToAsync<'a, TargetVfs> + Send + 'static,
266 <T as ReadFromAsync<'a, SelfVfs>>::Future: Future<Output = VfsResult<T, SelfVfs>> + Unpin,
267 <T as WriteToAsync<'a, TargetVfs>>::Future: Future<Output = VfsResult<(), TargetVfs>> + Unpin,
268{
269 type Output = Result<(), P::OwnedPath>;
270
271 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
272 let this = self.as_mut().project_replace(Self::Poisson);
273 match this {
274 DeferredReadWriteFutureProj::SamePath => Poll::Ready(Ok(())),
275 DeferredReadWriteFutureProj::Reading {
276 mut inner,
277 self_vfs,
278 target_vfs,
279 path,
280 } => match Pin::new(&mut inner).poll(cx) {
281 Poll::Ready(Ok(v)) => {
282 self.project_replace(Self::Writing {
283 inner: v.write_to_async(path, target_vfs),
284 });
285 cx.waker().wake_by_ref();
286 Poll::Pending
287 }
288 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
289 Poll::Pending => {
290 self.project_replace(Self::Reading {
291 inner,
292 path,
293 self_vfs,
294 target_vfs,
295 });
296 Poll::Pending
297 }
298 },
299 DeferredReadWriteFutureProj::Writing { mut inner } => {
300 match Pin::new(&mut inner).poll(cx) {
301 Poll::Ready(Ok(())) => Poll::Ready(Ok(())),
302 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
303 Poll::Pending => {
304 self.project_replace(Self::Writing { inner });
305 Poll::Pending
306 }
307 }
308 }
309 DeferredReadWriteFutureProj::Poisson => {
310 panic!(
311 "DeferredReadWriteFuture is in an invalid state. This is a bug in the code."
312 );
313 }
314 }
315 }
316}
317
318#[cfg(feature = "async")]
319#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
320impl<
321 'f,
322 const CHECK_ON_READ: bool,
323 T,
324 P: PathType + ?Sized + 'f,
325 SelfVfs: VfsAsync<Path = P> + 'f,
326 TargetVfs: WriteSupportingVfsAsync<Path = P> + 'f,
327> WriteToAsync<'f, TargetVfs> for DeferredRead<'f, T, SelfVfs, CHECK_ON_READ>
328where
329 T: for<'a> ReadFromAsync<'a, SelfVfs> + for<'a> WriteToAsync<'a, TargetVfs> + Send + 'static,
330 for<'a> <T as ReadFromAsync<'a, SelfVfs>>::Future:
331 Future<Output = VfsResult<T, SelfVfs>> + Unpin + 'a,
332 for<'a> <T as WriteToAsync<'a, TargetVfs>>::Future:
333 Future<Output = VfsResult<(), TargetVfs>> + Unpin + 'a,
334{
335 type Future = DeferredReadWriteFuture<'f, T, P, SelfVfs, TargetVfs>;
336
337 fn write_to_async(self, path: P::OwnedPath, vfs: Pin<&'f TargetVfs>) -> Self::Future {
338 if path == self.0 {
339 return DeferredReadWriteFuture::SamePath;
347 }
348
349 DeferredReadWriteFuture::Reading {
350 inner: T::read_from_async(self.0.clone(), self.1),
351 path,
352 self_vfs: self.1,
353 target_vfs: vfs,
354 }
355 }
356}
357
358#[cfg(feature = "async")]
359#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
360#[pin_project(project_replace = DeferredReadWriteRefFutureProj)]
361#[doc(hidden)]
362pub enum DeferredReadWriteRefFuture<
363 'f,
364 T,
365 P: PathType + ?Sized + 'f,
366 SelfVfs: VfsAsync<Path = P> + 'f,
367 TargetVfs: WriteSupportingVfsAsync<Path = P> + 'f,
368> where
369 T: for<'a> ReadFromAsync<'a, SelfVfs> + for<'a> WriteToAsync<'a, TargetVfs> + Send + 'static,
370 for<'a> <T as ReadFromAsync<'a, SelfVfs>>::Future:
371 Future<Output = VfsResult<T, SelfVfs>> + Unpin + 'a,
372 for<'a> <T as WriteToAsync<'a, TargetVfs>>::Future:
373 Future<Output = VfsResult<(), TargetVfs>> + Unpin + 'a,
374{
375 Poisson,
376 SamePath,
377 Reading {
378 self_vfs: Pin<&'f SelfVfs>,
379 target_vfs: Pin<&'f TargetVfs>,
380 inner: <T as ReadFromAsync<'f, SelfVfs>>::Future,
381 path: P::OwnedPath,
382 },
383 Writing {
384 inner: <T as WriteToAsync<'f, TargetVfs>>::Future,
385 },
386}
387
388#[cfg(feature = "async")]
389#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
390impl<
391 'f,
392 T,
393 P: PathType + ?Sized + 'f,
394 SelfVfs: VfsAsync<Path = P> + 'f,
395 TargetVfs: WriteSupportingVfsAsync<Path = P> + 'f,
396> Future for DeferredReadWriteRefFuture<'f, T, P, SelfVfs, TargetVfs>
397where
398 T: for<'a> ReadFromAsync<'a, SelfVfs> + for<'a> WriteToAsync<'a, TargetVfs> + Send + 'static,
399 for<'a> <T as ReadFromAsync<'a, SelfVfs>>::Future:
400 Future<Output = VfsResult<T, SelfVfs>> + Unpin + 'a,
401 for<'a> <T as WriteToAsync<'a, TargetVfs>>::Future:
402 Future<Output = VfsResult<(), TargetVfs>> + Unpin + 'a,
403{
404 type Output = Result<(), P::OwnedPath>;
405
406 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
407 let this = self.as_mut().project_replace(Self::Poisson);
408 match this {
409 DeferredReadWriteRefFutureProj::SamePath => Poll::Ready(Ok(())),
410 DeferredReadWriteRefFutureProj::Reading {
411 mut inner,
412 self_vfs,
413 target_vfs,
414 path,
415 } => match Pin::new(&mut inner).poll(cx) {
416 Poll::Ready(Ok(v)) => {
417 let write_fut = v.write_to_async(path, target_vfs);
418 self.as_mut()
419 .project_replace(Self::Writing { inner: write_fut });
420 cx.waker().wake_by_ref();
421 Poll::Pending
422 }
423 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
424 Poll::Pending => {
425 self.project_replace(Self::Reading {
426 inner,
427 self_vfs,
428 target_vfs,
429 path,
430 });
431 Poll::Pending
432 }
433 },
434 DeferredReadWriteRefFutureProj::Writing { mut inner } => {
435 match Pin::new(&mut inner).poll(cx) {
436 Poll::Ready(r) => Poll::Ready(r),
437 Poll::Pending => {
438 self.as_mut().project_replace(Self::Writing { inner });
439 cx.waker().wake_by_ref();
440 Poll::Pending
441 }
442 }
443 }
444 DeferredReadWriteRefFutureProj::Poisson => {
445 panic!(
446 "DeferredReadWriteRefFuture is in an invalid state. This is a bug in the code."
447 );
448 }
449 }
450 }
451}
452
453#[cfg(feature = "async")]
454#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
455impl<
456 'f,
457 const CHECK_ON_READ: bool,
458 T,
459 P: PathType + ?Sized + 'f,
460 SelfVfs: VfsAsync<Path = P> + 'f,
461 TargetVfs: WriteSupportingVfsAsync<Path = P> + 'f,
462> WriteToAsyncRef<'f, TargetVfs> for DeferredRead<'f, T, SelfVfs, CHECK_ON_READ>
463where
464 for<'a> T: ReadFromAsync<'a, SelfVfs> + WriteToAsync<'a, TargetVfs> + Send + 'a,
465 for<'a> <T as ReadFromAsync<'a, SelfVfs>>::Future:
466 Future<Output = VfsResult<T, SelfVfs>> + Unpin + 'a,
467 for<'a> <T as WriteToAsync<'a, TargetVfs>>::Future:
468 Future<Output = VfsResult<(), TargetVfs>> + Unpin + 'a,
469{
470 type Future<'a>
471 = DeferredReadWriteFuture<'a, T, P, SelfVfs, TargetVfs>
472 where
473 Self: 'a,
474 'f: 'a;
475
476 fn write_to_async_ref<'a>(
477 self: &'a Self,
478 path: P::OwnedPath,
479 vfs: Pin<&'a TargetVfs>,
480 ) -> Self::Future<'a>
481 where
482 'f: 'a,
483 {
484 if path == self.0 {
485 return DeferredReadWriteFuture::SamePath;
493 }
494
495 DeferredReadWriteFuture::Reading {
496 inner: T::read_from_async(self.0.clone(), self.1),
497 path,
498 self_vfs: self.1,
499 target_vfs: vfs,
500 }
501 }
502}
503
504#[cfg(feature = "resolve-path")]
505#[cfg_attr(docsrs, doc(cfg(feature = "resolve-path")))]
506impl<const CHECK_ON_READ: bool, const NAME: [char; HAS_FIELD_MAX_LEN], T, Vfs: VfsCore>
507 HasField<NAME> for DeferredRead<'_, T, Vfs, CHECK_ON_READ>
508where
509 T: HasField<NAME>,
510{
511 type Inner = <T as HasField<NAME>>::Inner;
512
513 fn resolve_path<P: OwnedPathType>(p: P) -> P {
514 T::resolve_path(p)
515 }
516}
517
518#[cfg(feature = "resolve-path")]
519#[cfg_attr(docsrs, doc(cfg(feature = "resolve-path")))]
520impl<const CHECK_ON_READ: bool, T, Vfs: VfsCore> DynamicHasField
521 for DeferredRead<'_, T, Vfs, CHECK_ON_READ>
522where
523 T: DynamicHasField,
524{
525 type Inner = <T as DynamicHasField>::Inner;
526
527 fn resolve_path<P: OwnedPathType>(p: P, name: &str) -> P {
528 T::resolve_path(p, name)
529 }
530}