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//! [An intro guide.](https://nrx.dnbln.dev/docs/dx/dir-structure/guide)
7//!
8//! # Example
9//!
10//! ## Writing a structure to disk
11//!
12#![cfg_attr(feature = "derive", doc = "```rust")]
13#![cfg_attr(not(feature = "derive"), doc = "```rust,compile_fail")]
14//! use std::path::Path;
15//! fn main() -> Result<(), Box<dyn std::error::Error>> {
16//!     use dir_structure::traits::sync::DirStructureItem;
17//!     #[derive(dir_structure::DirStructure)]
18//!     struct Dir {
19//!         #[dir_structure(path = "f1.txt")]
20//!         f1: String,
21//!         #[dir_structure(path = "subdir/f2.txt")]
22//!         f2: String,
23//!         // default path is just a file name from the field's name.
24//!         f3: String,
25//!         // also works with nested structures
26//!         #[dir_structure(path = "subdir2")]
27//!         subdir: Subdir,
28//!     }
29//!     #[derive(dir_structure::DirStructure)]
30//!     struct Subdir {
31//!         #[dir_structure(path = "f4.txt")]
32//!         f4: String,
33//!     }
34//!
35//!     let d = Path::new("dir");
36//!     Dir {
37//!         f1: "f1".to_owned(),
38//!         f2: "f2".to_owned(),
39//!         f3: "f3".to_owned(),
40//!         subdir: Subdir {
41//!             f4: "f4".to_owned(),
42//!         },
43//!     }.write(&d)?;
44//!     assert_eq!(std::fs::read_to_string(d.join("f1.txt"))?, "f1");
45//!     assert_eq!(std::fs::read_to_string(d.join("subdir/f2.txt"))?, "f2");
46//!     assert_eq!(std::fs::read_to_string(d.join("f3"))?, "f3");
47//!     assert_eq!(std::fs::read_to_string(d.join("subdir2/f4.txt"))?, "f4");
48//!
49//!     # std::fs::remove_dir_all(&d)?;
50//!
51//!     Ok(())
52//! }
53//! ```
54//!
55//! ## Reading a structure from disk
56//!
57#![cfg_attr(feature = "derive", doc = "```rust")]
58#![cfg_attr(not(feature = "derive"), doc = "```rust,compile_fail")]
59//! use std::path::Path;
60//! fn main() -> Result<(), Box<dyn std::error::Error>> {
61//!     use dir_structure::traits::sync::DirStructureItem;
62//!     #[derive(dir_structure::DirStructure)]
63//!     struct Dir {
64//!         #[dir_structure(path = "f1.txt")]
65//!         f1: String,
66//!         #[dir_structure(path = "subdir/f2.txt")]
67//!         f2: String,
68//!         // default path is just a file name from the field's name.
69//!         f3: String,
70//!         // also works with nested structures
71//!         #[dir_structure(path = "subdir2")]
72//!         subdir: Subdir,
73//!     }
74//!     #[derive(dir_structure::DirStructure)]
75//!     struct Subdir {
76//!         #[dir_structure(path = "f4.txt")]
77//!         f4: String,
78//!     }
79//!     let d = Path::new("dir");
80//!     std::fs::create_dir_all(&d)?;
81//!     std::fs::create_dir_all(d.join("subdir"))?;
82//!     std::fs::create_dir_all(d.join("subdir2"))?;
83//!     std::fs::write(d.join("f1.txt"), "f1")?;
84//!     std::fs::write(d.join("subdir/f2.txt"), "f2")?;
85//!     std::fs::write(d.join("f3"), "f3")?;
86//!     std::fs::write(d.join("subdir2/f4.txt"), "f4")?;
87//!     let dir = Dir::read(&d)?;
88//!     assert_eq!(dir.f1, "f1");
89//!     assert_eq!(dir.f2, "f2");
90//!     assert_eq!(dir.f3, "f3");
91//!     assert_eq!(dir.subdir.f4, "f4");
92//!
93//!     # std::fs::remove_dir_all(&d)?;
94//!
95//!     Ok(())
96//! }
97//! ```
98
99#![cfg_attr(docsrs, feature(doc_cfg))]
100#![cfg_attr(feature = "resolve-path", feature(adt_const_params))]
101#![cfg_attr(feature = "include_dir", feature(normalize_lexically))]
102#![deny(missing_docs)]
103
104#[cfg(feature = "async")]
105pub extern crate pin_project;
106
107#[cfg(feature = "include_dir")]
108pub extern crate include_dir;
109
110#[cfg(doctest)]
111mod __doc_check {
112    mod guide {
113        include!("../../../../doc/docs/content/docs/dx/dir-structure/.guide.mdx.doctests");
114    }
115
116    mod plumbing_guide {
117        include!("../../../../doc/docs/content/docs/dx/dir-structure/.custom-impl.mdx.doctests");
118    }
119
120    // need default features for README examples to work
121    #[cfg(feature = "derive")]
122    #[doc = include_str!("../README.md")]
123    struct Readme;
124}
125
126#[cfg(feature = "derive")]
127pub use dir_structure_macros::DirStructure;
128#[cfg(all(feature = "derive", feature = "async"))]
129pub use dir_structure_macros::DirStructureAsync;
130#[cfg(all(feature = "derive", feature = "resolve-path"))]
131pub use dir_structure_macros::HasField;
132
133pub mod prelude {
134    //! A prelude for the most commonly used items in this crate.
135    #[cfg(feature = "derive")]
136    pub use crate::DirStructure;
137    #[cfg(feature = "async")]
138    pub use crate::traits::asy::ReadFromAsync;
139    #[cfg(feature = "async")]
140    pub use crate::traits::asy::WriteToAsync;
141    #[cfg(feature = "async")]
142    pub use crate::traits::asy::WriteToAsyncRef;
143    #[cfg(feature = "async")]
144    pub use crate::traits::async_vfs::VfsAsync;
145    #[cfg(feature = "async")]
146    pub use crate::traits::async_vfs::VfsAsyncExt;
147    #[cfg(feature = "async")]
148    pub use crate::traits::async_vfs::WriteSupportingVfsAsyncExt;
149    pub use crate::traits::sync::DirStructureItem;
150    pub use crate::traits::sync::ReadFrom;
151    pub use crate::traits::sync::WriteTo;
152    pub use crate::traits::vfs::PathType;
153    pub use crate::traits::vfs::Vfs;
154    pub use crate::traits::vfs::VfsCore;
155    pub use crate::traits::vfs::VfsExt;
156    pub use crate::traits::vfs::WriteSupportingVfsExt;
157}
158
159#[cfg(feature = "tools-atomic-dir")]
160pub mod atomic_dir;
161#[cfg(feature = "tools-clean-dir")]
162pub mod clean_dir;
163#[cfg(feature = "tools-data-formats")]
164pub mod data_formats;
165#[cfg(feature = "tools-deferred-read")]
166pub mod deferred_read;
167#[cfg(feature = "tools-deferred-read-or-own")]
168pub mod deferred_read_or_own;
169#[cfg(feature = "tools-dir-children")]
170pub mod dir_children;
171#[cfg(feature = "tools-dir-descendants")]
172pub mod dir_descendants;
173pub mod error;
174#[cfg(feature = "tools-fmt-wrapper")]
175pub mod fmt_wrapper;
176#[cfg(feature = "image")]
177#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
178pub mod image;
179pub mod option;
180pub mod std_types;
181pub mod traits;
182#[cfg(feature = "tools-try-parse")]
183pub mod try_parse;
184#[cfg(feature = "tools-versioned")]
185pub mod versioned;
186#[cfg(feature = "tools-versioned-hash")]
187pub mod versioned_hash;
188pub mod vfs;
189
190/// A [`Filter`](dir_children::Filter), [`FileFilter`](dir_descendants::FileFilter),
191/// [`FolderFilter`](dir_descendants::FolderFilter), and [`FolderRecurseFilter`](dir_descendants::FolderRecurseFilter) that allows all paths.
192///
193/// This can be passed as a filter to [`DirChildren`](dir_children::DirChildren) and [`DirDescendants`](dir_descendants::DirDescendants) to read all paths; custom
194/// filtering will require a new filter type.
195///
196/// ```rust
197/// # use std::path::Path;
198/// # use dir_structure::{NoFilter, dir_children::Filter};
199/// #
200/// assert!(NoFilter::allows(Path::new("foo.txt")));
201/// assert!(NoFilter::allows(Path::new("foo/bar.txt")));
202/// assert!(NoFilter::allows(Path::new("foo/bar/baz.txt")));
203/// assert!(NoFilter::allows(Path::new("foo/bar/baz")));
204/// assert!(NoFilter::allows(Path::new("foo/bar/baz/")));
205/// assert!(NoFilter::allows(Path::new("foo/bar/baz/.")));
206/// assert!(NoFilter::allows(Path::new("foo/bar/baz/..")));
207/// assert!(NoFilter::allows(Path::new("foo/bar/baz/../..")));
208/// assert!(NoFilter::allows(Path::new("foo/bar/baz/../../..")));
209/// assert!(NoFilter::allows(Path::new("foo/bar/baz/../../../..")));
210/// assert!(NoFilter::allows(Path::new("foo/bar/baz/../../../../..")));
211/// assert!(NoFilter::allows(Path::new("foo/bar/baz/../../../../../..")));
212/// ```
213#[cfg(any(feature = "tools-dir-children", feature = "tools-dir-descendants",))]
214#[derive(Debug, Clone, Copy, PartialEq, Eq)]
215#[cfg_attr(feature = "assert_eq", derive(assert_eq::AssertEq))]
216pub struct NoFilter;
217
218#[cfg(test)]
219mod test_utils {
220    use crate::traits::vfs;
221    pub(crate) fn assert_is_read_from<
222        'vfs,
223        Vfs: vfs::Vfs<'vfs>,
224        T: crate::traits::sync::ReadFrom<'vfs, Vfs>,
225    >() {
226    }
227    pub(crate) fn assert_is_write_to<
228        'vfs,
229        Vfs: vfs::WriteSupportingVfs<'vfs>,
230        T: crate::traits::sync::WriteTo<'vfs, Vfs>,
231    >() {
232    }
233}