dir_structure/
lib.rs

1//! A library for reading and writing directory structures.
2//!
3//! This library provides a macro for defining directory structures, and a
4//! trait for reading and writing those structures to / from disk.
5//!
6//! # Example
7//!
8//! ## Writing a structure to disk
9//! ```
10//! use std::path::Path;
11//! fn main() -> Result<(), Box<dyn std::error::Error>> {
12//!     use dir_structure::DirStructureItem;
13//!     #[derive(dir_structure::DirStructure)]
14//!     struct Dir {
15//!         #[dir_structure(path = "f1.txt")]
16//!         f1: String,
17//!         #[dir_structure(path = "subdir/f2.txt")]
18//!         f2: String,
19//!         // default path is just a file name from the field's name.
20//!         f3: String,
21//!         // also works with nested structures
22//!         #[dir_structure(path = "subdir2")]
23//!         subdir: Subdir,
24//!     }
25//!     #[derive(dir_structure::DirStructure)]
26//!     struct Subdir {
27//!         #[dir_structure(path = "f4.txt")]
28//!         f4: String,
29//!     }
30//!
31//!     let d = Path::new("dir");
32//!     Dir {
33//!         f1: "f1".to_owned(),
34//!         f2: "f2".to_owned(),
35//!         f3: "f3".to_owned(),
36//!         subdir: Subdir {
37//!             f4: "f4".to_owned(),
38//!         },
39//!     }.write(&d)?;
40//!     assert_eq!(std::fs::read_to_string(d.join("f1.txt"))?, "f1");
41//!     assert_eq!(std::fs::read_to_string(d.join("subdir/f2.txt"))?, "f2");
42//!     assert_eq!(std::fs::read_to_string(d.join("f3"))?, "f3");
43//!     assert_eq!(std::fs::read_to_string(d.join("subdir2/f4.txt"))?, "f4");
44//!
45//!     # std::fs::remove_dir_all(&d)?;
46//!
47//!     Ok(())
48//! }
49//! ```
50//!
51//! ## Reading a structure from disk
52//!
53//! ```
54//! use std::path::Path;
55//! fn main() -> Result<(), Box<dyn std::error::Error>> {
56//!     use dir_structure::DirStructureItem;
57//!     #[derive(dir_structure::DirStructure)]
58//!     struct Dir {
59//!         #[dir_structure(path = "f1.txt")]
60//!         f1: String,
61//!         #[dir_structure(path = "subdir/f2.txt")]
62//!         f2: String,
63//!         // default path is just a file name from the field's name.
64//!         f3: String,
65//!         // also works with nested structures
66//!         #[dir_structure(path = "subdir2")]
67//!         subdir: Subdir,
68//!     }
69//!     #[derive(dir_structure::DirStructure)]
70//!     struct Subdir {
71//!         #[dir_structure(path = "f4.txt")]
72//!         f4: String,
73//!     }
74//!     let d = Path::new("dir");
75//!     std::fs::create_dir_all(&d)?;
76//!     std::fs::create_dir_all(d.join("subdir"))?;
77//!     std::fs::create_dir_all(d.join("subdir2"))?;
78//!     std::fs::write(d.join("f1.txt"), "f1")?;
79//!     std::fs::write(d.join("subdir/f2.txt"), "f2")?;
80//!     std::fs::write(d.join("f3"), "f3")?;
81//!     std::fs::write(d.join("subdir2/f4.txt"), "f4")?;
82//!     let dir = Dir::read(&d)?;
83//!     assert_eq!(dir.f1, "f1");
84//!     assert_eq!(dir.f2, "f2");
85//!     assert_eq!(dir.f3, "f3");
86//!     assert_eq!(dir.subdir.f4, "f4");
87//!
88//!     # std::fs::remove_dir_all(&d)?;
89//!
90//!     Ok(())
91//! }
92//! ```
93
94#![cfg_attr(docsrs, feature(doc_cfg))]
95
96use std::ffi::OsStr;
97use std::ffi::OsString;
98use std::fmt::Display;
99use std::fs::File;
100use std::marker;
101use std::ops::Deref;
102use std::ops::DerefMut;
103use std::path::Path;
104use std::path::PathBuf;
105use std::str::FromStr;
106
107/// The error type for this library.
108#[derive(Debug, thiserror::Error)]
109pub enum Error {
110    /// An IO error.
111    #[error("IO error at {0:?}: {1}")]
112    Io(PathBuf, #[source] std::io::Error),
113    /// Parse error.
114    #[error("Parse error at {0:?}: {1}")]
115    Parse(PathBuf, #[source] Box<dyn std::error::Error + Send + Sync>),
116    /// Serde error.
117    #[error("Serde error at {0:?}: {1}")]
118    Serde(PathBuf, #[source] Box<dyn std::error::Error + Send + Sync>),
119}
120
121trait WrapIoError: Sized {
122    type Output;
123
124    fn wrap_io_error(self, get_path: impl FnOnce() -> PathBuf) -> Result<Self::Output>;
125
126    fn wrap_io_error_with(self, path: &Path) -> Result<Self::Output> {
127        self.wrap_io_error(|| path.to_path_buf())
128    }
129}
130
131impl<T> WrapIoError for std::io::Result<T> {
132    type Output = T;
133
134    fn wrap_io_error(self, get_path: impl FnOnce() -> PathBuf) -> Result<Self::Output> {
135        self.map_err(|e| Error::Io(get_path(), e))
136    }
137}
138
139pub type Result<T> = std::result::Result<T, Error>;
140
141/// The main trait. This is implemented for
142/// all directory structures by the derive macro.
143///
144/// This trait doesn't have any methods, just a supertype:
145/// [`DirStructureItem`].
146pub trait DirStructure: DirStructureItem {}
147
148/// Helper trait, implemented for all types that have a [`ReadFrom`]
149/// and [`WriteTo`] implementation.
150pub trait DirStructureItem: ReadFrom + WriteTo {
151    /// Uses the [`ReadFrom`] implementation to read the structure from
152    /// disk, from the specified path.
153    fn read(path: impl AsRef<Path>) -> Result<Self>
154    where
155        Self: Sized,
156    {
157        Self::read_from(path.as_ref())
158    }
159
160    /// Uses the [`WriteTo`] implementation to write the structure
161    /// to disk at the specified path.
162    fn write(&self, path: impl AsRef<Path>) -> Result<()> {
163        self.write_to(path.as_ref())
164    }
165}
166
167// Blanket impl.
168impl<T> DirStructureItem for T where T: ReadFrom + WriteTo {}
169
170/// Trait for types / structures that can be
171/// read from disk, either from a file or a directory.
172pub trait ReadFrom {
173    /// Reads the structure from the specified path, which
174    /// can be either a file or a directory.
175    fn read_from(path: &Path) -> Result<Self>
176    where
177        Self: Sized;
178}
179
180/// Trait for types / structures that can be
181/// written to disk. All types in the library that
182/// write to files first check that the parent
183/// directories exist, so implementations of
184/// this that create the whole directory are
185/// not necessary (unless used empty children
186/// directories, in which case no directories will
187/// really be created).
188pub trait WriteTo {
189    /// Writes the structure to the specified path.
190    fn write_to(&self, path: &Path) -> Result<()>;
191}
192
193/// Trait to use when using the `with_newtype` attribute.
194///
195/// This is used to convert a reference to a normal type
196/// (like `String`, `Vec<u8>` etc. into a type that is a
197/// reference to them, like `&str`, `&[u8]` etc.), so that
198/// the `WriteTo` implementation can be written only for the
199/// reference types, and all the other [`WriteTo`] impls will
200/// only cast what they have to write to those reference types
201/// (via the function below), and then call the [`WriteTo::write_to`]
202/// method on that reference.
203pub trait FromRefForWriter<'a> {
204    /// The inner type to cast.
205    type Inner: ?Sized;
206    /// The reference type to cast to.
207    type Wr: WriteTo + 'a;
208
209    /// Casts the reference to the inner type to a [`WriteTo`]
210    /// reference type.
211    fn from_ref_for_writer(value: &'a Self::Inner) -> Self::Wr;
212}
213
214/// Trait to use when using the `with_newtype` attribute.
215///
216/// This is used to convert a newtype to its inner type.
217/// We are using this because we cannot make blanket impls with
218/// [`From`] due to the orphan rules.
219pub trait NewtypeToInner {
220    /// The inner type.
221    type Inner;
222
223    /// Converts the newtype to its inner type.
224    fn into_inner(self) -> Self::Inner;
225}
226
227/// A directory structure where we don't know the names of the folders at compile-time,
228/// and as such we cannot use the derive macro.
229///
230/// Instead we know that all the entries in the directory are folders,
231/// and that they all have the same structure inside (defined by the `T` type parameter),
232/// or they are all files (which can be read with [`DirChildren`]<[`String`]> for example).
233///
234/// In either case, [`ReadFrom::read_from`] must be able to read all the entries in
235/// the directory.
236///
237/// The [`WriteTo`] implementation will directly write the children to the directory it
238/// is passed, with no regards to the path stored in `self_path`.
239#[derive(Debug, PartialEq, Eq)]
240pub struct DirChildren<T, F: Filter = NoFilter>
241where
242    T: DirStructureItem,
243{
244    /// The path to the root directory.
245    ///
246    /// This path doesn't influence writing in any way, it is only to
247    /// point out the directory after it has been read and parsed.
248    pub self_path: PathBuf,
249    /// The children of the root directory.
250    pub children: Vec<DirChild<T>>,
251
252    filter: marker::PhantomData<F>,
253}
254
255impl<T, F> Clone for DirChildren<T, F>
256where
257    T: DirStructureItem + Clone,
258    F: Filter,
259{
260    fn clone(&self) -> Self {
261        Self {
262            self_path: self.self_path.clone(),
263            children: self.children.clone(),
264            filter: marker::PhantomData,
265        }
266    }
267}
268
269/// A filter for the children of a [`DirChildren`] structure.
270///
271/// This is used to filter out children that we don't want to
272/// read into the structure. For example, if we have a directory
273/// with a lot of files, we can use this to only read the
274/// files we want, for example, that have just a certain extension.
275///
276/// # Examples
277///
278/// For example, for a [`Filter`] that only allows `.txt` files:
279///
280/// ```rust
281/// use std::path::Path;
282/// use std::path::PathBuf;
283///
284/// use dir_structure::{DirStructure, DirStructureItem, DirChildren, Filter};
285///
286/// pub struct TextFileFilter;
287///
288/// impl Filter for TextFileFilter {
289///     fn make_filter() -> Self {
290///        Self
291///     }
292///
293///     fn allows(&self, path: &Path) -> bool {
294///         path.extension()
295///             .and_then(|s| s.to_str())
296///             .map_or(false, |s| s == "txt")
297///     }
298/// }
299///
300/// fn main() -> Result<(), Box<dyn std::error::Error>> {
301///     let path = PathBuf::from("dir");
302///     #[derive(DirStructure)]
303///     struct Dir {
304///        #[dir_structure(path = self)]
305///        text_files: DirChildren<String, TextFileFilter>,
306///     }
307///
308///     # std::fs::create_dir_all(&path)?;
309///
310///     std::fs::write(path.join("file1.txt"), "file1")?;
311///     std::fs::write(path.join("file2.txt"), "file2")?;
312///     std::fs::write(path.join("file3.bin"), "aaa")?;
313///
314///     let dir = Dir::read(&path)?;
315///     assert_eq!(dir.text_files.len(), 2);
316///     assert_eq!(dir.text_files.get_value_by_name("file1.txt"), Some(&String::from("file1")));
317///     assert_eq!(dir.text_files.get_value_by_name("file2.txt"), Some(&String::from("file2")));
318///     assert_eq!(dir.text_files.get_value_by_name("file3.bin"), None);
319///
320///     # std::fs::remove_dir_all(&path)?;
321///
322///     Ok(())
323/// }
324/// ```
325pub trait Filter {
326    /// Creates an instance of this filter.
327    fn make_filter() -> Self;
328    /// Checks if the path is allowed by this filter.
329    fn allows(&self, path: &Path) -> bool;
330}
331
332/// A [`Filter`] that allows all paths.
333///
334/// ```rust
335/// # use std::path::Path;
336/// # use dir_structure::{Filter, NoFilter};
337/// #
338/// let filter = NoFilter::make_filter();
339/// assert!(filter.allows(Path::new("foo.txt")));
340/// assert!(filter.allows(Path::new("foo/bar.txt")));
341/// assert!(filter.allows(Path::new("foo/bar/baz.txt")));
342/// assert!(filter.allows(Path::new("foo/bar/baz")));
343/// assert!(filter.allows(Path::new("foo/bar/baz/")));
344/// assert!(filter.allows(Path::new("foo/bar/baz/.")));
345/// assert!(filter.allows(Path::new("foo/bar/baz/..")));
346/// assert!(filter.allows(Path::new("foo/bar/baz/../..")));
347/// assert!(filter.allows(Path::new("foo/bar/baz/../../..")));
348/// assert!(filter.allows(Path::new("foo/bar/baz/../../../..")));
349/// assert!(filter.allows(Path::new("foo/bar/baz/../../../../..")));
350/// assert!(filter.allows(Path::new("foo/bar/baz/../../../../../..")));
351/// ```
352#[derive(Debug, Clone, Copy, PartialEq, Eq)]
353pub struct NoFilter;
354
355impl Filter for NoFilter {
356    fn make_filter() -> Self {
357        Self
358    }
359
360    fn allows(&self, _path: &Path) -> bool {
361        true
362    }
363}
364
365impl<T> Default for DirChildren<T>
366where
367    T: DirStructureItem,
368{
369    fn default() -> Self {
370        Self::new()
371    }
372}
373
374impl<T, F> DirChildren<T, F>
375where
376    T: DirStructureItem,
377    F: Filter,
378{
379    /// Creates an empty [`DirChildren`], with no children.
380    pub fn new() -> Self {
381        Self {
382            self_path: PathBuf::new(),
383            children: Vec::new(),
384            filter: marker::PhantomData,
385        }
386    }
387
388    /// Creates a [`DirChildren`] with the given path and children.
389    pub fn with_children_from_iter(
390        self_path: impl Into<PathBuf>,
391        children: impl IntoIterator<Item = DirChild<T>>,
392    ) -> Self {
393        Self {
394            self_path: self_path.into(),
395            children: children.into_iter().collect(),
396            filter: marker::PhantomData,
397        }
398    }
399
400    /// Maps the children of this [`DirChildren`] to a new type.
401    ///
402    /// This is useful for converting the children to a different type,
403    /// for example, if you want to convert the children to a different
404    /// type of [`DirStructureItem`].
405    ///
406    /// This is a convenience method that allows you to use the
407    /// `map` method on the children of this [`DirChildren`].
408    ///
409    /// # Examples
410    ///
411    /// ```rust
412    /// use std::path::Path;
413    /// use std::path::PathBuf;
414    /// use dir_structure::{DirStructure, DirStructureItem, DirChildren, DirChild, ReadFrom, WriteTo};
415    ///
416    /// #[derive(Debug, PartialEq, Eq)]
417    /// struct NewType(String);
418    ///
419    /// impl ReadFrom for NewType {
420    ///     fn read_from(path: &Path) -> dir_structure::Result<Self> {
421    ///         String::read_from(path).map(Self)
422    ///     }
423    /// }
424    ///
425    /// impl WriteTo for NewType {
426    ///     fn write_to(&self, path: &Path) -> dir_structure::Result<()> {
427    ///         self.0.write_to(path)
428    ///     }
429    /// }
430    ///
431    /// let d = PathBuf::from("dir");
432    /// let dir = DirChildren::<_, dir_structure::NoFilter>::with_children_from_iter(
433    ///     d.clone(),
434    ///     vec![
435    ///         DirChild::new("file1.txt", "file1".to_owned()),
436    ///         DirChild::new("file2.txt", "file2".to_owned()),
437    ///         DirChild::new("file3.txt", "file3".to_owned()),
438    ///     ],
439    /// );
440    /// let dir = dir.map(|child| child.map_value(NewType));
441    /// assert_eq!(
442    ///     dir,
443    ///     DirChildren::with_children_from_iter(
444    ///         d.clone(),
445    ///         vec![
446    ///             DirChild::new("file1.txt", NewType("file1".to_owned())),
447    ///             DirChild::new("file2.txt", NewType("file2".to_owned())),
448    ///             DirChild::new("file3.txt", NewType("file3".to_owned())),
449    ///         ],
450    ///     )
451    /// );
452    /// ```
453    pub fn map<U, MapF>(self, f: MapF) -> DirChildren<U, F>
454    where
455        MapF: FnMut(DirChild<T>) -> DirChild<U>,
456        U: DirStructureItem,
457    {
458        let children = self.children.into_iter().map(f).collect();
459        DirChildren {
460            self_path: self.self_path,
461            children,
462            filter: marker::PhantomData,
463        }
464    }
465
466    /// Maps the filter type. The children remain unchanged.
467    ///
468    /// This is useful if you are trying to pass a DirChildren<T, F1> to
469    /// a function requiring a DirChildren<T, F2>, where F1 and F2 are two
470    /// distinct types implementing [`Filter`].
471    ///
472    /// # Examples
473    ///
474    /// ```rust
475    /// use std::path::Path;
476    /// use dir_structure::{Filter, DirChildren};
477    ///
478    /// struct NewFilter;
479    ///
480    /// impl Filter for NewFilter {
481    ///     fn make_filter() -> Self {
482    ///         Self
483    ///     }
484    ///
485    ///     fn allows(&self, _path: &Path) -> bool {
486    ///         true
487    ///     }
488    /// }
489    ///
490    /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
491    /// let d2: DirChildren<String, NewFilter> = d.map_filter::<NewFilter>();
492    /// ```
493    pub fn map_filter<NewF: Filter>(self) -> DirChildren<T, NewF>
494    where
495        NewF: Filter,
496    {
497        DirChildren {
498            self_path: self.self_path,
499            children: self.children,
500            filter: marker::PhantomData,
501        }
502    }
503
504    /// Returns the number of children.
505    ///
506    /// # Examples
507    ///
508    /// ```rust
509    /// use std::path::{Path, PathBuf};
510    /// use dir_structure::{DirStructure, DirStructureItem, DirChildren, DirChild};
511    ///
512    /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
513    /// assert_eq!(d.len(), 0);
514    ///
515    /// let d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
516    ///     PathBuf::new(),
517    ///     vec![
518    ///         DirChild::new("file1.txt", "file1".to_owned()),
519    ///         DirChild::new("file2.txt", "file2".to_owned()),
520    ///     ],
521    /// );
522    /// assert_eq!(d.len(), 2);
523    /// ```
524    pub fn len(&self) -> usize {
525        self.children.len()
526    }
527
528    /// Gets the child at the specified index.
529    ///
530    /// # Examples
531    ///
532    /// ```rust
533    /// use std::path::{Path, PathBuf};
534    /// use dir_structure::{DirStructure, DirStructureItem, DirChildren, DirChild};
535    ///
536    /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
537    /// assert_eq!(d.get(0), None);
538    /// assert_eq!(d.get(1), None);
539    /// assert_eq!(d.get(100), None);
540    ///
541    /// let d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
542    ///     PathBuf::new(),
543    ///     vec![
544    ///         DirChild::new("file1.txt", "file1".to_owned()),
545    ///         DirChild::new("file2.txt", "file2".to_owned()),
546    ///     ],
547    /// );
548    /// assert_eq!(d.get(0), Some(&DirChild::new("file1.txt", "file1".to_owned())));
549    /// assert_eq!(d.get(1), Some(&DirChild::new("file2.txt", "file2".to_owned())));
550    /// assert_eq!(d.get(2), None);
551    /// assert_eq!(d.get(100), None);
552    /// ```
553    pub fn get(&self, index: usize) -> Option<&DirChild<T>> {
554        self.children.get(index)
555    }
556
557    /// Gets the child with the specified "file" name (last segment of path).
558    ///
559    /// # Examples
560    ///
561    /// ```rust
562    /// use std::path::{Path, PathBuf};
563    /// use dir_structure::{DirStructure, DirStructureItem, DirChildren, DirChild};
564    ///
565    /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
566    /// assert_eq!(d.get_name(""), None);
567    /// assert_eq!(d.get_name("any_name"), None);
568    /// assert_eq!(d.get_name("aaaa"), None);
569    ///
570    /// let d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
571    ///     PathBuf::new(),
572    ///     vec![
573    ///         DirChild::new("file1.txt", "file1".to_owned()),
574    ///         DirChild::new("file2.txt", "file2".to_owned()),
575    ///     ],
576    /// );
577    /// assert_eq!(d.get_name("file1.txt"), Some(&DirChild::new("file1.txt", "file1".to_owned())));
578    /// assert_eq!(d.get_name("file2.txt"), Some(&DirChild::new("file2.txt", "file2".to_owned())));
579    /// assert_eq!(d.get_name("any_name"), None);
580    /// assert_eq!(d.get_name("aaaa"), None);
581    /// ```
582    pub fn get_name(&self, name: impl AsRef<OsStr>) -> Option<&DirChild<T>> {
583        self.children
584            .iter()
585            .find(|child| child.file_name == name.as_ref())
586    }
587
588    /// Gets the value of the child with the specified "file" name (last segment of path).
589    ///
590    /// # Examples
591    ///
592    /// ```rust
593    /// use std::path::{Path, PathBuf};
594    /// use dir_structure::{DirStructure, DirStructureItem, DirChildren, DirChild};
595    ///
596    /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
597    /// assert_eq!(d.get_value_by_name(""), None);
598    /// assert_eq!(d.get_value_by_name("any_name"), None);
599    /// assert_eq!(d.get_value_by_name("aaaa"), None);
600    ///
601    /// let d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
602    ///     PathBuf::new(),
603    ///     vec![
604    ///         DirChild::new("file1.txt", "file1".to_owned()),
605    ///         DirChild::new("file2.txt", "file2".to_owned()),
606    ///     ],
607    /// );
608    /// assert_eq!(d.get_value_by_name("file1.txt"), Some(&"file1".to_owned()));
609    /// assert_eq!(d.get_value_by_name("file2.txt"), Some(&"file2".to_owned()));
610    /// assert_eq!(d.get_value_by_name("any_name"), None);
611    /// assert_eq!(d.get_value_by_name("aaaa"), None);
612    /// ```
613    pub fn get_value_by_name(&self, name: impl AsRef<OsStr>) -> Option<&T> {
614        self.get_name(name).map(|child| &child.value)
615    }
616
617    /// Returns an iterator over the children.
618    ///
619    /// # Examples
620    ///
621    /// ```rust
622    /// use std::path::{Path, PathBuf};
623    /// use dir_structure::{DirStructure, DirStructureItem, DirChildren, DirChild};
624    ///
625    /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
626    /// let mut i = d.iter();
627    /// assert_eq!(i.next(), None);
628    ///
629    /// let d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
630    ///     PathBuf::new(),
631    ///     vec![
632    ///         DirChild::new("file1.txt", "file1".to_owned()),
633    ///         DirChild::new("file2.txt", "file2".to_owned()),
634    ///     ],
635    /// );
636    /// let mut i = d.iter();
637    /// assert_eq!(i.next(), Some(&DirChild::new("file1.txt", "file1".to_owned())));
638    /// assert_eq!(i.next(), Some(&DirChild::new("file2.txt", "file2".to_owned())));
639    /// assert_eq!(i.next(), None);
640    /// ```
641    pub fn iter(&self) -> DirChildrenIter<'_, T> {
642        DirChildrenIter(self.children.iter())
643    }
644}
645
646impl<T, F> ReadFrom for DirChildren<T, F>
647where
648    T: DirStructureItem,
649    F: Filter,
650{
651    fn read_from(path: &Path) -> Result<Self>
652    where
653        Self: Sized,
654    {
655        let filter = F::make_filter();
656
657        let mut children = Vec::new();
658        for child in path.read_dir().wrap_io_error_with(path)? {
659            let child = child.wrap_io_error_with(path)?;
660            let child_path = child.path();
661
662            if !filter.allows(&child_path) {
663                continue;
664            }
665
666            let value = T::read_from(&child_path)?;
667            let file_name = child.file_name();
668            children.push(DirChild { file_name, value });
669        }
670
671        Ok(DirChildren {
672            self_path: path.to_path_buf(),
673            children,
674            filter: marker::PhantomData,
675        })
676    }
677}
678
679impl<T, F> WriteTo for DirChildren<T, F>
680where
681    T: DirStructureItem,
682    F: Filter,
683{
684    fn write_to(&self, path: &Path) -> Result<()> {
685        for child in &self.children {
686            let child_path = path.join(&child.file_name);
687            child.value.write_to(&child_path)?;
688        }
689
690        Ok(())
691    }
692}
693
694/// A single child of a [`DirChildren`] structure.
695#[derive(Debug, Clone, PartialEq, Eq)]
696pub struct DirChild<T>
697where
698    T: DirStructureItem,
699{
700    /// The file name of the child.
701    file_name: OsString,
702    /// The parsed value of the child.
703    value: T,
704}
705
706impl<T> DirChild<T>
707where
708    T: DirStructureItem,
709{
710    /// Creates a new [`DirChild`] with the specified file name and value.
711    ///
712    /// # Examples
713    ///
714    /// ```rust
715    /// use std::ffi::OsString;
716    /// use dir_structure::DirChild;
717    ///
718    /// let d = DirChild::new("file.txt", "file".to_owned());
719    /// assert_eq!(d.file_name(), &OsString::from("file.txt"));
720    /// assert_eq!(d.value(), &"file".to_owned());
721    /// ```
722    pub fn new(file_name: impl Into<OsString>, value: T) -> Self {
723        Self {
724            file_name: file_name.into(),
725            value,
726        }
727    }
728
729    /// Gets the file name of the child (or the name of the directory; the last segment in the path).
730    ///
731    /// # Examples
732    ///
733    /// ```rust
734    /// use std::ffi::OsString;
735    /// use dir_structure::DirChild;
736    ///
737    /// let d = DirChild::new("file.txt", "file".to_owned());
738    /// assert_eq!(d.file_name(), &OsString::from("file.txt"));
739    /// ```
740    pub fn file_name(&self) -> &OsString {
741        &self.file_name
742    }
743
744    /// Gets the file name of the child (or the name of the directory; the last segment in the path).
745    ///
746    /// Mutable reference version of [`Self::file_name`].
747    ///
748    /// # Examples
749    ///
750    /// ```rust
751    /// use std::ffi::OsString;
752    /// use dir_structure::DirChild;
753    ///
754    /// let mut d = DirChild::new("file.txt", "file".to_owned());
755    /// assert_eq!(d.file_name(), &OsString::from("file.txt"));
756    /// *d.file_name_mut() = OsString::from("new_file.txt");
757    /// assert_eq!(d.file_name(), &OsString::from("new_file.txt"));
758    /// ```
759    pub fn file_name_mut(&mut self) -> &mut OsString {
760        &mut self.file_name
761    }
762
763    /// Gets the value of the child.
764    ///
765    /// This is the parsed value of the file / directory.
766    ///
767    /// # Examples
768    ///
769    /// ```rust
770    /// use std::ffi::OsString;
771    /// use dir_structure::DirChild;
772    ///
773    /// let d = DirChild::new("file.txt", "file".to_owned());
774    /// assert_eq!(d.value(), &"file".to_owned());
775    /// ```
776    pub fn value(&self) -> &T {
777        &self.value
778    }
779
780    /// Gets the value of the child.
781    ///
782    /// This is the parsed value of the file / directory.
783    ///
784    /// Mutable reference version of [`Self::value`].
785    ///
786    /// # Examples
787    ///
788    /// ```rust
789    /// use std::ffi::OsString;
790    /// use dir_structure::DirChild;
791    ///
792    /// let mut d = DirChild::new("file.txt", "file".to_owned());
793    /// assert_eq!(d.value(), &"file".to_owned());
794    /// *d.value_mut() = "new_file".to_owned();
795    /// assert_eq!(d.value(), &"new_file".to_owned());
796    /// ```
797    pub fn value_mut(&mut self) -> &mut T {
798        &mut self.value
799    }
800
801    /// Maps the file name of this [`DirChild`] to a new value.
802    ///
803    /// # Examples
804    ///
805    /// ```rust
806    /// use std::ffi::OsString;
807    /// use dir_structure::DirChild;
808    ///
809    /// let d = DirChild::new("file.txt", "file".to_owned());
810    /// assert_eq!(d.map_file_name(|s| s.to_str().unwrap().to_uppercase()), DirChild::new("FILE.TXT", "file".to_owned()));
811    /// ```
812    pub fn map_file_name<F, O>(self, f: F) -> Self
813    where
814        F: FnOnce(OsString) -> O,
815        O: Into<OsString>,
816    {
817        let file_name = f(self.file_name).into();
818        DirChild {
819            file_name,
820            value: self.value,
821        }
822    }
823
824    /// Maps the value of this [`DirChild`] to a new type.
825    ///
826    /// This is useful for converting the value to a different type,
827    /// for example, if you want to convert the value to a different
828    /// type of [`DirStructureItem`].
829    ///
830    /// # Examples
831    ///
832    /// ```rust
833    /// use std::ffi::OsString;
834    /// use dir_structure::DirChild;
835    /// use dir_structure::FileString;
836    ///
837    /// let d = DirChild::new("file.txt", "file".to_owned());
838    /// assert_eq!(d.map_value(|v| FileString(v)), DirChild::new("file.txt", FileString("file".to_owned())));
839    /// ```
840    pub fn map_value<U, F>(self, f: F) -> DirChild<U>
841    where
842        F: FnOnce(T) -> U,
843        U: DirStructureItem,
844    {
845        let value = f(self.value);
846        DirChild {
847            file_name: self.file_name,
848            value,
849        }
850    }
851}
852
853impl<T> IntoIterator for DirChildren<T>
854where
855    T: DirStructureItem,
856{
857    type Item = DirChild<T>;
858    type IntoIter = std::vec::IntoIter<Self::Item>;
859
860    fn into_iter(self) -> Self::IntoIter {
861        self.children.into_iter()
862    }
863}
864
865/// A [`DirChildren`] iterator. It iterates over the children of a
866/// [`DirChildren`] structure.
867pub struct DirChildrenIter<'a, T: DirStructureItem>(std::slice::Iter<'a, DirChild<T>>);
868
869impl<'a, T> Iterator for DirChildrenIter<'a, T>
870where
871    T: DirStructureItem,
872{
873    type Item = &'a DirChild<T>;
874
875    fn next(&mut self) -> Option<Self::Item> {
876        self.0.next()
877    }
878
879    fn size_hint(&self) -> (usize, Option<usize>) {
880        self.0.size_hint()
881    }
882}
883
884impl<T> ExactSizeIterator for DirChildrenIter<'_, T>
885where
886    T: DirStructureItem,
887{
888    fn len(&self) -> usize {
889        self.0.len()
890    }
891}
892
893impl<T> DoubleEndedIterator for DirChildrenIter<'_, T>
894where
895    T: DirStructureItem,
896{
897    fn next_back(&mut self) -> Option<Self::Item> {
898        self.0.next_back()
899    }
900}
901
902/// A simple macro that generates a [`DirChildren`] newtype, together with
903/// a few impls to make it easy to use.
904#[macro_export]
905macro_rules! dir_children_wrapper {
906    ($vis:vis $name:ident $ty:ty) => {
907        $vis struct $name(pub $crate::DirChildren<$ty>);
908
909        impl $crate::ReadFrom for $name {
910            fn read_from(path: &::std::path::Path) -> $crate::Result<Self>
911            where
912                Self: Sized,
913            {
914                Ok(Self(<$crate::DirChildren<$ty>>::read_from(path)?))
915            }
916        }
917
918        impl $crate::WriteTo for $name {
919            fn write_to(&self, path: &::std::path::Path) -> $crate::Result<()> {
920                self.0.write_to(path)
921            }
922        }
923
924        impl std::ops::Deref for $name {
925            type Target = $crate::DirChildren<$ty>;
926
927            fn deref(&self) -> &Self::Target {
928                &self.0
929            }
930        }
931
932        impl std::ops::DerefMut for $name {
933            fn deref_mut(&mut self) -> &mut Self::Target {
934                &mut self.0
935            }
936        }
937
938        impl std::iter::IntoIterator for $name {
939            type Item = $crate::DirChild<$ty>;
940            type IntoIter = std::vec::IntoIter<Self::Item>;
941
942            fn into_iter(self) -> Self::IntoIter {
943                self.0.into_iter()
944            }
945        }
946    };
947}
948
949pub use dir_structure_macros::DirStructure;
950
951macro_rules! data_format_impl {
952    (
953        $(#[$mod_attr:meta])*
954        $mod_name:ident,
955        $(#[$main_ty_attrs:meta])*
956        $main_ty:ident,
957
958        $from_str_impl:expr,
959        $from_str_error:ty,
960
961        $(#[$to_str_ty_attrs:meta])*
962        $to_str_ty:ident,
963        $to_str_impl:expr,
964        $to_writer_impl:expr,
965        $to_str_error:ty,
966
967        $(#[$writer_ty_attrs:meta])*
968        $writer_ty:ident,
969
970        $extension:literal,
971        $text:literal $(,)?
972    ) => {
973        $(#[$mod_attr])*
974        pub mod $mod_name {
975            #![doc = concat!(r##"
976With the `"##, stringify!($mod_name), r##"` feature, this module provides the [`"##, stringify!($main_ty), r##"`] type,
977
978This allows us to read and parse `"##, stringify!($mod_name), r##"` files to some `serde::Deserialize` type,
979and write them back to disk.
980
981# Examples
982
983## Reading a "##, stringify!($mod_name), r##" file
984
985```
986use std::path::Path;
987
988use dir_structure::DirStructureItem;
989use dir_structure::"##, stringify!($mod_name), "::", stringify!($main_ty), r##";
990
991#[derive(dir_structure::DirStructure)]
992struct Dir {
993    #[dir_structure(path = "f"##, $extension, r##"", with_newtype = "##, stringify!($main_ty), r##"<Obj>)]
994    f: Obj,
995}
996
997#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
998struct Obj {
999    name: String,
1000    age: u32,
1001}
1002
1003fn main() -> Result<(), Box<dyn std::error::Error>> {
1004    let d = Path::new("dir");
1005    std::fs::create_dir_all(&d)?;
1006    std::fs::write(d.join("f"##, $extension, r##""), "##, $text, r##")?;
1007    let dir = Dir::read(&d)?;
1008    assert_eq!(dir.f, Obj { name: "John".to_owned(), age: 30 });
1009    # std::fs::remove_dir_all(&d)?;
1010    Ok(())
1011}
1012```
1013
1014## Writing a "##, stringify!($mod_name), r##" file
1015
1016```
1017use std::path::Path;
1018
1019use dir_structure::DirStructureItem;
1020use dir_structure::"##, stringify!($mod_name), "::", stringify!($main_ty), r##";
1021
1022#[derive(dir_structure::DirStructure)]
1023struct Dir {
1024    #[dir_structure(path = "f"##, $extension, r##"", with_newtype = "##, stringify!($main_ty), r##"<Obj>)]
1025    f: Obj,
1026}
1027
1028#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1029struct Obj {
1030    name: String,
1031    age: u32,
1032}
1033
1034fn main() -> Result<(), Box<dyn std::error::Error>> {
1035    let d = Path::new("dir");
1036    let dir = Dir {
1037        f: Obj {
1038            name: "John".to_owned(),
1039            age: 30,
1040        },
1041    };
1042    dir.write(&d)?;
1043    assert_eq!(std::fs::read_to_string(d.join("f"##, $extension, r##""))?,
1044        "##, $text, r##"
1045    );
1046    # std::fs::remove_dir_all(&d)?;
1047    Ok(())
1048}
1049```
1050"##)]
1051
1052            use std::fmt;
1053            use std::fmt::Formatter;
1054            use std::path::Path;
1055            use std::str::FromStr;
1056
1057            use crate::FromRefForWriter;
1058            use crate::NewtypeToInner;
1059            use crate::ReadFrom;
1060            use crate::WriteTo;
1061
1062            $(#[$main_ty_attrs])*
1063            #[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash)]
1064            #[serde(transparent)]
1065            pub struct $main_ty<T>(#[serde(bound = "")] pub T)
1066            where
1067                T: 'static + serde::Serialize + for<'d> serde::Deserialize<'d>;
1068
1069            impl<T> FromStr for $main_ty<T>
1070            where
1071                T: serde::Serialize + for<'d> serde::Deserialize<'d> + 'static,
1072            {
1073                type Err = $from_str_error;
1074
1075                fn from_str(s: &str) -> Result<Self, Self::Err> {
1076                    $from_str_impl(s).map(Self)
1077                }
1078            }
1079
1080            $(#[$to_str_ty_attrs])*
1081            struct $to_str_ty<'a, T>(&'a T)
1082            where
1083                T: serde::Serialize + 'a;
1084
1085            impl<'a, T> $to_str_ty<'a, T>
1086            where
1087                T: serde::Serialize + 'a
1088            {
1089                fn to_str(&self) -> Result<String, $to_str_error> {
1090                    $to_str_impl(&self.0)
1091                }
1092
1093                fn to_writer<W>(&self, writer: &mut W) -> Result<(), ToWriterError>
1094                where
1095                    W: std::io::Write,
1096                {
1097                    $to_writer_impl(&self.0, writer)
1098                }
1099            }
1100
1101            enum ToWriterError {
1102                #[allow(unused)]
1103                Io(std::io::Error),
1104                Serde($to_str_error),
1105            }
1106
1107            impl<'a, T> fmt::Display for $to_str_ty<'a, T>
1108            where
1109                T: serde::Serialize + 'a,
1110            {
1111                fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1112                    let s = self.to_str().map_err(|_| fmt::Error)?;
1113                    write!(f, "{}", s)
1114                }
1115            }
1116
1117            impl<T> fmt::Display for $main_ty<T>
1118            where
1119                T: serde::Serialize + for<'d> serde::Deserialize<'d> + 'static,
1120            {
1121                fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1122                    $to_str_ty(&self.0).fmt(f)
1123                }
1124            }
1125
1126            impl<T> ReadFrom for $main_ty<T>
1127            where
1128                T: serde::Serialize + for<'d> serde::Deserialize<'d> + 'static,
1129            {
1130                fn read_from(path: &Path) -> crate::Result<Self> {
1131                    let contents = crate::FileString::read_from(path)?.0;
1132                    let v = contents
1133                        .parse::<$main_ty<T>>()
1134                        .map_err(|e| crate::Error::Parse(path.to_path_buf(), e.into()))?;
1135                    Ok(v)
1136                }
1137            }
1138
1139            impl<T> WriteTo for $main_ty<T>
1140            where
1141                T: serde::Serialize + for<'d> serde::Deserialize<'d> + 'static,
1142            {
1143                fn write_to(&self, path: &Path) -> crate::Result<()> {
1144                    Self::from_ref_for_writer(&self.0).write_to(path)
1145                }
1146            }
1147
1148            impl<T> NewtypeToInner for $main_ty<T>
1149            where
1150                T: serde::Serialize + for<'d> serde::Deserialize<'d> + 'static,
1151            {
1152                type Inner = T;
1153
1154                fn into_inner(self) -> Self::Inner {
1155                    self.0
1156                }
1157            }
1158
1159            impl<'a, T> FromRefForWriter<'a> for $main_ty<T>
1160            where
1161                T: serde::Serialize + for<'d> serde::Deserialize<'d> + 'static,
1162            {
1163                type Inner = T;
1164                type Wr = $writer_ty<'a, T>;
1165
1166                fn from_ref_for_writer(value: &'a Self::Inner) -> Self::Wr {
1167                    $writer_ty(value)
1168                }
1169            }
1170
1171            $(#[$writer_ty_attrs])*
1172            pub struct $writer_ty<'a, T>(&'a T)
1173            where
1174                T: serde::Serialize + 'a;
1175
1176            impl<'a, T> WriteTo for $writer_ty<'a, T>
1177            where
1178                T: serde::Serialize + 'a,
1179            {
1180                fn write_to(&self, path: &Path) -> crate::Result<()> {
1181                    let mut f = crate::StreamingFileWriter::new(path)?;
1182                    $to_str_ty(self.0).to_writer(&mut f)
1183                        .map_err(|e| match e {
1184                            ToWriterError::Io(e) => crate::Error::Io(path.to_path_buf(), e),
1185                            ToWriterError::Serde(e) => crate::Error::Serde(path.to_path_buf(), e.into()),
1186                        })?;
1187
1188                    Ok(())
1189                }
1190            }
1191        }
1192    };
1193}
1194
1195data_format_impl!(
1196    #[cfg(feature = "json")]
1197    #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
1198    json,
1199    /// A wrapper around a type that implements [`serde::Serialize`] and [`serde::Deserialize`],
1200    /// thus allowing us to parse and serialize it from / to json when we read / write a
1201    /// directory structure.
1202    Json,
1203    |s| serde_json::from_str(s),
1204    serde_json::Error,
1205    JsonToStr,
1206    |v| serde_json::to_string(&v),
1207    |v, w| serde_json::to_writer(w, v).map_err(ToWriterError::Serde),
1208    serde_json::Error,
1209    /// [`FromRefForWriter`] implementation for [`Json`].
1210    JsonRefWr,
1211    ".json", r##"r#"{"name":"John","age":30}"#"##,
1212);
1213
1214data_format_impl!(
1215    #[cfg(feature = "toml")]
1216    #[cfg_attr(docsrs, doc(cfg(feature = "toml")))]
1217    toml,
1218    /// A wrapper around a type that implements [`serde::Serialize`] and [`serde::Deserialize`],
1219    /// thus allowing us to parse and serialize it from / to toml when we read / write a
1220    /// directory structure.
1221    Toml,
1222    |s| toml::de::from_str(s),
1223    toml::de::Error,
1224    TomlToStr,
1225    |v| toml::ser::to_string(&v),
1226    |v, w: &mut dyn std::io::Write| {
1227        let s = toml::ser::to_string(&v).map_err(ToWriterError::Serde)?;
1228        w.write_all(s.as_bytes()).map_err(ToWriterError::Io)?;
1229        Ok(())
1230    },
1231    toml::ser::Error,
1232    /// [`FromRefForWriter`] implementation for [`Toml`].
1233    TomlRefWr,
1234    ".toml", r##"r#"
1235name = "John"
1236age = 30
1237"#.trim_start()"##,
1238);
1239
1240data_format_impl!(
1241    #[cfg(feature = "yaml")]
1242    #[cfg_attr(docsrs, doc(cfg(feature = "yaml")))]
1243    yaml,
1244    /// A wrapper around a type that implements [`serde::Serialize`] and [`serde::Deserialize`],
1245    /// thus allowing us to parse and serialize it from / to yaml when we read / write a
1246    /// directory structure.
1247    Yaml,
1248    |s| serde_yaml::from_str(s),
1249    serde_yaml::Error,
1250    YamlToStr,
1251    |v| serde_yaml::to_string(&v),
1252    |v, w| serde_yaml::to_writer(w, v).map_err(ToWriterError::Serde),
1253    serde_yaml::Error,
1254    /// [`FromRefForWriter`] implementation for [`Yaml`].
1255    YamlRefWr,
1256    ".yaml", r##"r#"
1257name: John
1258age: 30
1259"#.trim_start()"##,
1260);
1261
1262data_format_impl!(
1263    #[cfg(feature = "ron")]
1264    #[cfg_attr(docsrs, doc(cfg(feature = "ron")))]
1265    ron,
1266    /// A wrapper around a type that implements [`serde::Serialize`] and [`serde::Deserialize`],
1267    /// thus allowing us to parse and serialize it from / to ron when we read / write a
1268    /// directory structure.
1269    Ron,
1270    |s| ron::de::from_str(s),
1271    ron::error::SpannedError,
1272    RonToStr,
1273    |v| ron::ser::to_string(&v),
1274    |v, w| ron::ser::to_writer(w, v).map_err(ToWriterError::Serde),
1275    ron::error::Error,
1276    /// [`FromRefForWriter`] implementation for [`Ron`].
1277    RonRefWr,
1278    ".ron", r##"r#"(name:"John",age:30)"#"##,
1279);
1280
1281/// A wrapper around a type which will use the [`Display`] and [`FromStr`] implementations
1282/// for serialization / deserialization.
1283///
1284/// For example: u8, i8, i16, u16, all integer types... bool etc.
1285///
1286/// # Examples
1287///
1288/// ```rust
1289/// use std::path::Path;
1290/// use dir_structure::DirStructureItem;
1291///
1292/// use dir_structure::FmtWrapper;
1293///
1294/// #[derive(dir_structure::DirStructure, PartialEq, Debug)]
1295/// struct Dir {
1296///    #[dir_structure(path = "f.txt", with_newtype = FmtWrapper<u8>)]
1297///    f: u8,
1298///    #[dir_structure(path = "b.txt", with_newtype = FmtWrapper<bool>)]
1299///    b: bool,
1300/// }
1301///
1302/// fn main() -> Result<(), Box<dyn std::error::Error>> {
1303///     let d = Path::new("dir");
1304///     std::fs::create_dir_all(&d)?;
1305///     std::fs::write(d.join("f.txt"), "42")?;
1306///     std::fs::write(d.join("b.txt"), "true")?;
1307///     let mut dir = Dir::read(&d)?;
1308///     assert_eq!(dir.f, 42);
1309///     assert_eq!(dir.b, true);
1310///     dir.f = 100;
1311///     dir.b = false;
1312///     dir.write(&d)?;
1313///     assert_eq!(std::fs::read_to_string(d.join("f.txt"))?, "100");
1314///     assert_eq!(std::fs::read_to_string(d.join("b.txt"))?, "false");
1315///     # std::fs::remove_dir_all(&d)?;
1316///     Ok(())
1317/// }
1318/// ```
1319pub struct FmtWrapper<T>(pub T);
1320
1321impl<T> NewtypeToInner for FmtWrapper<T> {
1322    type Inner = T;
1323
1324    fn into_inner(self) -> Self::Inner {
1325        self.0
1326    }
1327}
1328
1329impl<T> ReadFrom for FmtWrapper<T>
1330where
1331    T: FromStr,
1332    T::Err: Into<Box<dyn std::error::Error + Send + Sync>>,
1333{
1334    fn read_from(path: &Path) -> Result<Self>
1335    where
1336        Self: Sized,
1337    {
1338        let contents = FileString::read_from(path)?.0;
1339        match contents.parse::<T>() {
1340            Ok(v) => Ok(Self(v)),
1341            Err(e) => Err(Error::Parse(path.to_path_buf(), e.into())),
1342        }
1343    }
1344}
1345
1346impl<T> WriteTo for FmtWrapper<T>
1347where
1348    T: Display,
1349{
1350    fn write_to(&self, path: &Path) -> Result<()> {
1351        Self::from_ref_for_writer(&self.0).write_to(path)
1352    }
1353}
1354
1355impl<'a, T> FromRefForWriter<'a> for FmtWrapper<T>
1356where
1357    T: Display + 'a,
1358{
1359    type Inner = T;
1360    type Wr = FmtWrapperRefWr<'a, T>;
1361
1362    fn from_ref_for_writer(value: &'a Self::Inner) -> Self::Wr {
1363        FmtWrapperRefWr(value)
1364    }
1365}
1366
1367/// A [`WriteTo`] wrapper around a reference to a type which will use the [`Display`]
1368/// implementation to write the value.
1369pub struct FmtWrapperRefWr<'a, T: ?Sized>(pub &'a T);
1370
1371impl<T> WriteTo for FmtWrapperRefWr<'_, T>
1372where
1373    T: Display + ?Sized,
1374{
1375    fn write_to(&self, path: &Path) -> Result<()> {
1376        use std::io::Write;
1377        utils::create_parent_dir(path)?;
1378        let mut f = File::create(path).wrap_io_error_with(path)?;
1379        write!(f, "{}", self.0).wrap_io_error_with(path)?;
1380        Ok(())
1381    }
1382}
1383
1384/// A newtype around a `Vec<u8>`.
1385#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1386pub struct FileBytes(pub Vec<u8>);
1387
1388impl FileBytes {
1389    /// Creates a new [`FileBytes`] from the specified `Vec<u8>`.
1390    pub fn new(v: impl Into<Vec<u8>>) -> Self {
1391        Self(v.into())
1392    }
1393}
1394
1395impl ReadFrom for FileBytes {
1396    fn read_from(path: &Path) -> Result<Self>
1397    where
1398        Self: Sized,
1399    {
1400        std::fs::read(path).wrap_io_error_with(path).map(Self)
1401    }
1402}
1403
1404impl WriteTo for FileBytes {
1405    fn write_to(&self, path: &Path) -> Result<()> {
1406        Self::from_ref_for_writer(&self.0).write_to(path)
1407    }
1408}
1409
1410impl From<FileBytes> for Vec<u8> {
1411    fn from(value: FileBytes) -> Self {
1412        value.0
1413    }
1414}
1415
1416impl From<Vec<u8>> for FileBytes {
1417    fn from(value: Vec<u8>) -> Self {
1418        Self(value)
1419    }
1420}
1421
1422impl NewtypeToInner for FileBytes {
1423    type Inner = Vec<u8>;
1424
1425    fn into_inner(self) -> Self::Inner {
1426        self.0
1427    }
1428}
1429
1430impl<'a> FromRefForWriter<'a> for FileBytes {
1431    type Inner = [u8];
1432    type Wr = FileBytesRefWr<'a>;
1433
1434    fn from_ref_for_writer(value: &'a Self::Inner) -> Self::Wr {
1435        FileBytesRefWr(value)
1436    }
1437}
1438
1439/// The [`WriteTo`] wrapper around a reference to a `[u8]`.
1440pub struct FileBytesRefWr<'a>(&'a [u8]);
1441
1442impl WriteTo for FileBytesRefWr<'_> {
1443    fn write_to(&self, path: &Path) -> Result<()> {
1444        utils::create_parent_dir(path)?;
1445        std::fs::write(path, self.0).wrap_io_error_with(path)?;
1446        Ok(())
1447    }
1448}
1449
1450/// A newtype around a [`String`].
1451#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1452pub struct FileString(pub String);
1453
1454impl FileString {
1455    /// Creates a new [`FileString`] from the specified [`String`].
1456    pub fn new(s: impl Into<String>) -> Self {
1457        Self(s.into())
1458    }
1459}
1460
1461impl From<FileString> for String {
1462    fn from(value: FileString) -> Self {
1463        value.0
1464    }
1465}
1466
1467impl From<String> for FileString {
1468    fn from(value: String) -> Self {
1469        Self(value)
1470    }
1471}
1472
1473impl NewtypeToInner for FileString {
1474    type Inner = String;
1475
1476    fn into_inner(self) -> Self::Inner {
1477        self.0
1478    }
1479}
1480
1481impl ReadFrom for FileString {
1482    fn read_from(path: &Path) -> Result<Self>
1483    where
1484        Self: Sized,
1485    {
1486        std::fs::read_to_string(path)
1487            .wrap_io_error_with(path)
1488            .map(Self)
1489    }
1490}
1491
1492impl WriteTo for FileString {
1493    fn write_to(&self, path: &Path) -> Result<()> {
1494        Self::from_ref_for_writer(&self.0).write_to(path)
1495    }
1496}
1497
1498impl<'a> FromRefForWriter<'a> for FileString {
1499    type Inner = str;
1500    type Wr = FileStrWr<'a>;
1501
1502    fn from_ref_for_writer(value: &'a Self::Inner) -> Self::Wr {
1503        FileStrWr(value)
1504    }
1505}
1506
1507/// The [`WriteTo`] wrapper around a reference to a [`str`].
1508pub struct FileStrWr<'a>(&'a str);
1509
1510impl WriteTo for FileStrWr<'_> {
1511    fn write_to(&self, path: &Path) -> Result<()> {
1512        FileBytes::from_ref_for_writer(self.0.as_bytes()).write_to(path)
1513    }
1514}
1515
1516impl<T> ReadFrom for Option<T>
1517where
1518    T: ReadFrom,
1519{
1520    fn read_from(path: &Path) -> Result<Self>
1521    where
1522        Self: Sized,
1523    {
1524        if path.exists() {
1525            T::read_from(path).map(Some)
1526        } else {
1527            Ok(None)
1528        }
1529    }
1530}
1531
1532impl<T> WriteTo for Option<T>
1533where
1534    T: WriteTo,
1535{
1536    fn write_to(&self, path: &Path) -> Result<()> {
1537        if let Some(v) = self {
1538            v.write_to(path)
1539        } else {
1540            Ok(())
1541        }
1542    }
1543}
1544
1545/// A wrapper that defers the reading of a file until it is actually needed.
1546///
1547/// The only thing you can do with a [`DeferredRead`] is to call [`DeferredRead::perform_read`],
1548/// which will read the file and return the value.
1549///
1550/// See the [`DeferredRead::perform_read`] method for more details.
1551#[derive(Debug, Clone, Hash)]
1552pub struct DeferredRead<T>(pub PathBuf, marker::PhantomData<T>)
1553where
1554    T: ReadFrom;
1555
1556impl<T> ReadFrom for DeferredRead<T>
1557where
1558    T: ReadFrom,
1559{
1560    fn read_from(path: &Path) -> Result<Self>
1561    where
1562        Self: Sized,
1563    {
1564        Ok(Self(path.to_path_buf(), marker::PhantomData))
1565    }
1566}
1567
1568impl<T> DeferredRead<T>
1569where
1570    T: ReadFrom,
1571{
1572    /// Performs the read and returns the value.
1573    ///
1574    /// If the value changed on disk since the [`DeferredRead`] was created, then the
1575    /// new value will be read from disk and returned.
1576    ///
1577    /// For a cached version see [`DeferredReadOrOwn`].
1578    ///
1579    /// # Examples
1580    ///
1581    /// ```rust
1582    /// use std::path::Path;
1583    /// use dir_structure::DirStructureItem;
1584    /// use dir_structure::DeferredRead;
1585    ///
1586    /// #[derive(dir_structure::DirStructure)]
1587    /// struct Dir {
1588    ///     #[dir_structure(path = "f.txt")]
1589    ///     f: DeferredRead<String>,
1590    /// }
1591    ///
1592    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
1593    ///     let d = Path::new("dir");
1594    ///
1595    ///     std::fs::create_dir_all(&d)?;
1596    ///     std::fs::write(d.join("f.txt"), "Hello, world!")?;
1597    ///
1598    ///     let dir = Dir::read(&d)?;
1599    ///     assert_eq!(dir.f.perform_read()?, "Hello, world!");
1600    ///
1601    ///     std::fs::write(d.join("f.txt"), "Goodbye, world!")?;
1602    ///     assert_eq!(dir.f.perform_read()?, "Goodbye, world!");
1603    ///
1604    ///     # std::fs::remove_dir_all(&d)?;
1605    ///     Ok(())
1606    /// }
1607    /// ```
1608    pub fn perform_read(&self) -> Result<T> {
1609        T::read_from(&self.0)
1610    }
1611}
1612
1613impl<T> WriteTo for DeferredRead<T>
1614where
1615    T: ReadFrom + WriteTo,
1616{
1617    fn write_to(&self, path: &Path) -> Result<()> {
1618        if path == self.0 {
1619            // Optimization: We were asked to write to the same path
1620            // we are supposed to read from. We can just ignore it, since
1621            // the file / directory should already be in the given state.
1622
1623            // If `T` has trivial `ReadFrom` / `WriteTo` implementations,
1624            // this should not be a problem, but if it is, a custom `DeferredRead`
1625            // implementation should be written for it.
1626            return Ok(());
1627        }
1628
1629        let r = self.perform_read()?;
1630        r.write_to(path)
1631    }
1632}
1633
1634/// A wrapper that defers the reading of a file until it is actually needed,
1635/// but can also store the value.
1636///
1637/// It allows us to read the value from disk, and then store it in memory,
1638/// and if we ever need it again, we can just return the stored value.
1639///
1640/// This type exposes 2 functions: [`DeferredReadOrOwn::get`] and
1641/// [`DeferredReadOrOwn::perform_and_store_read`].
1642///
1643/// The table below summarizes the differences between the two functions:
1644///
1645/// | State             | [`DeferredReadOrOwn::get`]               | [`DeferredReadOrOwn::perform_and_store_read`] |
1646/// |-------------------|------------------------------------------|-----------------------------------------------|
1647/// | New, not cached   | Reads the value, does not cache          | Reads the value, and caches it                |
1648/// | Cached            | Returns the cached value                 | Returns the cached value                      |
1649///
1650/// As such, [`DeferredReadOrOwn::get`] has the signature of `fn(&self) -> Result<T>` and
1651/// [`DeferredReadOrOwn::perform_and_store_read`] has the signature of `fn(&mut self) -> Result<&T>`.
1652///
1653/// If you never call [`DeferredReadOrOwn::perform_and_store_read`], and only ever call [`DeferredReadOrOwn::get`],
1654/// that would effectively be the same as using a [`DeferredRead`], and that should be preferred instead.
1655#[derive(Debug, Clone, Hash)]
1656pub enum DeferredReadOrOwn<T>
1657where
1658    T: ReadFrom,
1659{
1660    Own(T),
1661    Deferred(DeferredRead<T>),
1662}
1663
1664impl<T> DeferredReadOrOwn<T>
1665where
1666    T: ReadFrom,
1667{
1668    /// Gets the value. If it is not already read, it will read it, but without saving it.
1669    ///
1670    /// This is useful if you want to read the value, but you don't want to store it.
1671    ///
1672    /// Though never calling [`DeferredReadOrOwn::perform_and_store_read`] and only calling
1673    /// [`DeferredReadOrOwn::get`] is equivalent to using a [`DeferredRead`], and that should be preferred.
1674    ///
1675    /// See [`DeferredReadOrOwn`] for more details.
1676    ///
1677    /// # Examples
1678    ///
1679    /// ```rust
1680    /// use std::path::Path;
1681    /// use dir_structure::DirStructureItem;
1682    /// use dir_structure::DeferredRead;
1683    /// use dir_structure::DeferredReadOrOwn;
1684    /// use dir_structure::ReadFrom;
1685    ///
1686    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
1687    ///     let d = Path::new("dir");
1688    ///     std::fs::create_dir_all(&d)?;
1689    ///     let deferred = DeferredReadOrOwn::<String>::Deferred(
1690    ///         DeferredRead::read_from(&d.join("f.txt")).unwrap()
1691    ///     );
1692    ///     assert!(deferred.get().is_err());
1693    ///     std::fs::write(d.join("f.txt"), "Hello, world!")?;
1694    ///     assert_eq!(deferred.get()?, "Hello, world!");
1695    ///     std::fs::write(d.join("f.txt"), "Goodbye, world!")?;
1696    ///     assert_eq!(deferred.get()?, "Goodbye, world!");
1697    ///     # std::fs::remove_dir_all(&d)?;
1698    ///     Ok(())
1699    /// }
1700    /// ```
1701    pub fn get(&self) -> Result<T>
1702    where
1703        T: Clone,
1704    {
1705        match self {
1706            DeferredReadOrOwn::Own(own) => Ok(own.clone()),
1707            DeferredReadOrOwn::Deferred(d) => Ok(d.perform_read()?),
1708        }
1709    }
1710
1711    /// Performs the read and stores the value. If the value is already read, it will
1712    /// just return a reference to it.
1713    ///
1714    /// See [`DeferredReadOrOwn`] for more details.
1715    ///
1716    /// # Examples
1717    ///
1718    /// ```rust
1719    /// use std::path::Path;
1720    /// use dir_structure::DirStructureItem;
1721    /// use dir_structure::DeferredRead;
1722    /// use dir_structure::DeferredReadOrOwn;
1723    /// use dir_structure::ReadFrom;
1724    ///
1725    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
1726    ///     let d = Path::new("dir");
1727    ///     std::fs::create_dir_all(&d)?;
1728    ///     let mut deferred = DeferredReadOrOwn::<String>::Deferred(
1729    ///         DeferredRead::read_from(&d.join("f.txt")).unwrap()
1730    ///     );
1731    ///     assert!(deferred.perform_and_store_read().is_err());
1732    ///     std::fs::write(d.join("f.txt"), "Hello, world!")?;
1733    ///     assert_eq!(deferred.perform_and_store_read()?, "Hello, world!");
1734    ///     std::fs::write(d.join("f.txt"), "Goodbye, world!")?;
1735    ///     assert_eq!(deferred.perform_and_store_read()?, "Hello, world!");
1736    ///     # std::fs::remove_dir_all(&d)?;
1737    ///     Ok(())
1738    /// }
1739    /// ```
1740    pub fn perform_and_store_read(&mut self) -> Result<&T> {
1741        match self {
1742            DeferredReadOrOwn::Own(own) => Ok(own),
1743            DeferredReadOrOwn::Deferred(d) => {
1744                let value = d.perform_read()?;
1745                *self = DeferredReadOrOwn::Own(value);
1746                let DeferredReadOrOwn::Own(own) = self else {
1747                    unreachable!()
1748                };
1749                Ok(own)
1750            }
1751        }
1752    }
1753}
1754
1755impl<T> ReadFrom for DeferredReadOrOwn<T>
1756where
1757    T: ReadFrom,
1758{
1759    fn read_from(path: &Path) -> Result<Self>
1760    where
1761        Self: Sized,
1762    {
1763        ReadFrom::read_from(path).map(Self::Deferred)
1764    }
1765}
1766
1767impl<T> WriteTo for DeferredReadOrOwn<T>
1768where
1769    T: ReadFrom + WriteTo,
1770{
1771    fn write_to(&self, path: &Path) -> Result<()> {
1772        match self {
1773            DeferredReadOrOwn::Own(own) => own.write_to(path),
1774            DeferredReadOrOwn::Deferred(d) => d.write_to(path),
1775        }
1776    }
1777}
1778
1779/// A newtype that will clean the directory it is written to, before writing
1780/// the value.
1781///
1782/// This is useful when we want to write a directory structure, but we want
1783/// to make sure that the directory is clean before writing it, so that there
1784/// are no old files / directories left in it.
1785///
1786/// ```rust
1787/// use std::path::Path;
1788///
1789/// use dir_structure::DirStructureItem;
1790/// use dir_structure::CleanDir;
1791///
1792/// #[derive(dir_structure::DirStructure)]
1793/// struct Dir {
1794///    #[dir_structure(path = "f.txt")]
1795///    f: String,
1796/// }
1797///
1798/// fn main() -> Result<(), Box<dyn std::error::Error>> {
1799///     let d = Path::new("dir");
1800///     std::fs::create_dir_all(&d)?;
1801///     std::fs::write(d.join("f.txt"), "Hello, world!")?;
1802///     std::fs::write(d.join("f2.txt"), "Hello, world! (2)")?;
1803///     let dir = Dir::read(&d)?;
1804///     assert_eq!(dir.f, "Hello, world!");
1805///     assert_eq!(std::fs::read_to_string(d.join("f2.txt"))?, "Hello, world! (2)");
1806///     CleanDir(dir).write(&d)?;
1807///     assert_eq!(std::fs::read_to_string(d.join("f.txt"))?, "Hello, world!");
1808///     assert!(!d.join("f2.txt").exists());
1809///     # std::fs::remove_dir_all(&d)?;
1810///     Ok(())
1811/// }
1812/// ```
1813pub struct CleanDir<T: DirStructureItem>(pub T);
1814
1815impl<T> ReadFrom for CleanDir<T>
1816where
1817    T: DirStructureItem,
1818{
1819    fn read_from(path: &Path) -> Result<Self>
1820    where
1821        Self: Sized,
1822    {
1823        Ok(Self(T::read_from(path)?))
1824    }
1825}
1826
1827impl<T> WriteTo for CleanDir<T>
1828where
1829    T: DirStructureItem,
1830{
1831    fn write_to(&self, path: &Path) -> Result<()> {
1832        Self::from_ref_for_writer(&self.0).write_to(path)
1833    }
1834}
1835
1836impl<'a, T> FromRefForWriter<'a> for CleanDir<T>
1837where
1838    T: DirStructureItem + 'a,
1839{
1840    type Inner = T;
1841    type Wr = CleanDirRefWr<'a, T>;
1842
1843    fn from_ref_for_writer(value: &'a Self::Inner) -> Self::Wr {
1844        CleanDirRefWr(value)
1845    }
1846}
1847
1848impl<T> NewtypeToInner for CleanDir<T>
1849where
1850    T: DirStructureItem,
1851{
1852    type Inner = T;
1853
1854    fn into_inner(self) -> Self::Inner {
1855        self.0
1856    }
1857}
1858
1859/// [`WriteTo`] impl for [`CleanDir`]
1860pub struct CleanDirRefWr<'a, T: ?Sized + DirStructureItem>(&'a T);
1861
1862impl<T> WriteTo for CleanDirRefWr<'_, T>
1863where
1864    T: ?Sized + DirStructureItem,
1865{
1866    fn write_to(&self, path: &Path) -> Result<()> {
1867        if path.exists() {
1868            std::fs::remove_dir_all(path).wrap_io_error_with(path)?;
1869        } else {
1870            utils::create_parent_dir(path)?;
1871        }
1872        self.0.write_to(path)
1873    }
1874}
1875
1876/// A versioned value. This is a wrapper around a value that will keep track of
1877/// how many times it has been changed. This is useful to not write the value
1878/// to disk if it hasn't changed.
1879///
1880/// You can get a reference to the value via its [`Deref`] implementation, and
1881/// you can get a mutable reference to the value via its [`DerefMut`] implementation.
1882///
1883/// The version is incremented every time [`DerefMut::deref_mut`] is called.
1884///
1885/// Alternatively, for [`Eq`] types, you can use the [`Versioned::edit_eq_check`]
1886/// method to edit the value, and it will increment the version if the value has changed.
1887///
1888/// # Example
1889///
1890/// ```
1891/// use dir_structure::VersionedString;
1892///
1893/// let mut v = VersionedString::new("value".to_owned(), "path");
1894/// assert!(v.is_clean());
1895/// assert!(!v.is_dirty());
1896///
1897/// *v = "new value".to_owned();
1898/// assert!(v.is_dirty());
1899/// ```
1900#[derive(Debug, Clone, Hash)]
1901pub struct Versioned<T: DirStructureItem> {
1902    value: T,
1903    version: usize,
1904    path: PathBuf,
1905}
1906
1907impl<T: DirStructureItem> Versioned<T> {
1908    const DEFAULT_VERSION: usize = 0;
1909
1910    /// Creates a new [`Versioned`] with the specified value.
1911    ///
1912    /// The version is set to the default value.
1913    pub fn new(value: T, path: impl Into<PathBuf>) -> Self {
1914        Self {
1915            value,
1916            version: Self::DEFAULT_VERSION,
1917            path: path.into(),
1918        }
1919    }
1920
1921    /// Creates a new [`Versioned`] with the specified value, and in a dirty state.
1922    ///
1923    /// # Example
1924    ///
1925    /// ```
1926    /// use dir_structure::VersionedString;
1927    ///
1928    /// let v = VersionedString::new_dirty("value".to_owned(), "path");
1929    /// assert!(v.is_dirty());
1930    /// ```
1931    pub fn new_dirty(value: T, path: impl Into<PathBuf>) -> Self {
1932        Self {
1933            value,
1934            version: Self::DEFAULT_VERSION + 1,
1935            path: path.into(),
1936        }
1937    }
1938
1939    /// Checks if the value has been changed.
1940    pub fn is_dirty(&self) -> bool {
1941        !self.is_clean()
1942    }
1943
1944    /// Checks if the value has not been changed.
1945    pub fn is_clean(&self) -> bool {
1946        self.version == Self::DEFAULT_VERSION
1947    }
1948
1949    /// Edits the value using the provided closure, and increments the version
1950    /// if the value has changed.
1951    ///
1952    /// # Example
1953    ///
1954    /// ```
1955    /// use dir_structure::VersionedString;
1956    ///
1957    /// let mut v = VersionedString::new("value".to_owned(), "path");
1958    ///
1959    /// v.edit_eq_check(|s| *s = "value".to_owned());
1960    /// assert!(v.is_clean());
1961    /// v.edit_eq_check(|s| *s = "new value".to_owned());
1962    /// assert!(v.is_dirty());
1963    /// ```
1964    pub fn edit_eq_check(&mut self, f: impl FnOnce(&mut T))
1965    where
1966        T: Eq + Clone,
1967    {
1968        let copy = self.value.clone();
1969
1970        f(&mut self.value);
1971
1972        if copy != self.value {
1973            self.version += 1;
1974        }
1975    }
1976}
1977
1978impl<T: DirStructureItem> ReadFrom for Versioned<T> {
1979    fn read_from(path: &Path) -> Result<Self>
1980    where
1981        Self: Sized,
1982    {
1983        T::read_from(path).map(|it| Self::new(it, path))
1984    }
1985}
1986
1987impl<T: DirStructureItem> WriteTo for Versioned<T> {
1988    fn write_to(&self, path: &Path) -> Result<()> {
1989        if self.path == path && self.is_clean() {
1990            return Ok(());
1991        }
1992
1993        self.value.write_to(path)
1994    }
1995}
1996
1997impl<T: DirStructureItem> Deref for Versioned<T> {
1998    type Target = T;
1999
2000    fn deref(&self) -> &Self::Target {
2001        &self.value
2002    }
2003}
2004
2005impl<T: DirStructureItem> DerefMut for Versioned<T> {
2006    fn deref_mut(&mut self) -> &mut Self::Target {
2007        // We will assume that the value has changed, if `deref_mut` was called.
2008        // So we increment the version.
2009        self.version += 1;
2010
2011        &mut self.value
2012    }
2013}
2014
2015pub type VersionedString = Versioned<String>;
2016pub type VersionedBytes = Versioned<Vec<u8>>;
2017
2018// Impls for std types.
2019
2020impl ReadFrom for String {
2021    fn read_from(path: &Path) -> Result<Self>
2022    where
2023        Self: Sized,
2024    {
2025        FileString::read_from(path).map(|v| v.0)
2026    }
2027}
2028
2029impl WriteTo for String {
2030    fn write_to(&self, path: &Path) -> Result<()> {
2031        FileString::from_ref_for_writer(self).write_to(path)
2032    }
2033}
2034
2035impl ReadFrom for Vec<u8> {
2036    fn read_from(path: &Path) -> Result<Self>
2037    where
2038        Self: Sized,
2039    {
2040        FileBytes::read_from(path).map(|v| v.0)
2041    }
2042}
2043
2044impl WriteTo for Vec<u8> {
2045    fn write_to(&self, path: &Path) -> Result<()> {
2046        FileBytes::from_ref_for_writer(self).write_to(path)
2047    }
2048}
2049
2050impl WriteTo for str {
2051    fn write_to(&self, path: &Path) -> Result<()> {
2052        FileStrWr(self).write_to(path)
2053    }
2054}
2055
2056impl WriteTo for &str {
2057    fn write_to(&self, path: &Path) -> Result<()> {
2058        FileStrWr(self).write_to(path)
2059    }
2060}
2061
2062impl WriteTo for [u8] {
2063    fn write_to(&self, path: &Path) -> Result<()> {
2064        FileBytesRefWr(self).write_to(path)
2065    }
2066}
2067
2068impl WriteTo for &[u8] {
2069    fn write_to(&self, path: &Path) -> Result<()> {
2070        FileBytesRefWr(self).write_to(path)
2071    }
2072}
2073
2074mod utils {
2075    use crate::WrapIoError;
2076
2077    pub fn create_parent_dir(path: &std::path::Path) -> crate::Result<()> {
2078        if let Some(parent) = path.parent() {
2079            if !parent.exists() {
2080                std::fs::create_dir_all(parent).wrap_io_error_with(parent)?;
2081            }
2082        }
2083        Ok(())
2084    }
2085}
2086
2087struct StreamingFileWriter {
2088    f: File,
2089}
2090
2091impl StreamingFileWriter {
2092    fn new(path: &Path) -> Result<Self> {
2093        utils::create_parent_dir(path)?;
2094        let f = File::create(path).wrap_io_error_with(path)?;
2095        Ok(Self { f })
2096    }
2097}
2098
2099impl std::io::Write for StreamingFileWriter {
2100    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
2101        self.f.write(buf)
2102    }
2103
2104    fn flush(&mut self) -> std::io::Result<()> {
2105        self.f.flush()
2106    }
2107}
2108
2109impl std::fmt::Write for StreamingFileWriter {
2110    fn write_str(&mut self, s: &str) -> std::fmt::Result {
2111        use std::io::Write;
2112
2113        self.f
2114            .write_all(s.as_bytes())
2115            .map_err(|_| std::fmt::Error)?;
2116        Ok(())
2117    }
2118}