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}