dir_structure/
deferred_read_or_own.rs

1//! A wrapper that defers the reading of a file until it is actually needed.
2//!
3//! See [`DeferredReadOrOwn`] for more details.
4
5use std::fmt;
6use std::hash;
7use std::pin::Pin;
8#[cfg(feature = "async")]
9use std::task::Context;
10#[cfg(feature = "async")]
11use std::task::Poll;
12
13#[cfg(feature = "async")]
14use pin_project::pin_project;
15
16use crate::deferred_read::DeferredRead;
17use crate::error::Result;
18use crate::error::VfsResult;
19use crate::prelude::*;
20#[cfg(feature = "async")]
21use crate::traits::async_vfs::VfsAsync;
22#[cfg(feature = "async")]
23use crate::traits::async_vfs::WriteSupportingVfsAsync;
24#[cfg(feature = "resolve-path")]
25use crate::traits::resolve::DynamicHasField;
26#[cfg(feature = "resolve-path")]
27use crate::traits::resolve::HAS_FIELD_MAX_LEN;
28#[cfg(feature = "resolve-path")]
29use crate::traits::resolve::HasField;
30use crate::traits::vfs;
31#[cfg(feature = "resolve-path")]
32use crate::traits::vfs::OwnedPathType;
33use crate::traits::vfs::PathType;
34#[cfg(feature = "async")]
35use crate::traits::vfs::VfsCore;
36use crate::vfs::fs_vfs;
37
38/// A wrapper that defers the reading of a file until it is actually needed,
39/// but can also store the value.
40///
41/// It allows us to read the value from disk, and then store it in memory,
42/// and if we ever need it again, we can just return the stored value.
43///
44/// This type exposes 2 functions: [`DeferredReadOrOwn::get`] and
45/// [`DeferredReadOrOwn::perform_and_store_read`].
46///
47/// The table below summarizes the differences between the two functions:
48///
49/// | State             | [`DeferredReadOrOwn::get`]               | [`DeferredReadOrOwn::perform_and_store_read`]     |
50/// |-------------------|------------------------------------------|---------------------------------------------------|
51/// | New, not cached   | Reads the value, does not cache          | Reads the value, and caches it, returns reference |
52/// | Cached            | Clones the cached value                  | Returns a reference to the cached value           |
53///
54/// As such, [`DeferredReadOrOwn::get`] has the signature of `fn(&self) -> Result<T>` and
55/// [`DeferredReadOrOwn::perform_and_store_read`] has the signature of `fn(&mut self) -> Result<&mut T>`.
56///
57/// If you never call [`DeferredReadOrOwn::perform_and_store_read`], and only ever call [`DeferredReadOrOwn::get`],
58/// that would effectively be the same as using a [`DeferredRead`], and that should be preferred instead.
59#[derive(Clone)]
60pub enum DeferredReadOrOwn<'a, T, Vfs: VfsCore = fs_vfs::FsVfs, const CHECK_ON_READ: bool = false> {
61    /// An owned value.
62    Own(T),
63    /// A deferred read.
64    Deferred(DeferredRead<'a, T, Vfs, CHECK_ON_READ>),
65}
66
67impl<'a, T, Vfs: VfsCore, const CHECK_ON_READ: bool> hash::Hash
68    for DeferredReadOrOwn<'a, T, Vfs, CHECK_ON_READ>
69where
70    T: hash::Hash,
71    <Vfs::Path as PathType>::OwnedPath: hash::Hash,
72{
73    fn hash<H: hash::Hasher>(&self, state: &mut H) {
74        match self {
75            DeferredReadOrOwn::Own(own) => {
76                state.write_u8(0);
77                own.hash(state);
78            }
79            DeferredReadOrOwn::Deferred(d) => {
80                state.write_u8(1);
81                d.hash(state);
82            }
83        }
84    }
85}
86
87#[cfg(feature = "assert_eq")]
88impl<'a, T, Vfs: VfsCore<Path = P>, P, const CHECK_ON_READ: bool> assert_eq::AssertEq
89    for DeferredReadOrOwn<'a, T, Vfs, CHECK_ON_READ>
90where
91    T: assert_eq::AssertEq,
92    P: PathType + ?Sized,
93    P::OwnedPath: assert_eq::AssertEq + fmt::Debug,
94{
95    fn assert_eq(
96        &self,
97        other: &Self,
98        path: &mut assert_eq::AssertPath,
99        init_left: &impl fmt::Display,
100        init_right: &impl fmt::Display,
101    ) {
102        match (self, other) {
103            (Self::Own(l), Self::Own(r)) => {
104                T::assert_eq(l, r, &mut *path.__guard("[Own]"), init_left, init_right);
105            }
106            (Self::Deferred(l), Self::Deferred(r)) => {
107                DeferredRead::<T, Vfs, CHECK_ON_READ>::assert_eq(
108                    l,
109                    r,
110                    &mut *path.__guard("[Deferred]"),
111                    init_left,
112                    init_right,
113                );
114            }
115            (Self::Own(_), Self::Deferred(_)) => {
116                panic!("Left is Own, right is Deferred: at: {:?}", path);
117            }
118            (Self::Deferred(_), Self::Own(_)) => {
119                panic!("Left is Deferred, right is Own: at: {:?}", path);
120            }
121        }
122    }
123}
124
125impl<'a, const CHECK_ON_READ: bool, T, Vfs: VfsCore<Path = P>, P> fmt::Debug
126    for DeferredReadOrOwn<'a, T, Vfs, CHECK_ON_READ>
127where
128    T: fmt::Debug,
129    P: PathType + ?Sized,
130    P::OwnedPath: fmt::Debug,
131{
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        match self {
134            DeferredReadOrOwn::Own(own) => f.debug_tuple("Own").field(own).finish(),
135            DeferredReadOrOwn::Deferred(d) => f.debug_tuple("Deferred").field(d).finish(),
136        }
137    }
138}
139
140impl<'a, const CHECK_ON_READ: bool, T, Vfs: vfs::Vfs<'a, Path = P>, P: PathType + ?Sized + 'a>
141    DeferredReadOrOwn<'a, T, Vfs, CHECK_ON_READ>
142where
143    T: ReadFrom<'a, Vfs>,
144{
145    /// Gets the value. If it is not already read, it will read it, but without saving it.
146    ///
147    /// This is useful if you want to read the value, but you don't want to store it.
148    ///
149    /// Though never calling [`DeferredReadOrOwn::perform_and_store_read`] and only calling
150    /// [`DeferredReadOrOwn::get`] is equivalent to using a [`DeferredRead`], and that should be preferred.
151    ///
152    /// See [`DeferredReadOrOwn`] for more details.
153    ///
154    /// # Examples
155    ///
156    /// ```rust
157    /// use std::path::Path;
158    /// use std::pin::Pin;
159    /// use dir_structure::traits::sync::DirStructureItem;
160    /// use dir_structure::deferred_read::DeferredRead;
161    /// use dir_structure::deferred_read_or_own::DeferredReadOrOwn;
162    /// use dir_structure::prelude::*;
163    /// use dir_structure::vfs::fs_vfs::FsVfs;
164    ///
165    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
166    ///     let d = Path::new("dir");
167    ///     std::fs::create_dir_all(&d)?;
168    ///     let deferred = DeferredReadOrOwn::<String, FsVfs>::Deferred(
169    ///         DeferredRead::read_from(d.join("f.txt").as_ref(), Pin::new(&FsVfs)).unwrap()
170    ///     );
171    ///     assert!(deferred.get().is_err());
172    ///     std::fs::write(d.join("f.txt"), "Hello, world!")?;
173    ///     assert_eq!(deferred.get()?, "Hello, world!");
174    ///     std::fs::write(d.join("f.txt"), "Goodbye, world!")?;
175    ///     assert_eq!(deferred.get()?, "Goodbye, world!");
176    ///     # std::fs::remove_dir_all(&d)?;
177    ///     Ok(())
178    /// }
179    /// ```
180    pub fn get(&self) -> VfsResult<T, Vfs>
181    where
182        T: Clone,
183    {
184        match self {
185            DeferredReadOrOwn::Own(own) => Ok(own.clone()),
186            DeferredReadOrOwn::Deferred(d) => Ok(d.perform_read()?),
187        }
188    }
189
190    /// Performs the read and stores the value. If the value is already read, it will
191    /// just return a reference to it.
192    ///
193    /// See [`DeferredReadOrOwn`] for more details.
194    ///
195    /// # Examples
196    ///
197    /// ```rust
198    /// use std::path::Path;
199    /// use std::pin::Pin;
200    /// use dir_structure::traits::sync::DirStructureItem;
201    /// use dir_structure::deferred_read::DeferredRead;
202    /// use dir_structure::deferred_read_or_own::DeferredReadOrOwn;
203    /// use dir_structure::prelude::*;
204    /// use dir_structure::vfs::fs_vfs::FsVfs;
205    ///
206    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
207    ///     let d = Path::new("dir");
208    ///     std::fs::create_dir_all(&d)?;
209    ///     let mut deferred = DeferredReadOrOwn::<String, FsVfs>::Deferred(
210    ///         DeferredRead::read_from(d.join("f.txt").as_ref(), Pin::new(&FsVfs)).unwrap()
211    ///     );
212    ///     assert!(deferred.perform_and_store_read().is_err());
213    ///     std::fs::write(d.join("f.txt"), "Hello, world!")?;
214    ///     assert_eq!(deferred.perform_and_store_read()?, "Hello, world!");
215    ///     std::fs::write(d.join("f.txt"), "Goodbye, world!")?;
216    ///     assert_eq!(deferred.perform_and_store_read()?, "Hello, world!");
217    ///     # std::fs::remove_dir_all(&d)?;
218    ///     Ok(())
219    /// }
220    /// ```
221    pub fn perform_and_store_read(&mut self) -> VfsResult<&mut T, Vfs> {
222        match self {
223            DeferredReadOrOwn::Own(own) => Ok(own),
224            DeferredReadOrOwn::Deferred(d) => {
225                let value = d.perform_read()?;
226                *self = DeferredReadOrOwn::Own(value);
227                let DeferredReadOrOwn::Own(own) = self else {
228                    unreachable!()
229                };
230                Ok(own)
231            }
232        }
233    }
234
235    /// Flushes the current value to the specified path.
236    pub fn flush_to<'t, TargetVfs: vfs::WriteSupportingVfs<'t, Path = P>>(
237        &self,
238        path: &P,
239        vfs: Pin<&'t TargetVfs>,
240    ) -> VfsResult<(), Vfs>
241    where
242        T: WriteTo<'t, TargetVfs>,
243    {
244        match self {
245            DeferredReadOrOwn::Own(own) => own.write_to(path, vfs),
246            DeferredReadOrOwn::Deferred(d) => d.write_to(path, vfs),
247        }
248    }
249}
250
251impl<'a, const CHECK_ON_READ: bool, T, Vfs: vfs::Vfs<'a>> ReadFrom<'a, Vfs>
252    for DeferredReadOrOwn<'a, T, Vfs, CHECK_ON_READ>
253where
254    T: ReadFrom<'a, Vfs>,
255{
256    fn read_from(path: &Vfs::Path, vfs: Pin<&'a Vfs>) -> VfsResult<Self, Vfs>
257    where
258        Self: Sized,
259    {
260        ReadFrom::read_from(path, vfs).map(Self::Deferred)
261    }
262}
263
264#[cfg(feature = "async")]
265#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
266impl<'a, const CHECK_ON_READ: bool, T, Vfs: VfsAsync<Path = P> + 'a, P: PathType + ?Sized + 'a>
267    DeferredReadOrOwn<'a, T, Vfs, CHECK_ON_READ>
268where
269    T: ReadFromAsync<'a, Vfs> + Send + 'static,
270{
271    /// Gets the value, asynchronously. This is an async version of [`get`](Self::get).
272    pub async fn get_async(&'a self) -> VfsResult<T, Vfs>
273    where
274        T: Clone,
275    {
276        match self {
277            DeferredReadOrOwn::Own(own) => Ok(own.clone()),
278            DeferredReadOrOwn::Deferred(d) => d.perform_read_async().await,
279        }
280    }
281
282    /// Performs the read and stores the value. If the value is already read, it will
283    /// just return a reference to it.
284    ///
285    /// See [`DeferredReadOrOwn`] for more details.
286    ///
287    /// This is an async version of [`perform_and_store_read`](Self::perform_and_store_read).
288    pub async fn perform_and_store_read_async(&'a mut self) -> VfsResult<&'a mut T, Vfs> {
289        match self {
290            DeferredReadOrOwn::Own(own) => Ok(own),
291            DeferredReadOrOwn::Deferred(d) => {
292                let value = d.perform_read_async().await?;
293                *self = DeferredReadOrOwn::Own(value);
294                let DeferredReadOrOwn::Own(own) = self else {
295                    unreachable!()
296                };
297                Ok(own)
298            }
299        }
300    }
301}
302
303#[cfg(feature = "async")]
304#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
305impl<'a, const CHECK_ON_READ: bool, T, Vfs: VfsAsync<Path = P> + 'a, P: PathType + ?Sized + 'a>
306    DeferredReadOrOwn<'a, T, Vfs, CHECK_ON_READ>
307where
308    P::OwnedPath: 'a,
309{
310    /// Flushes the current value to the specified path. Async version of [`flush_to`](Self::flush_to).
311    pub async fn flush_to_async<TargetVfs: WriteSupportingVfsAsync<Path = P> + 'a, ReadFutTy>(
312        &'a self,
313        path: P::OwnedPath,
314        vfs: Pin<&'a TargetVfs>,
315    ) -> VfsResult<(), Vfs>
316    where
317        for<'b> T: ReadFromAsync<'b, Vfs, Future = ReadFutTy>
318            + WriteToAsync<'b, TargetVfs>
319            + WriteToAsyncRef<'b, TargetVfs>
320            + Send
321            + 'b,
322        ReadFutTy: Future<Output = VfsResult<T, Vfs>> + Unpin + 'static,
323    {
324        match self {
325            DeferredReadOrOwn::Own(own) => own.write_to_async_ref(path, vfs).await,
326            DeferredReadOrOwn::Deferred(d) => d.write_to_async_ref(path, vfs).await,
327        }
328    }
329}
330
331#[cfg(feature = "async")]
332#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
333impl<'a, const CHECK_ON_READ: bool, T, Vfs: VfsAsync<Path = P> + 'static, P: PathType + ?Sized + 'a>
334    ReadFromAsync<'a, Vfs> for DeferredReadOrOwn<'a, T, Vfs, CHECK_ON_READ>
335where
336    T: ReadFromAsync<'a, Vfs> + Send + 'static,
337    P::OwnedPath: Send + Sync,
338{
339    type Future = Pin<Box<dyn Future<Output = VfsResult<Self, Vfs>> + Send + 'a>>;
340
341    fn read_from_async(path: P::OwnedPath, vfs: Pin<&'a Vfs>) -> Self::Future {
342        use std::future::poll_fn;
343
344        let mut fut = DeferredRead::<T, Vfs, CHECK_ON_READ>::read_from_async(path, vfs);
345
346        Box::pin(poll_fn(move |cx| {
347            fut.as_mut().poll(cx).map_ok(Self::Deferred)
348        }))
349    }
350}
351
352impl<
353    'a,
354    't,
355    const CHECK_ON_READ: bool,
356    T,
357    P: PathType + ?Sized + 'a,
358    SelfVfs: vfs::Vfs<'a, Path = P>,
359    TargetVfs: vfs::WriteSupportingVfs<'t, Path = P>,
360> WriteTo<'t, TargetVfs> for DeferredReadOrOwn<'a, T, SelfVfs, CHECK_ON_READ>
361where
362    T: ReadFrom<'a, SelfVfs> + WriteTo<'t, TargetVfs>,
363{
364    fn write_to(&self, path: &P, vfs: Pin<&'t TargetVfs>) -> Result<(), P::OwnedPath> {
365        match self {
366            DeferredReadOrOwn::Own(own) => own.write_to(path, vfs),
367            DeferredReadOrOwn::Deferred(d) => d.write_to(path, vfs),
368        }
369    }
370}
371
372#[cfg(feature = "async")]
373#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
374#[pin_project(project_replace = DeferredReadOrOwnWriteFutureProj)]
375#[doc(hidden)]
376pub enum DeferredReadOrOwnWriteFuture<
377    'a,
378    T,
379    Vfs: WriteSupportingVfsAsync + 'static,
380    const CHECK_ON_READ: bool,
381> where
382    T: for<'b> ReadFromAsync<'b, Vfs> + for<'b> WriteToAsync<'b, Vfs> + Send + 'static,
383    for<'b> <T as ReadFromAsync<'b, Vfs>>::Future: Future<Output = VfsResult<T, Vfs>> + Unpin + 'b,
384    for<'b> <T as WriteToAsync<'b, Vfs>>::Future: Future<Output = VfsResult<(), Vfs>> + Unpin + 'b,
385{
386    Poisson,
387    Own {
388        inner: <T as WriteToAsync<'a, Vfs>>::Future,
389    },
390    Deferred {
391        inner: <DeferredRead<'a, T, Vfs, CHECK_ON_READ> as WriteToAsync<'a, Vfs>>::Future,
392    },
393}
394
395// needed to avoid ICE in rustdoc, see https://github.com/rust-lang/rust/issues/144918
396#[cfg(all(feature = "async", doc))]
397impl<T, Vfs, const CHECK_ON_READ: bool> core::marker::Unpin
398    for DeferredReadOrOwnWriteFutureProj<'_, T, Vfs, CHECK_ON_READ>
399where
400    T: for<'b> ReadFromAsync<'b, Vfs> + for<'b> WriteToAsync<'b, Vfs> + Send + 'static,
401    for<'b> <T as ReadFromAsync<'b, Vfs>>::Future: Future<Output = VfsResult<T, Vfs>> + Unpin + 'b,
402    for<'b> <T as WriteToAsync<'b, Vfs>>::Future: Future<Output = VfsResult<(), Vfs>> + Unpin + 'b,
403    Vfs: WriteSupportingVfsAsync + 'static,
404{
405}
406
407#[cfg(feature = "async")]
408#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
409impl<
410    'a,
411    const CHECK_ON_READ: bool,
412    T,
413    P: PathType + ?Sized + 'a,
414    Vfs: WriteSupportingVfsAsync<Path = P> + 'a,
415> Future for DeferredReadOrOwnWriteFuture<'a, T, Vfs, CHECK_ON_READ>
416where
417    T: for<'b> ReadFromAsync<'b, Vfs> + for<'b> WriteToAsync<'b, Vfs> + Send + 'static,
418    for<'b> <T as ReadFromAsync<'b, Vfs>>::Future: Future<Output = VfsResult<T, Vfs>> + Unpin + 'b,
419    for<'b> <T as WriteToAsync<'b, Vfs>>::Future: Future<Output = VfsResult<(), Vfs>> + Unpin + 'b,
420{
421    type Output = VfsResult<(), Vfs>;
422
423    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
424        let this = self.as_mut().project_replace(Self::Poisson);
425        match this {
426            DeferredReadOrOwnWriteFutureProj::Own { mut inner } => {
427                match Pin::new(&mut inner).poll(cx) {
428                    Poll::Ready(v) => Poll::Ready(v),
429                    Poll::Pending => {
430                        self.project_replace(Self::Own { inner });
431                        Poll::Pending
432                    }
433                }
434            }
435            DeferredReadOrOwnWriteFutureProj::Deferred { mut inner } => {
436                match Pin::new(&mut inner).poll(cx) {
437                    Poll::Ready(v) => Poll::Ready(v),
438                    Poll::Pending => {
439                        self.project_replace(Self::Deferred { inner });
440                        Poll::Pending
441                    }
442                }
443            }
444            DeferredReadOrOwnWriteFutureProj::Poisson => {
445                panic!(
446                    "DeferredReadOrOwnWriteFuture 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<'a, const CHECK_ON_READ: bool, T, Vfs: WriteSupportingVfsAsync + 'static> WriteToAsync<'a, Vfs>
456    for DeferredReadOrOwn<'a, T, Vfs, CHECK_ON_READ>
457where
458    T: for<'b> ReadFromAsync<'b, Vfs> + for<'b> WriteToAsync<'b, Vfs> + Send + 'static,
459    for<'b> <T as ReadFromAsync<'b, Vfs>>::Future: Future<Output = VfsResult<T, Vfs>> + Unpin + 'b,
460    for<'b> <T as WriteToAsync<'b, Vfs>>::Future: Future<Output = VfsResult<(), Vfs>> + Unpin + 'b,
461{
462    type Future = DeferredReadOrOwnWriteFuture<'a, T, Vfs, CHECK_ON_READ>;
463
464    fn write_to_async(
465        self,
466        path: <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
467        vfs: Pin<&'a Vfs>,
468    ) -> Self::Future {
469        match self {
470            DeferredReadOrOwn::Own(own) => DeferredReadOrOwnWriteFuture::Own {
471                inner: own.write_to_async(path, vfs),
472            },
473            DeferredReadOrOwn::Deferred(d) => DeferredReadOrOwnWriteFuture::Deferred {
474                inner: d.write_to_async(path, vfs),
475            },
476        }
477    }
478}
479
480#[cfg(feature = "resolve-path")]
481#[cfg_attr(docsrs, doc(cfg(feature = "resolve-path")))]
482impl<'a, const CHECK_ON_READ: bool, const NAME: [char; HAS_FIELD_MAX_LEN], T, Vfs> HasField<NAME>
483    for DeferredReadOrOwn<'a, T, Vfs, CHECK_ON_READ>
484where
485    T: HasField<NAME>,
486    Vfs: VfsCore,
487{
488    type Inner = <T as HasField<NAME>>::Inner;
489
490    fn resolve_path<P: OwnedPathType>(p: P) -> P {
491        T::resolve_path(p)
492    }
493}
494
495#[cfg(feature = "resolve-path")]
496#[cfg_attr(docsrs, doc(cfg(feature = "resolve-path")))]
497impl<'a, const CHECK_ON_READ: bool, T, Vfs> DynamicHasField
498    for DeferredReadOrOwn<'a, T, Vfs, CHECK_ON_READ>
499where
500    T: DynamicHasField,
501    Vfs: VfsCore,
502{
503    type Inner = <T as DynamicHasField>::Inner;
504
505    fn resolve_path<P: OwnedPathType>(p: P, name: &str) -> P {
506        T::resolve_path(p, name)
507    }
508}