dir_structure/dir_children.rs
1//! A structure representing the children of a directory.
2//!
3//! See [`DirChildren`] for more details.
4//!
5//! Additionally, [`ForceCreateDirChildren`] is a variant that forces the creation of the directory
6//! structure, even without any children.
7
8use std::fmt;
9use std::hash;
10use std::marker;
11use std::marker::PhantomData;
12use std::mem;
13use std::ops::Deref;
14use std::ops::DerefMut;
15use std::ops::RangeBounds;
16use std::path::Path;
17use std::pin::Pin;
18use std::slice;
19#[cfg(feature = "async")]
20use std::task::Context;
21#[cfg(feature = "async")]
22use std::task::Poll;
23use std::vec;
24
25#[cfg(feature = "async")]
26use futures::Stream;
27#[cfg(feature = "async")]
28use pin_project::pin_project;
29
30use crate::NoFilter;
31use crate::error::Error;
32use crate::error::VfsResult;
33use crate::prelude::*;
34#[cfg(feature = "async")]
35use crate::traits::asy::ReadFromAsync;
36#[cfg(feature = "async")]
37use crate::traits::async_vfs::VfsAsync;
38#[cfg(feature = "async")]
39use crate::traits::async_vfs::WriteSupportingVfsAsync;
40#[cfg(feature = "resolve-path")]
41use crate::traits::resolve::DynamicHasField;
42use crate::traits::sync::DirStructureItem;
43use crate::traits::vfs;
44use crate::traits::vfs::DirEntryInfo;
45use crate::traits::vfs::DirWalker as _;
46#[cfg(feature = "resolve-path")]
47use crate::traits::vfs::OwnedPathType;
48use crate::traits::vfs::PathType;
49#[cfg(feature = "async")]
50use crate::traits::vfs::VfsCore;
51
52/// A directory structure where we don't know the names of the folders at compile-time,
53/// and as such we cannot use the derive macro.
54///
55/// Instead we know that all the entries in the directory are folders,
56/// and that they all have the same structure inside (defined by the `T` type parameter),
57/// or they are all files (which can be read with [`DirChildren`]<[`String`]> for example).
58///
59/// In either case, [`ReadFrom::read_from`] must be able to read all the entries in
60/// the directory.
61///
62/// The [`WriteTo`] implementation will directly write the children to the directory it
63/// is passed, with no regards to the path stored in `self_path`.
64#[derive(PartialEq, Eq)]
65#[cfg_attr(feature = "assert_eq", derive(assert_eq::AssertEq))]
66pub struct DirChildren<T, F: Filter<P> = NoFilter, P: PathType + ?Sized = Path> {
67 /// The children of the root directory.
68 pub children: Vec<DirChild<T, P>>,
69
70 #[cfg_attr(feature = "assert_eq", assert_eq(ignore))]
71 filter: marker::PhantomData<(F, P)>,
72}
73
74impl<T, P: PathType + ?Sized, F: Filter<P>> Clone for DirChildren<T, F, P>
75where
76 T: Clone,
77{
78 fn clone(&self) -> Self {
79 Self {
80 children: self.children.clone(),
81 filter: marker::PhantomData,
82 }
83 }
84}
85
86impl<T, P: PathType + ?Sized, F: Filter<P>> fmt::Debug for DirChildren<T, F, P>
87where
88 T: fmt::Debug,
89 P::PathSegmentOwned: fmt::Debug,
90{
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 f.debug_struct("DirChildren")
93 .field("children", &self.children)
94 .finish()
95 }
96}
97
98/// A filter for the children of a [`DirChildren`] structure.
99///
100/// This is used to filter out children that we don't want to
101/// read into the structure. For example, if we have a directory
102/// with a lot of files, we can use this to only read the
103/// files we want, for example, that have just a certain extension.
104///
105/// # Examples
106///
107/// For example, for a [`Filter`] that only allows `.txt` files:
108///
109#[cfg_attr(feature = "derive", doc = "```rust")]
110#[cfg_attr(not(feature = "derive"), doc = "```rust,compile_fail")]
111/// use std::path::Path;
112/// use std::path::PathBuf;
113///
114/// use dir_structure::{DirStructure, traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, Filter}};
115/// use dir_structure::prelude::*;
116///
117/// pub struct TextFileFilter;
118///
119/// impl Filter<Path> for TextFileFilter {
120/// fn allows(path: &Path) -> bool {
121/// path.extension()
122/// .and_then(|s| s.to_str())
123/// .map_or(false, |s| s == "txt")
124/// }
125/// }
126///
127/// fn main() -> Result<(), Box<dyn std::error::Error>> {
128/// let path = PathBuf::from("dir");
129/// #[derive(DirStructure)]
130/// struct Dir<Vfs: VfsCore<Path = Path>> {
131/// #[dir_structure(path = self)]
132/// text_files: DirChildren<String, TextFileFilter, Vfs::Path>,
133/// }
134///
135/// # std::fs::create_dir_all(&path)?;
136///
137/// std::fs::write(path.join("file1.txt"), "file1")?;
138/// std::fs::write(path.join("file2.txt"), "file2")?;
139/// std::fs::write(path.join("file3.bin"), "aaa")?;
140///
141/// let dir = Dir::read(&path)?;
142/// assert_eq!(dir.text_files.len(), 2);
143/// assert_eq!(dir.text_files.get_value_by_name("file1.txt"), Some(&String::from("file1")));
144/// assert_eq!(dir.text_files.get_value_by_name("file2.txt"), Some(&String::from("file2")));
145/// assert_eq!(dir.text_files.get_value_by_name("file3.bin"), None);
146///
147/// # std::fs::remove_dir_all(&path)?;
148///
149/// Ok(())
150/// }
151/// ```
152pub trait Filter<P: PathType + ?Sized> {
153 /// Checks if the path is allowed by this filter.
154 fn allows(path: &P) -> bool;
155}
156
157impl<P: PathType + ?Sized> Filter<P> for NoFilter {
158 fn allows(_path: &P) -> bool {
159 true
160 }
161}
162
163/// Creates a [`Filter`] type that only allows files / folders with a specific [extension](Path::extension).
164///
165/// # Examples
166///
167/// ```rust
168/// use std::path::Path;
169/// use dir_structure::dir_children::Filter;
170///
171/// dir_structure::ext_filter!(RustFile, "rs");
172///
173/// assert!(RustFile::allows(Path::new("main.rs")));
174/// assert!(RustFile::allows(Path::new("src/a/b/mod.rs")));
175/// assert!(!RustFile::allows(Path::new("main.txt")));
176/// ```
177#[macro_export]
178macro_rules! ext_filter {
179 ($vis:vis $name:ident, $Ext:literal) => {
180 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
181 $vis struct $name;
182
183 impl $crate::dir_children::Filter<::std::path::Path> for $name {
184 fn allows(path: &::std::path::Path) -> bool {
185 path.extension()
186 .map_or(false, |s| s == $Ext)
187 }
188 }
189 };
190}
191
192/// Creates a [`Filter`] type that only allows files / folders with a specific [stem](Path::file_stem).
193///
194/// # Examples
195///
196/// ```rust
197/// use std::path::Path;
198/// use dir_structure::dir_children::Filter;
199///
200/// dir_structure::stem_filter!(MainFile, "main");
201///
202/// assert!(MainFile::allows(Path::new("main.rs")));
203/// assert!(MainFile::allows(Path::new("src/a/b/main.rs")));
204/// assert!(MainFile::allows(Path::new("main.txt")));
205/// assert!(!MainFile::allows(Path::new("main.a.rs")));
206/// ```
207#[macro_export]
208macro_rules! stem_filter {
209 ($vis:vis $name:ident, $base_name:literal) => {
210 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
211 $vis struct $name;
212
213 impl $crate::dir_children::Filter<::std::path::Path> for $name {
214 fn allows(path: &::std::path::Path) -> bool {
215 path.file_stem()
216 .and_then(|s| s.to_str())
217 .map_or(false, |s| s == $base_name)
218 }
219 }
220 };
221}
222
223/// Creates a [`Filter`] type that only allows files / folders with a specific [prefix](Path::file_prefix).
224///
225/// # Examples
226///
227/// ```rust
228/// use std::path::Path;
229/// use dir_structure::dir_children::Filter;
230///
231/// dir_structure::file_prefix_filter!(LogFile, "log");
232///
233/// assert!(LogFile::allows(Path::new("log.txt")));
234/// assert!(LogFile::allows(Path::new("log")));
235/// assert!(LogFile::allows(Path::new("log.log")));
236/// assert!(LogFile::allows(Path::new("src/a/b/log.txt")));
237/// assert!(!LogFile::allows(Path::new("src/a/b/file.txt")));
238/// ```
239#[macro_export]
240macro_rules! file_prefix_filter {
241 ($vis:vis $name:ident, $file_prefix:literal) => {
242 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
243 $vis struct $name;
244
245 impl $crate::dir_children::Filter<::std::path::Path> for $name {
246 fn allows(path: &::std::path::Path) -> bool {
247 path.file_prefix()
248 .and_then(|s| s.to_str())
249 .map_or(false, |s| s == $file_prefix)
250 }
251 }
252 };
253}
254
255impl<T, P: PathType + ?Sized, F: Filter<P>> Default for DirChildren<T, F, P> {
256 fn default() -> Self {
257 Self::new()
258 }
259}
260
261impl<T, F: Filter<P>, P: PathType + ?Sized> DirChildren<T, F, P> {
262 /// Creates an empty [`DirChildren`], with no children.
263 ///
264 /// # Examples
265 ///
266 /// ```
267 /// use std::path::PathBuf;
268 /// use dir_structure::{dir_children::DirChildren, NoFilter};
269 ///
270 /// let d = DirChildren::<String, NoFilter>::new();
271 /// assert!(d.is_empty());
272 /// ```
273 pub fn new() -> Self {
274 Self {
275 children: Vec::new(),
276 filter: marker::PhantomData,
277 }
278 }
279
280 /// Creates a [`DirChildren`] with the given path and children.
281 ///
282 /// # Examples
283 ///
284 /// ```
285 /// use dir_structure::{dir_children::{DirChildren, DirChild}, NoFilter};
286 ///
287 /// let d = DirChildren::<String, NoFilter>::with_children_from_iter(
288 /// vec![
289 /// DirChild::new("file1.txt", "file1".to_owned()),
290 /// DirChild::new("file2.txt", "file2".to_owned()),
291 /// ],
292 /// );
293 /// assert!(!d.is_empty());
294 /// ```
295 pub fn with_children_from_iter(children: impl IntoIterator<Item = DirChild<T, P>>) -> Self {
296 Self {
297 children: children.into_iter().collect(),
298 filter: marker::PhantomData,
299 }
300 }
301
302 /// Maps the children of this [`DirChildren`] to a new type.
303 ///
304 /// This is useful for converting the children to a different type,
305 /// for example, if you want to convert the children to a different
306 /// type of [`DirStructureItem`].
307 ///
308 /// This is a convenience method that allows you to use the
309 /// `map` method on the children of this [`DirChildren`].
310 ///
311 /// # Examples
312 ///
313 /// ```rust
314 /// use std::path::Path;
315 /// use std::pin::Pin;
316 /// use dir_structure::{dir_children::{DirChildren, DirChild}, prelude::*};
317 ///
318 /// #[derive(Debug, PartialEq, Eq)]
319 /// struct NewType(String);
320 ///
321 /// let dir = DirChildren::<_, dir_structure::NoFilter>::with_children_from_iter(
322 /// vec![
323 /// DirChild::new("file1.txt", "file1".to_owned()),
324 /// DirChild::new("file2.txt", "file2".to_owned()),
325 /// DirChild::new("file3.txt", "file3".to_owned()),
326 /// ],
327 /// );
328 /// let dir = dir.map::<_, _, dir_structure::NoFilter, Path>(|child| child.map_value(NewType));
329 /// assert_eq!(
330 /// dir,
331 /// DirChildren::with_children_from_iter(
332 /// vec![
333 /// DirChild::new("file1.txt", NewType("file1".to_owned())),
334 /// DirChild::new("file2.txt", NewType("file2".to_owned())),
335 /// DirChild::new("file3.txt", NewType("file3".to_owned())),
336 /// ],
337 /// )
338 /// );
339 /// ```
340 pub fn map<U, MapF, F2, P2>(self, f: MapF) -> DirChildren<U, F2, P2>
341 where
342 MapF: FnMut(DirChild<T, P>) -> DirChild<U, P2>,
343 F2: Filter<P2>,
344 P2: PathType + ?Sized,
345 {
346 let children = self.children.into_iter().map(f).collect();
347 DirChildren {
348 children,
349 filter: marker::PhantomData,
350 }
351 }
352
353 /// Maps the filter type. The children remain unchanged.
354 ///
355 /// This is useful if you are trying to pass a DirChildren<T, F1> to
356 /// a function requiring a DirChildren<T, F2>, where F1 and F2 are two
357 /// distinct types implementing [`Filter`].
358 ///
359 /// # Examples
360 ///
361 /// ```rust
362 /// use std::path::Path;
363 /// use dir_structure::traits::vfs::PathType;
364 /// use dir_structure::dir_children::{Filter, DirChildren};
365 ///
366 /// struct NewFilter;
367 ///
368 /// impl<P: PathType + ?Sized> Filter<P> for NewFilter {
369 /// fn allows(_path: &P) -> bool {
370 /// true
371 /// }
372 /// }
373 ///
374 /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
375 /// let d2: DirChildren<String, NewFilter> = d.map_filter::<NewFilter>();
376 /// ```
377 pub fn map_filter<NewF>(self) -> DirChildren<T, NewF, P>
378 where
379 NewF: Filter<P>,
380 {
381 DirChildren {
382 children: self.children,
383 filter: marker::PhantomData,
384 }
385 }
386
387 /// Returns the number of children.
388 ///
389 /// # Examples
390 ///
391 /// ```rust
392 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
393 ///
394 /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
395 /// assert_eq!(d.len(), 0);
396 ///
397 /// let d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
398 /// vec![
399 /// DirChild::new("file1.txt", "file1".to_owned()),
400 /// DirChild::new("file2.txt", "file2".to_owned()),
401 /// ],
402 /// );
403 /// assert_eq!(d.len(), 2);
404 /// ```
405 pub fn len(&self) -> usize {
406 self.children.len()
407 }
408
409 /// Returns true if there are no children.
410 ///
411 /// # Examples
412 ///
413 /// ```
414 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
415 ///
416 /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
417 /// assert!(d.is_empty());
418 ///
419 /// let d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
420 /// vec![
421 /// DirChild::new("file1.txt", "file1".to_owned()),
422 /// DirChild::new("file2.txt", "file2".to_owned()),
423 /// ],
424 /// );
425 /// assert!(!d.is_empty());
426 /// ```
427 pub fn is_empty(&self) -> bool {
428 self.children.is_empty()
429 }
430
431 /// Gets the child at the specified index.
432 ///
433 /// # Examples
434 ///
435 /// ```rust
436 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
437 ///
438 /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
439 /// assert_eq!(d.get(0), None);
440 /// assert_eq!(d.get(1), None);
441 /// assert_eq!(d.get(100), None);
442 ///
443 /// let d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
444 /// vec![
445 /// DirChild::new("file1.txt", "file1".to_owned()),
446 /// DirChild::new("file2.txt", "file2".to_owned()),
447 /// ],
448 /// );
449 /// assert_eq!(d.get(0), Some(&DirChild::new("file1.txt", "file1".to_owned())));
450 /// assert_eq!(d.get(1), Some(&DirChild::new("file2.txt", "file2".to_owned())));
451 /// assert_eq!(d.get(2), None);
452 /// assert_eq!(d.get(100), None);
453 /// ```
454 pub fn get(&self, index: usize) -> Option<&DirChild<T, P>> {
455 self.children.get(index)
456 }
457
458 /// Gets a mutable reference to the child at the specified index.
459 /// This is a mutable version of [`get`][Self::get].
460 ///
461 /// # Examples
462 ///
463 /// ```rust
464 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
465 ///
466 /// let mut d = DirChildren::<String, dir_structure::NoFilter>::new();
467 /// assert_eq!(d.get_mut(0), None);
468 /// assert_eq!(d.get_mut(1), None);
469 /// assert_eq!(d.get_mut(100), None);
470 ///
471 /// let mut d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
472 /// vec![
473 /// DirChild::new("file1.txt", "file1".to_owned()),
474 /// DirChild::new("file2.txt", "file2".to_owned()),
475 /// ],
476 /// );
477 /// assert_eq!(d.get_mut(0), Some(&mut DirChild::new("file1.txt", "file1".to_owned())));
478 /// assert_eq!(d.get_mut(1), Some(&mut DirChild::new("file2.txt", "file2".to_owned())));
479 /// assert_eq!(d.get_mut(2), None);
480 /// assert_eq!(d.get_mut(100), None);
481 /// ```
482 pub fn get_mut(&mut self, index: usize) -> Option<&mut DirChild<T, P>> {
483 self.children.get_mut(index)
484 }
485
486 /// Gets the child with the specified "file" name (last segment of path).
487 ///
488 /// # Examples
489 ///
490 /// ```rust
491 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
492 ///
493 /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
494 /// assert_eq!(d.get_name(""), None);
495 /// assert_eq!(d.get_name("any_name"), None);
496 /// assert_eq!(d.get_name("aaaa"), None);
497 ///
498 /// let d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
499 /// vec![
500 /// DirChild::new("file1.txt", "file1".to_owned()),
501 /// DirChild::new("file2.txt", "file2".to_owned()),
502 /// ],
503 /// );
504 /// assert_eq!(d.get_name("file1.txt"), Some(&DirChild::new("file1.txt", "file1".to_owned())));
505 /// assert_eq!(d.get_name("file2.txt"), Some(&DirChild::new("file2.txt", "file2".to_owned())));
506 /// assert_eq!(d.get_name("any_name"), None);
507 /// assert_eq!(d.get_name("aaaa"), None);
508 /// ```
509 pub fn get_name(&self, name: impl AsRef<P::PathSegmentRef>) -> Option<&DirChild<T, P>>
510 where
511 P::PathSegmentRef: PartialEq,
512 {
513 self.children
514 .iter()
515 .find(|child| child.file_name.as_ref() == name.as_ref())
516 }
517
518 /// Gets the child with the specified "file" name (last segment of path).
519 /// This is a mutable version of [`get_name`][Self::get_name].
520 ///
521 /// # Examples
522 ///
523 /// ```rust
524 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
525 ///
526 /// let mut d = DirChildren::<String, dir_structure::NoFilter>::new();
527 /// assert_eq!(d.get_name_mut(""), None);
528 /// assert_eq!(d.get_name_mut("any_name"), None);
529 /// assert_eq!(d.get_name_mut("aaaa"), None);
530 ///
531 /// let mut d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
532 /// vec![
533 /// DirChild::new("file1.txt", "file1".to_owned()),
534 /// DirChild::new("file2.txt", "file2".to_owned()),
535 /// ],
536 /// );
537 /// assert_eq!(d.get_name_mut("file1.txt"), Some(&mut DirChild::new("file1.txt", "file1".to_owned())));
538 /// assert_eq!(d.get_name_mut("file2.txt"), Some(&mut DirChild::new("file2.txt", "file2".to_owned())));
539 /// assert_eq!(d.get_name_mut("any_name"), None);
540 /// assert_eq!(d.get_name_mut("aaaa"), None);
541 /// ```
542 pub fn get_name_mut(
543 &mut self,
544 name: impl AsRef<P::PathSegmentRef>,
545 ) -> Option<&mut DirChild<T, P>>
546 where
547 P::PathSegmentRef: PartialEq,
548 {
549 self.children
550 .iter_mut()
551 .find(|child| child.file_name.as_ref() == name.as_ref())
552 }
553
554 /// Gets the value of the child with the specified "file" name (last segment of path).
555 ///
556 /// # Examples
557 ///
558 /// ```rust
559 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
560 ///
561 /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
562 /// assert_eq!(d.get_value_by_name(""), None);
563 /// assert_eq!(d.get_value_by_name("any_name"), None);
564 /// assert_eq!(d.get_value_by_name("aaaa"), None);
565 ///
566 /// let d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
567 /// vec![
568 /// DirChild::new("file1.txt", "file1".to_owned()),
569 /// DirChild::new("file2.txt", "file2".to_owned()),
570 /// ],
571 /// );
572 /// assert_eq!(d.get_value_by_name("file1.txt"), Some(&"file1".to_owned()));
573 /// assert_eq!(d.get_value_by_name("file2.txt"), Some(&"file2".to_owned()));
574 /// assert_eq!(d.get_value_by_name("any_name"), None);
575 /// assert_eq!(d.get_value_by_name("aaaa"), None);
576 /// ```
577 pub fn get_value_by_name(&self, name: impl AsRef<P::PathSegmentRef>) -> Option<&T>
578 where
579 P::PathSegmentRef: PartialEq,
580 {
581 self.get_name(name).map(|child| &child.value)
582 }
583
584 /// Gets the value of the child with the specified "file" name (last segment of path).
585 /// This is a mutable version of [`get_value_by_name`][Self::get_value_by_name].
586 ///
587 /// # Examples
588 ///
589 /// ```rust
590 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
591 ///
592 /// let mut d = DirChildren::<String, dir_structure::NoFilter>::new();
593 /// assert_eq!(d.get_value_by_name_mut(""), None);
594 /// assert_eq!(d.get_value_by_name_mut("any_name"), None);
595 /// assert_eq!(d.get_value_by_name_mut("aaaa"), None);
596 ///
597 /// let mut d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
598 /// vec![
599 /// DirChild::new("file1.txt", "file1".to_owned()),
600 /// DirChild::new("file2.txt", "file2".to_owned()),
601 /// ],
602 /// );
603 /// assert_eq!(d.get_value_by_name_mut("file1.txt"), Some(&mut "file1".to_owned()));
604 /// assert_eq!(d.get_value_by_name_mut("file2.txt"), Some(&mut "file2".to_owned()));
605 /// assert_eq!(d.get_value_by_name_mut("any_name"), None);
606 /// assert_eq!(d.get_value_by_name_mut("aaaa"), None);
607 /// ```
608 pub fn get_value_by_name_mut(&mut self, name: impl AsRef<P::PathSegmentRef>) -> Option<&mut T>
609 where
610 P::PathSegmentRef: PartialEq,
611 {
612 self.get_name_mut(name).map(|child| &mut child.value)
613 }
614
615 /// Returns an iterator over the children.
616 ///
617 /// # Examples
618 ///
619 /// ```rust
620 /// use std::path::{Path, PathBuf};
621 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
622 ///
623 /// let d = DirChildren::<String, dir_structure::NoFilter>::new();
624 /// let mut i = d.iter();
625 /// assert_eq!(i.next(), None);
626 ///
627 /// let d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
628 /// vec![
629 /// DirChild::new("file1.txt", "file1".to_owned()),
630 /// DirChild::new("file2.txt", "file2".to_owned()),
631 /// ],
632 /// );
633 /// let mut i = d.iter();
634 /// assert_eq!(i.next(), Some(&DirChild::new("file1.txt", "file1".to_owned())));
635 /// assert_eq!(i.next(), Some(&DirChild::new("file2.txt", "file2".to_owned())));
636 /// assert_eq!(i.next(), None);
637 /// ```
638 pub fn iter(&self) -> DirChildrenIter<'_, T, P> {
639 DirChildrenIter(self.children.iter())
640 }
641
642 /// Returns a mutable iterator over the children.
643 ///
644 /// # Examples
645 ///
646 /// ```rust
647 /// use std::path::{Path, PathBuf};
648 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
649 ///
650 /// let mut d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
651 /// vec![
652 /// DirChild::new("file1.txt", "file1".to_owned()),
653 /// DirChild::new("file2.txt", "file2".to_owned()),
654 /// ],
655 /// );
656 /// let mut i = d.iter_mut();
657 /// assert_eq!(i.next(), Some(&mut DirChild::new("file1.txt", "file1".to_owned())));
658 /// assert_eq!(i.next(), Some(&mut DirChild::new("file2.txt", "file2".to_owned())));
659 /// assert_eq!(i.next(), None);
660 /// ```
661 ///
662 /// Modifying the children is also possible:
663 ///
664 /// ```rust
665 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
666 ///
667 /// let mut d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
668 /// vec![
669 /// DirChild::new("file1.txt", "file1".to_owned()),
670 /// DirChild::new("file2.txt", "file2".to_owned()),
671 /// ],
672 /// );
673 /// d.iter_mut().for_each(|child| *child.value_mut() = "modified".to_owned());
674 /// let mut i = d.iter();
675 /// assert_eq!(i.next(), Some(&DirChild::new("file1.txt", "modified".to_owned())));
676 /// assert_eq!(i.next(), Some(&DirChild::new("file2.txt", "modified".to_owned())));
677 /// assert_eq!(i.next(), None);
678 /// ```
679 pub fn iter_mut(&mut self) -> DirChildrenIterMut<'_, T, P> {
680 DirChildrenIterMut(self.children.iter_mut())
681 }
682
683 /// Pushes a new child to the end of the children list.
684 ///
685 /// This method takes a file name and a value, and creates a new `DirChild`
686 /// with the given file name and value, then pushes it to the end of the children
687 /// list.
688 ///
689 /// # Examples
690 ///
691 /// ```rust
692 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
693 /// let mut d = DirChildren::<String, dir_structure::NoFilter>::new();
694 ///
695 /// d.push("file1.txt", "file1".to_owned());
696 ///
697 /// let mut i = d.iter();
698 /// assert_eq!(i.next(), Some(&DirChild::new("file1.txt", "file1".to_owned())));
699 /// assert_eq!(i.next(), None);
700 ///
701 /// d.push("file2.txt", "file2".to_owned());
702 ///
703 /// let mut i = d.iter();
704 /// assert_eq!(i.next(), Some(&DirChild::new("file1.txt", "file1".to_owned())));
705 /// assert_eq!(i.next(), Some(&DirChild::new("file2.txt", "file2".to_owned())));
706 /// assert_eq!(i.next(), None);
707 /// ```
708 pub fn push(&mut self, file_name: impl Into<P::PathSegmentOwned>, value: T) {
709 self.children.push(DirChild {
710 file_name: file_name.into(),
711 value,
712 });
713 }
714
715 /// Retains only the children specified by the predicate.
716 ///
717 /// The predicate is a closure that takes a reference to a `DirChild<T>`
718 /// and returns `true` if the child should be kept, or `false` if it should be removed.
719 ///
720 /// # Examples
721 ///
722 /// ```rust
723 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
724 /// let mut d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
725 /// vec![
726 /// DirChild::new("file1.txt", "file1".to_owned()),
727 /// DirChild::new("file2.txt", "file2".to_owned()),
728 /// ],
729 /// );
730 /// d.retain(|child| child.file_name() != "file1.txt");
731 /// let mut i = d.iter();
732 /// assert_eq!(i.next(), Some(&DirChild::new("file2.txt", "file2".to_owned())));
733 /// assert_eq!(i.next(), None);
734 /// ```
735 pub fn retain(&mut self, f: impl FnMut(&DirChild<T, P>) -> bool) {
736 self.children.retain(f);
737 }
738
739 /// Drains the children in the specified range, returning an iterator over the removed children.
740 /// The range is specified using the standard Rust range syntax.
741 ///
742 /// # Examples
743 ///
744 /// ```rust
745 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
746 /// let mut d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
747 /// vec![
748 /// DirChild::new("file1.txt", "file1".to_owned()),
749 /// DirChild::new("file2.txt", "file2".to_owned()),
750 /// DirChild::new("file3.txt", "file3".to_owned()),
751 /// ],
752 /// );
753 /// let drained: Vec<_> = d.drain(0..1).collect();
754 /// assert_eq!(drained, vec![DirChild::new("file1.txt", "file1".to_owned())]);
755 /// let mut i = d.iter();
756 /// assert_eq!(i.next(), Some(&DirChild::new("file2.txt", "file2".to_owned())));
757 /// assert_eq!(i.next(), Some(&DirChild::new("file3.txt", "file3".to_owned())));
758 /// assert_eq!(i.next(), None);
759 /// ```
760 pub fn drain(&mut self, range: impl RangeBounds<usize>) -> DirChildrenDrain<'_, T, P> {
761 DirChildrenDrain(self.children.drain(range))
762 }
763
764 /// Extracts the children in the specified range that satisfy the given predicate,
765 /// returning an iterator over the removed children.
766 ///
767 /// The range is specified using the standard Rust range syntax.
768 /// The predicate is a closure that takes a mutable reference to a `DirChild<T>`
769 /// and returns `true` if the child should be removed, or `false` if it should be kept.
770 ///
771 /// # Examples
772 ///
773 /// ```rust
774 /// use dir_structure::{traits::sync::{DirStructure, DirStructureItem}, dir_children::{DirChildren, DirChild}};
775 /// let mut d = DirChildren::<String, dir_structure::NoFilter>::with_children_from_iter(
776 /// vec![
777 /// DirChild::new("file1.txt", "file1".to_owned()),
778 /// DirChild::new("file2.txt", "file2".to_owned()),
779 /// DirChild::new("file3.txt", "file3".to_owned()),
780 /// DirChild::new("file4.txt", "file4".to_owned()),
781 /// ],
782 /// );
783 /// let extracted: Vec<_> = d.extract_if(1..3, |child| child.file_name() == "file2.txt").collect();
784 /// assert_eq!(extracted, vec![DirChild::new("file2.txt", "file2".to_owned())]);
785 ///
786 /// let mut i = d.iter();
787 /// assert_eq!(i.next(), Some(&DirChild::new("file1.txt", "file1".to_owned())));
788 /// assert_eq!(i.next(), Some(&DirChild::new("file3.txt", "file3".to_owned())));
789 /// assert_eq!(i.next(), Some(&DirChild::new("file4.txt", "file4".to_owned())));
790 /// assert_eq!(i.next(), None);
791 /// ```
792 pub fn extract_if<'a, Fi>(
793 &'a mut self,
794 range: impl RangeBounds<usize>,
795 filter: Fi,
796 ) -> DirChildrenExtractIf<'a, T, P, Fi>
797 where
798 Fi: FnMut(&mut DirChild<T, P>) -> bool,
799 {
800 DirChildrenExtractIf(self.children.extract_if(range, filter))
801 }
802}
803
804impl<T, P: PathType + ?Sized, F> From<Vec<DirChild<T, P>>> for DirChildren<T, F, P>
805where
806 F: Filter<P>,
807{
808 fn from(children: Vec<DirChild<T, P>>) -> Self {
809 Self {
810 children,
811 filter: marker::PhantomData,
812 }
813 }
814}
815
816impl<T, P: PathType + ?Sized, F> Extend<DirChild<T, P>> for DirChildren<T, F, P>
817where
818 F: Filter<P>,
819{
820 fn extend<I: IntoIterator<Item = DirChild<T, P>>>(&mut self, iter: I) {
821 self.children.extend(iter);
822 }
823}
824
825impl<T, P: PathType + ?Sized, F> FromIterator<DirChild<T, P>> for DirChildren<T, F, P>
826where
827 F: Filter<P>,
828{
829 fn from_iter<I: IntoIterator<Item = DirChild<T, P>>>(iter: I) -> Self {
830 Self::with_children_from_iter(iter)
831 }
832}
833
834/// An iterator that drains the children of a [`DirChildren`].
835///
836/// See [`DirChildren::drain`].
837pub struct DirChildrenDrain<'a, T, P: PathType + ?Sized>(vec::Drain<'a, DirChild<T, P>>);
838
839impl<T, P: PathType + ?Sized> Iterator for DirChildrenDrain<'_, T, P> {
840 type Item = DirChild<T, P>;
841
842 fn next(&mut self) -> Option<Self::Item> {
843 self.0.next()
844 }
845
846 fn size_hint(&self) -> (usize, Option<usize>) {
847 self.0.size_hint()
848 }
849}
850
851impl<T, P: PathType + ?Sized> ExactSizeIterator for DirChildrenDrain<'_, T, P> {
852 fn len(&self) -> usize {
853 self.0.len()
854 }
855}
856
857impl<T, P: PathType + ?Sized> DoubleEndedIterator for DirChildrenDrain<'_, T, P> {
858 fn next_back(&mut self) -> Option<Self::Item> {
859 self.0.next_back()
860 }
861}
862
863impl<'a, T, P: PathType + ?Sized + 'a, F: Filter<P>, Vfs: vfs::Vfs<'a, Path = P>> ReadFrom<'a, Vfs>
864 for DirChildren<T, F, P>
865where
866 T: ReadFrom<'a, Vfs>,
867 F: 'a,
868{
869 fn read_from(path: &Vfs::Path, vfs: Pin<&'a Vfs>) -> VfsResult<Self, Vfs>
870 where
871 Self: Sized,
872 {
873 let mut children = Vec::new();
874 let mut walker = vfs.walk_dir(path)?;
875 while let Some(child) = walker.next() {
876 let DirEntryInfo {
877 name,
878 path: child_path,
879 ..
880 } = child?;
881
882 if !F::allows(child_path.as_ref()) {
883 continue;
884 }
885
886 let value = T::read_from(child_path.as_ref(), vfs)?;
887 children.push(DirChild {
888 file_name: name,
889 value,
890 });
891 }
892
893 Ok(DirChildren {
894 children,
895 filter: marker::PhantomData,
896 })
897 }
898}
899
900#[cfg(feature = "async")]
901#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
902#[pin_project(project_replace = DirChildrenReadAsyncFutureProjOwn)]
903#[doc(hidden)]
904pub enum DirChildrenReadAsyncFuture<'a, T, F, Vfs: VfsAsync + 'a>
905where
906 T: ReadFromAsync<'a, Vfs> + 'static,
907 F: Filter<Vfs::Path> + Send + 'static,
908 T::Future: Future<Output = VfsResult<T, Vfs>> + Send + Unpin + 'a,
909{
910 Poison,
911 Init(
912 Pin<Box<Vfs::DirWalkFuture<'a>>>,
913 Vec<DirChild<T, Vfs::Path>>,
914 <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
915 Pin<&'a Vfs>,
916 PhantomData<F>,
917 ),
918 Begin(
919 Pin<Box<Vfs::DirWalk<'a>>>,
920 Vec<DirChild<T, Vfs::Path>>,
921 <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
922 Pin<&'a Vfs>,
923 ),
924 ReadAsync(
925 Pin<Box<Vfs::DirWalk<'a>>>,
926 Vec<DirChild<T, Vfs::Path>>,
927 <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
928 T::Future,
929 <Vfs::Path as PathType>::PathSegmentOwned,
930 Pin<&'a Vfs>,
931 ),
932}
933
934#[cfg(feature = "async")]
935#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
936impl<'a, T, F, Vfs: VfsAsync + 'a> Future for DirChildrenReadAsyncFuture<'a, T, F, Vfs>
937where
938 T: ReadFromAsync<'a, Vfs> + Send + 'static,
939 F: Filter<Vfs::Path> + Send + 'static,
940 T::Future: Future<Output = VfsResult<T, Vfs>> + Unpin + 'static,
941{
942 type Output = VfsResult<DirChildren<T, F, Vfs::Path>, Vfs>;
943
944 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
945 let this = self.as_mut().project_replace(Self::Poison);
946
947 match this {
948 DirChildrenReadAsyncFutureProjOwn::Init(mut entries, children, path, vfs, _) => {
949 match entries.as_mut().poll(cx) {
950 Poll::Ready(Ok(entries)) => {
951 self.project_replace(DirChildrenReadAsyncFuture::Begin(
952 Box::pin(entries),
953 children,
954 path,
955 vfs,
956 ));
957 cx.waker().wake_by_ref();
958 Poll::Pending
959 }
960 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
961 Poll::Pending => {
962 self.project_replace(DirChildrenReadAsyncFuture::Init(
963 entries,
964 children,
965 path,
966 vfs,
967 PhantomData::<F>,
968 ));
969 Poll::Pending
970 }
971 }
972 }
973 DirChildrenReadAsyncFutureProjOwn::Begin(mut entries, children, path, vfs) => {
974 use std::task::Poll;
975
976 match entries.as_mut().poll_next(cx) {
977 Poll::Ready(Some(Ok(DirEntryInfo {
978 name,
979 path: path_child,
980 kind: _,
981 }))) => {
982 if !F::allows(path_child.as_ref()) {
983 self.project_replace(DirChildrenReadAsyncFuture::Begin(
984 entries, children, path, vfs,
985 ));
986 cx.waker().wake_by_ref();
987 return Poll::Pending;
988 }
989
990 let value_future = T::read_from_async(path_child, vfs);
991 self.project_replace(DirChildrenReadAsyncFuture::ReadAsync(
992 entries,
993 children,
994 path,
995 value_future,
996 name,
997 vfs,
998 ));
999 cx.waker().wake_by_ref();
1000 Poll::Pending
1001 }
1002 Poll::Ready(None) => Poll::Ready(Ok(DirChildren {
1003 children,
1004 filter: marker::PhantomData,
1005 })),
1006 Poll::Ready(Some(Err(e))) => Poll::Ready(Err(e)),
1007 Poll::Pending => {
1008 self.project_replace(DirChildrenReadAsyncFuture::Begin(
1009 entries, children, path, vfs,
1010 ));
1011 Poll::Pending
1012 }
1013 }
1014 }
1015 DirChildrenReadAsyncFutureProjOwn::ReadAsync(
1016 entries,
1017 mut children,
1018 path,
1019 mut value_fut,
1020 file_name,
1021 vfs,
1022 ) => match Pin::<&mut T::Future>::new(&mut value_fut).poll(cx) {
1023 Poll::Ready(Ok(value)) => {
1024 children.push(DirChild { file_name, value });
1025 self.project_replace(DirChildrenReadAsyncFuture::Begin(
1026 entries, children, path, vfs,
1027 ));
1028 cx.waker().wake_by_ref();
1029 Poll::Pending
1030 }
1031 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
1032 Poll::Pending => {
1033 self.project_replace(DirChildrenReadAsyncFuture::ReadAsync(
1034 entries,
1035 children,
1036 path,
1037 value_fut,
1038 file_name.clone(),
1039 vfs,
1040 ));
1041 Poll::Pending
1042 }
1043 },
1044 DirChildrenReadAsyncFutureProjOwn::Poison => {
1045 panic!("DirChildrenReadAsyncFuture is poisoned, this should never happen");
1046 }
1047 }
1048 }
1049}
1050
1051#[cfg(feature = "async")]
1052#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
1053impl<'a, T, F, Vfs: VfsAsync + 'a> ReadFromAsync<'a, Vfs> for DirChildren<T, F, Vfs::Path>
1054where
1055 T: ReadFromAsync<'a, Vfs> + Send + 'static,
1056 F: Filter<Vfs::Path> + Send + 'static,
1057 T::Future: Future<Output = VfsResult<T, Vfs>> + Unpin + 'static,
1058{
1059 type Future = DirChildrenReadAsyncFuture<'a, T, F, Vfs>;
1060
1061 fn read_from_async(
1062 path: <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
1063 vfs: Pin<&'a Vfs>,
1064 ) -> Self::Future {
1065 let f = Box::pin(vfs.walk_dir(path.clone()));
1066 DirChildrenReadAsyncFuture::Init(f, Vec::new(), path, vfs, PhantomData::<F>)
1067 }
1068}
1069
1070impl<'a, T, F, Vfs: vfs::WriteSupportingVfs<'a>> WriteTo<'a, Vfs> for DirChildren<T, F, Vfs::Path>
1071where
1072 T: WriteTo<'a, Vfs>,
1073 F: Filter<Vfs::Path>,
1074{
1075 fn write_to(&self, path: &Vfs::Path, vfs: Pin<&'a Vfs>) -> VfsResult<(), Vfs> {
1076 for child in &self.children {
1077 let child_path = path.join_segment(&child.file_name);
1078 child.value.write_to(child_path.as_ref(), vfs)?;
1079 }
1080
1081 Ok(())
1082 }
1083}
1084
1085#[cfg(feature = "async")]
1086#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
1087impl<'a, T, F, Vfs: WriteSupportingVfsAsync + 'static> WriteToAsync<'a, Vfs>
1088 for DirChildren<T, F, Vfs::Path>
1089where
1090 T: WriteToAsync<'a, Vfs> + Send + Sync + 'static,
1091 F: Filter<Vfs::Path> + Send + 'static,
1092 T::Future: Future<Output = VfsResult<(), Vfs>> + Unpin + 'a,
1093{
1094 type Future = DirChildrenWriteAsyncFuture<'a, T, Vfs>;
1095
1096 fn write_to_async(
1097 self,
1098 path: <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
1099 vfs: Pin<&'a Vfs>,
1100 ) -> Self::Future {
1101 DirChildrenWriteAsyncFuture::Init(self.into_iter(), path, vfs)
1102 }
1103}
1104
1105#[cfg(feature = "async")]
1106#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
1107#[pin_project(project_replace = DirChildrenWriteAsyncFutureProjOwn)]
1108#[doc(hidden)]
1109pub enum DirChildrenWriteAsyncFuture<'a, T, Vfs: WriteSupportingVfsAsync + 'static>
1110where
1111 T: WriteToAsync<'a, Vfs>,
1112 <T as WriteToAsync<'a, Vfs>>::Future: Future<Output = VfsResult<(), Vfs>> + Unpin,
1113{
1114 Poison,
1115 Init(
1116 DirChildrenIntoIter<T, <Vfs as VfsCore>::Path>,
1117 <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
1118 Pin<&'a Vfs>,
1119 ),
1120 Write(
1121 DirChildrenIntoIter<T, <Vfs as VfsCore>::Path>,
1122 <T as WriteToAsync<'a, Vfs>>::Future,
1123 <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
1124 Pin<&'a Vfs>,
1125 ),
1126}
1127
1128#[cfg(feature = "async")]
1129#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
1130impl<'a, T, Vfs: WriteSupportingVfsAsync + 'static> Future
1131 for DirChildrenWriteAsyncFuture<'a, T, Vfs>
1132where
1133 T: WriteToAsync<'a, Vfs>,
1134 <T as WriteToAsync<'a, Vfs>>::Future: Future<Output = VfsResult<(), Vfs>> + Unpin,
1135{
1136 type Output = VfsResult<(), Vfs>;
1137
1138 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1139 let this = self.as_mut().project_replace(Self::Poison);
1140
1141 match this {
1142 DirChildrenWriteAsyncFutureProjOwn::Init(mut iter, path, vfs) => {
1143 if let Some(child) = iter.next() {
1144 let fut = child
1145 .value
1146 .write_to_async(path.as_ref().join_segment(&child.file_name), vfs);
1147 self.project_replace(Self::Write(iter, fut, path.clone(), vfs));
1148 cx.waker().wake_by_ref();
1149 Poll::Pending
1150 } else {
1151 Poll::Ready(Ok(()))
1152 }
1153 }
1154 DirChildrenWriteAsyncFutureProjOwn::Write(mut iter, mut fut, path, vfs) => {
1155 match Pin::new(&mut fut).poll(cx) {
1156 Poll::Ready(Ok(())) => {
1157 if let Some(child) = iter.next() {
1158 let new_fut = child
1159 .value
1160 .write_to_async(path.as_ref().join_segment(&child.file_name), vfs);
1161 self.project_replace(Self::Write(iter, new_fut, path.clone(), vfs));
1162 cx.waker().wake_by_ref();
1163 Poll::Pending
1164 } else {
1165 Poll::Ready(Ok(()))
1166 }
1167 }
1168 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
1169 Poll::Pending => {
1170 self.project_replace(Self::Write(iter, fut, path.clone(), vfs));
1171 Poll::Pending
1172 }
1173 }
1174 }
1175 DirChildrenWriteAsyncFutureProjOwn::Poison => {
1176 panic!("DirChildrenWriteAsyncFuture is poisoned, this should never happen");
1177 }
1178 }
1179 }
1180}
1181
1182#[cfg(feature = "async")]
1183#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
1184impl<'r, T, F, Vfs: WriteSupportingVfsAsync + 'static> WriteToAsyncRef<'r, Vfs>
1185 for DirChildren<T, F, Vfs::Path>
1186where
1187 T: WriteToAsyncRef<'r, Vfs> + Send + Sync + 'static,
1188 F: Filter<Vfs::Path> + Send + 'static,
1189 for<'f> <T as WriteToAsyncRef<'r, Vfs>>::Future<'f>:
1190 Future<Output = VfsResult<(), Vfs>> + Unpin + 'f,
1191{
1192 type Future<'a>
1193 = DirChildrenWriteAsyncRefFuture<'r, 'a, T, Vfs>
1194 where
1195 T: 'a,
1196 Vfs: 'a,
1197 Self: 'a,
1198 'r: 'a;
1199
1200 fn write_to_async_ref<'a>(
1201 &'a self,
1202 path: <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
1203 vfs: Pin<&'a Vfs>,
1204 ) -> <Self as WriteToAsyncRef<'r, Vfs>>::Future<'a>
1205 where
1206 'r: 'a,
1207 {
1208 DirChildrenWriteAsyncRefFuture::Init(self.iter(), path, vfs)
1209 }
1210}
1211
1212#[cfg(feature = "async")]
1213#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
1214#[pin_project(project_replace = DirChildrenWriteAsyncRefFutureProjOwn)]
1215#[doc(hidden)]
1216pub enum DirChildrenWriteAsyncRefFuture<'r, 'f, T, Vfs: WriteSupportingVfsAsync + 'static>
1217where
1218 T: WriteToAsyncRef<'r, Vfs> + 'r,
1219 <T as WriteToAsyncRef<'r, Vfs>>::Future<'f>: Future<Output = VfsResult<(), Vfs>> + Unpin + 'f,
1220 'r: 'f,
1221{
1222 Poison,
1223 Init(
1224 DirChildrenIter<'f, T, Vfs::Path>,
1225 <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
1226 Pin<&'f Vfs>,
1227 ),
1228 Write(
1229 DirChildrenIter<'f, T, Vfs::Path>,
1230 <T as WriteToAsyncRef<'r, Vfs>>::Future<'f>,
1231 <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
1232 Pin<&'f Vfs>,
1233 ),
1234}
1235
1236#[cfg(feature = "async")]
1237#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
1238impl<'r, 'f, T, Vfs: WriteSupportingVfsAsync + 'static> Future
1239 for DirChildrenWriteAsyncRefFuture<'r, 'f, T, Vfs>
1240where
1241 T: WriteToAsyncRef<'r, Vfs>,
1242 <T as WriteToAsyncRef<'r, Vfs>>::Future<'f>: Future<Output = VfsResult<(), Vfs>> + Unpin + 'f,
1243 'r: 'f,
1244{
1245 type Output = VfsResult<(), Vfs>;
1246
1247 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1248 let this = self.as_mut().project_replace(Self::Poison);
1249
1250 match this {
1251 DirChildrenWriteAsyncRefFutureProjOwn::Init(mut iter, path, vfs) => {
1252 if let Some(child) = iter.next() {
1253 let fut = child
1254 .value
1255 .write_to_async_ref(path.as_ref().join_segment(&child.file_name), vfs);
1256 self.project_replace(Self::Write(iter, fut, path.clone(), vfs));
1257 cx.waker().wake_by_ref();
1258 Poll::Pending
1259 } else {
1260 Poll::Ready(Ok(()))
1261 }
1262 }
1263 DirChildrenWriteAsyncRefFutureProjOwn::Write(mut iter, mut fut, path, vfs) => {
1264 match Pin::new(&mut fut).poll(cx) {
1265 Poll::Ready(Ok(())) => {
1266 if let Some(child) = iter.next() {
1267 let new_fut = child.value.write_to_async_ref(
1268 path.as_ref().join_segment(&child.file_name),
1269 vfs,
1270 );
1271 self.project_replace(Self::Write(iter, new_fut, path.clone(), vfs));
1272 cx.waker().wake_by_ref();
1273 Poll::Pending
1274 } else {
1275 Poll::Ready(Ok(()))
1276 }
1277 }
1278 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
1279 Poll::Pending => {
1280 self.project_replace(Self::Write(iter, fut, path.clone(), vfs));
1281 Poll::Pending
1282 }
1283 }
1284 }
1285 DirChildrenWriteAsyncRefFutureProjOwn::Poison => {
1286 panic!("DirChildrenWriteAsyncRefFuture is poisoned, this should never happen");
1287 }
1288 }
1289 }
1290}
1291
1292#[cfg(feature = "resolve-path")]
1293#[cfg_attr(docsrs, doc(cfg(feature = "resolve-path")))]
1294impl<T, F, P: PathType + ?Sized> DynamicHasField for DirChildren<T, F, P>
1295where
1296 F: Filter<P>,
1297{
1298 type Inner = T;
1299
1300 fn resolve_path<Pt: OwnedPathType>(mut p: Pt, name: &str) -> Pt {
1301 p.push_segment_str(name);
1302 p
1303 }
1304}
1305
1306/// A single child of a [`DirChildren`] structure.
1307#[derive(PartialEq, Eq)]
1308#[cfg_attr(feature = "assert_eq", derive(assert_eq::AssertEq))]
1309pub struct DirChild<T, P: PathType + ?Sized = Path> {
1310 /// The file name of the child.
1311 file_name: P::PathSegmentOwned,
1312 /// The parsed value of the child.
1313 value: T,
1314}
1315
1316impl<T, P: PathType + ?Sized> Clone for DirChild<T, P>
1317where
1318 T: Clone,
1319 P::PathSegmentOwned: Clone,
1320{
1321 fn clone(&self) -> Self {
1322 Self {
1323 file_name: self.file_name.clone(),
1324 value: self.value.clone(),
1325 }
1326 }
1327}
1328
1329impl<T, P: PathType + ?Sized> fmt::Debug for DirChild<T, P>
1330where
1331 T: fmt::Debug,
1332 P::PathSegmentOwned: fmt::Debug,
1333{
1334 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1335 f.debug_struct("DirChild")
1336 .field("file_name", &self.file_name)
1337 .field("value", &self.value)
1338 .finish()
1339 }
1340}
1341
1342impl<T, P: PathType + ?Sized> DirChild<T, P> {
1343 /// Creates a new [`DirChild`] with the specified file name and value.
1344 ///
1345 /// # Examples
1346 ///
1347 /// ```rust
1348 /// use std::ffi::OsString;
1349 /// use std::path::Path;
1350 /// use dir_structure::dir_children::DirChild;
1351 ///
1352 /// let d = DirChild::<_, Path>::new("file.txt".to_owned(), "file".to_owned());
1353 /// assert_eq!(d.file_name(), &OsString::from("file.txt"));
1354 /// assert_eq!(d.value(), &"file".to_owned());
1355 /// ```
1356 pub fn new(file_name: impl Into<P::PathSegmentOwned>, value: T) -> Self {
1357 Self {
1358 file_name: file_name.into(),
1359 value,
1360 }
1361 }
1362
1363 /// Gets the file name of the child (or the name of the directory; the last segment in the path).
1364 ///
1365 /// # Examples
1366 ///
1367 /// ```rust
1368 /// use std::ffi::OsString;
1369 /// use std::path::Path;
1370 /// use dir_structure::dir_children::DirChild;
1371 ///
1372 /// let d = DirChild::<_, Path>::new("file.txt".to_owned(), "file".to_owned());
1373 /// assert_eq!(d.file_name(), &OsString::from("file.txt"));
1374 /// ```
1375 pub fn file_name(&self) -> &P::PathSegmentOwned {
1376 &self.file_name
1377 }
1378
1379 /// Gets the file name of the child (or the name of the directory; the last segment in the path).
1380 ///
1381 /// Mutable reference version of [`Self::file_name`].
1382 ///
1383 /// # Examples
1384 ///
1385 /// ```rust
1386 /// use std::ffi::OsString;
1387 /// use std::path::Path;
1388 /// use dir_structure::dir_children::DirChild;
1389 ///
1390 /// let mut d = DirChild::<_, Path>::new("file.txt".to_owned(), "file".to_owned());
1391 /// assert_eq!(d.file_name(), &OsString::from("file.txt"));
1392 /// *d.file_name_mut() = OsString::from("new_file.txt");
1393 /// assert_eq!(d.file_name(), &OsString::from("new_file.txt"));
1394 /// ```
1395 pub fn file_name_mut(&mut self) -> &mut P::PathSegmentOwned {
1396 &mut self.file_name
1397 }
1398
1399 /// Gets the value of the child.
1400 ///
1401 /// This is the parsed value of the file / directory.
1402 ///
1403 /// # Examples
1404 ///
1405 /// ```rust
1406 /// use std::ffi::OsString;
1407 /// use std::path::Path;
1408 /// use dir_structure::dir_children::DirChild;
1409 ///
1410 /// let d = DirChild::<_, Path>::new("file.txt".to_owned(), "file".to_owned());
1411 /// assert_eq!(d.value(), &"file".to_owned());
1412 /// ```
1413 pub fn value(&self) -> &T {
1414 &self.value
1415 }
1416
1417 /// Gets the value of the child.
1418 ///
1419 /// This is the parsed value of the file / directory.
1420 ///
1421 /// Mutable reference version of [`Self::value`].
1422 ///
1423 /// # Examples
1424 ///
1425 /// ```rust
1426 /// use std::ffi::OsString;
1427 /// use std::path::Path;
1428 /// use dir_structure::dir_children::DirChild;
1429 ///
1430 /// let mut d = DirChild::<_, Path>::new("file.txt".to_owned(), "file".to_owned());
1431 /// assert_eq!(d.value(), &"file".to_owned());
1432 /// *d.value_mut() = "new_file".to_owned();
1433 /// assert_eq!(d.value(), &"new_file".to_owned());
1434 /// ```
1435 pub fn value_mut(&mut self) -> &mut T {
1436 &mut self.value
1437 }
1438
1439 /// Maps the file name of this [`DirChild`] to a new value.
1440 ///
1441 /// # Examples
1442 ///
1443 /// ```rust
1444 /// use std::ffi::OsString;
1445 /// use std::path::Path;
1446 /// use dir_structure::dir_children::DirChild;
1447 ///
1448 /// let d = DirChild::<_, Path>::new("file.txt".to_owned(), "file".to_owned());
1449 /// assert_eq!(d.map_file_name(|s| s.to_str().unwrap().to_uppercase()), DirChild::new("FILE.TXT", "file".to_owned()));
1450 /// ```
1451 pub fn map_file_name<F, O>(self, f: F) -> Self
1452 where
1453 F: FnOnce(P::PathSegmentOwned) -> O,
1454 O: Into<P::PathSegmentOwned>,
1455 {
1456 let file_name = f(self.file_name).into();
1457 DirChild {
1458 file_name,
1459 value: self.value,
1460 }
1461 }
1462
1463 /// Maps the value of this [`DirChild`] to a new type.
1464 ///
1465 /// This is useful for converting the value to a different type,
1466 /// for example, if you want to convert the value to a different
1467 /// type of [`DirStructureItem`].
1468 ///
1469 /// # Examples
1470 ///
1471 /// ```rust
1472 /// use std::ffi::OsString;
1473 /// use std::path::Path;
1474 /// use dir_structure::dir_children::DirChild;
1475 /// use dir_structure::std_types::FileString;
1476 ///
1477 /// let d = DirChild::<_, Path>::new("file.txt".to_owned(), "file".to_owned());
1478 /// assert_eq!(d.map_value(|v| FileString(v)), DirChild::new("file.txt".to_owned(), FileString("file".to_owned())));
1479 /// ```
1480 pub fn map_value<U, F>(self, f: F) -> DirChild<U, P>
1481 where
1482 F: FnOnce(T) -> U,
1483 {
1484 let value = f(self.value);
1485 DirChild {
1486 file_name: self.file_name,
1487 value,
1488 }
1489 }
1490}
1491
1492impl<T, P: PathType + ?Sized> Deref for DirChild<T, P> {
1493 type Target = T;
1494
1495 fn deref(&self) -> &Self::Target {
1496 &self.value
1497 }
1498}
1499
1500impl<T, P: PathType + ?Sized> DerefMut for DirChild<T, P> {
1501 fn deref_mut(&mut self) -> &mut Self::Target {
1502 &mut self.value
1503 }
1504}
1505
1506/// A [`DirChildren`] iterator. It iterates over the children of a
1507/// [`DirChildren`] structure.
1508///
1509/// See [`DirChildren::iter`] for more information.
1510pub struct DirChildrenIter<'a, T, P: PathType + ?Sized>(slice::Iter<'a, DirChild<T, P>>);
1511
1512impl<'a, T, P: PathType + ?Sized> Iterator for DirChildrenIter<'a, T, P> {
1513 type Item = &'a DirChild<T, P>;
1514
1515 fn next(&mut self) -> Option<Self::Item> {
1516 self.0.next()
1517 }
1518
1519 fn size_hint(&self) -> (usize, Option<usize>) {
1520 self.0.size_hint()
1521 }
1522}
1523
1524impl<T, P: PathType + ?Sized> ExactSizeIterator for DirChildrenIter<'_, T, P>
1525where
1526 T: DirStructureItem,
1527{
1528 fn len(&self) -> usize {
1529 self.0.len()
1530 }
1531}
1532
1533impl<T, P: PathType + ?Sized> DoubleEndedIterator for DirChildrenIter<'_, T, P>
1534where
1535 T: DirStructureItem,
1536{
1537 fn next_back(&mut self) -> Option<Self::Item> {
1538 self.0.next_back()
1539 }
1540}
1541
1542/// A mutable iterator over the children of a [`DirChildren`] structure.
1543/// This allows you to mutate the children of the
1544/// [`DirChildren`] structure while iterating over them.
1545///
1546/// See [`DirChildren::iter_mut`] for more information.
1547pub struct DirChildrenIterMut<'a, T, P: PathType + ?Sized>(slice::IterMut<'a, DirChild<T, P>>);
1548
1549impl<'a, T, P: PathType + ?Sized> Iterator for DirChildrenIterMut<'a, T, P>
1550where
1551 T: DirStructureItem,
1552{
1553 type Item = &'a mut DirChild<T, P>;
1554
1555 fn next(&mut self) -> Option<Self::Item> {
1556 self.0.next()
1557 }
1558
1559 fn size_hint(&self) -> (usize, Option<usize>) {
1560 self.0.size_hint()
1561 }
1562}
1563
1564impl<T, P: PathType + ?Sized> ExactSizeIterator for DirChildrenIterMut<'_, T, P>
1565where
1566 T: DirStructureItem,
1567{
1568 fn len(&self) -> usize {
1569 self.0.len()
1570 }
1571}
1572
1573impl<T, P: PathType + ?Sized> DoubleEndedIterator for DirChildrenIterMut<'_, T, P>
1574where
1575 T: DirStructureItem,
1576{
1577 fn next_back(&mut self) -> Option<Self::Item> {
1578 self.0.next_back()
1579 }
1580}
1581
1582impl<T, F, P: ?Sized + PathType> IntoIterator for DirChildren<T, F, P>
1583where
1584 F: Filter<P>,
1585{
1586 type Item = DirChild<T, P>;
1587 type IntoIter = DirChildrenIntoIter<T, P>;
1588
1589 fn into_iter(self) -> Self::IntoIter {
1590 DirChildrenIntoIter(self.children.into_iter())
1591 }
1592}
1593
1594impl<'a, T, F, P: PathType + ?Sized> IntoIterator for &'a DirChildren<T, F, P>
1595where
1596 F: Filter<P>,
1597{
1598 type Item = &'a DirChild<T, P>;
1599 type IntoIter = DirChildrenIter<'a, T, P>;
1600
1601 fn into_iter(self) -> Self::IntoIter {
1602 self.iter()
1603 }
1604}
1605
1606impl<'a, T, F, P: PathType + ?Sized> IntoIterator for &'a mut DirChildren<T, F, P>
1607where
1608 F: Filter<P>,
1609{
1610 type Item = &'a mut DirChild<T, P>;
1611 type IntoIter = DirChildrenIterMut<'a, T, P>;
1612
1613 fn into_iter(self) -> Self::IntoIter {
1614 self.iter_mut()
1615 }
1616}
1617
1618/// An owned iterator over the children of a [`DirChildren`] structure.
1619///
1620/// See [`DirChildren::into_iter`] for more information.
1621pub struct DirChildrenIntoIter<T, P: PathType + ?Sized>(vec::IntoIter<DirChild<T, P>>);
1622
1623impl<T, P: PathType + ?Sized> Iterator for DirChildrenIntoIter<T, P> {
1624 type Item = DirChild<T, P>;
1625
1626 fn next(&mut self) -> Option<Self::Item> {
1627 self.0.next()
1628 }
1629
1630 fn size_hint(&self) -> (usize, Option<usize>) {
1631 self.0.size_hint()
1632 }
1633}
1634
1635impl<T, P: PathType + ?Sized> ExactSizeIterator for DirChildrenIntoIter<T, P> {
1636 fn len(&self) -> usize {
1637 self.0.len()
1638 }
1639}
1640
1641impl<T, P: PathType + ?Sized> DoubleEndedIterator for DirChildrenIntoIter<T, P> {
1642 fn next_back(&mut self) -> Option<Self::Item> {
1643 self.0.next_back()
1644 }
1645}
1646
1647/// An iterator that extracts children from a [`DirChildren`] structure
1648/// that satisfy a given predicate.
1649///
1650/// See [`DirChildren::extract_if`] for more information.
1651pub struct DirChildrenExtractIf<'a, T, P: PathType + ?Sized, F: FnMut(&mut DirChild<T, P>) -> bool>(
1652 vec::ExtractIf<'a, DirChild<T, P>, F>,
1653);
1654
1655impl<'a, T, P: PathType + ?Sized, F: FnMut(&mut DirChild<T, P>) -> bool> Iterator
1656 for DirChildrenExtractIf<'a, T, P, F>
1657{
1658 type Item = DirChild<T, P>;
1659
1660 fn next(&mut self) -> Option<Self::Item> {
1661 self.0.next()
1662 }
1663
1664 fn size_hint(&self) -> (usize, Option<usize>) {
1665 self.0.size_hint()
1666 }
1667}
1668
1669/// A wrapper around [`DirChildren`] that adds the <'vfs, Vfs> generics.
1670#[macro_export]
1671macro_rules! dir_children_wrapper_with_vfs {
1672 ($vis:vis $name:ident $ty:ident $(<Path=$p_ty:ty>)?) => {
1673 $vis struct $name<'vfs, Vfs: $crate::traits::vfs::VfsCore $(<Path = $p_ty>)? + 'vfs>(pub $crate::dir_children::DirChildren<$ty<'vfs, Vfs>, $crate::NoFilter, Vfs::Path>)
1674 where
1675 Vfs: $crate::traits::vfs::VfsCore + 'vfs;
1676
1677 impl<'vfs, Vfs: $crate::traits::vfs::Vfs<'vfs $(, Path = $p_ty)?> + 'vfs> $crate::traits::sync::ReadFrom<'vfs, Vfs> for $name<'vfs, Vfs> {
1678 fn read_from(path: &Vfs::Path, vfs: ::std::pin::Pin<&'vfs Vfs>) -> $crate::error::VfsResult<Self, Vfs>
1679 where
1680 Self: Sized,
1681 {
1682 Ok(Self(<$crate::dir_children::DirChildren<$ty<'vfs, Vfs>, $crate::NoFilter, Vfs::Path>>::read_from(path, vfs)?))
1683 }
1684 }
1685
1686 impl<'vfs, Vfs: $crate::traits::vfs::WriteSupportingVfs<'vfs $(, Path = $p_ty)?> + 'vfs> $crate::traits::sync::WriteTo<'vfs, Vfs> for $name<'vfs, Vfs> {
1687 fn write_to(&self, path: &Vfs::Path, vfs: ::std::pin::Pin<&'vfs Vfs>) -> $crate::error::VfsResult<(), Vfs> {
1688 self.0.write_to(path, vfs)
1689 }
1690 }
1691
1692 impl<'vfs, Vfs: $crate::traits::vfs::VfsCore $(<Path = $p_ty>)? + 'vfs> std::ops::Deref for $name<'vfs, Vfs> {
1693 type Target = $crate::dir_children::DirChildren<$ty<'vfs, Vfs>, $crate::NoFilter, Vfs::Path>;
1694
1695 fn deref(&self) -> &Self::Target {
1696 &self.0
1697 }
1698 }
1699
1700 impl<'vfs, Vfs: $crate::traits::vfs::VfsCore $(<Path = $p_ty>)? + 'vfs> std::ops::DerefMut for $name<'vfs, Vfs> {
1701 fn deref_mut(&mut self) -> &mut Self::Target {
1702 &mut self.0
1703 }
1704 }
1705
1706 impl<'vfs, Vfs: $crate::traits::vfs::VfsCore $(<Path = $p_ty>)?+ 'vfs> std::iter::IntoIterator for $name<'vfs, Vfs> {
1707 type Item = $crate::dir_children::DirChild<$ty<'vfs, Vfs>, Vfs::Path>;
1708 type IntoIter = $crate::dir_children::DirChildrenIntoIter<$ty<'vfs, Vfs>, Vfs::Path>;
1709
1710 fn into_iter(self) -> Self::IntoIter {
1711 self.0.into_iter()
1712 }
1713 }
1714
1715 impl<'vfs, Vfs: $crate::traits::vfs::VfsCore $(<Path = $p_ty>)? + 'vfs> $crate::traits::resolve::DynamicHasField for $name<'vfs, Vfs> where $crate::dir_children::DirChildren<$ty<'vfs, Vfs>, $crate::NoFilter, Vfs::Path>: $crate::traits::resolve::DynamicHasField {
1716 type Inner = <$crate::dir_children::DirChildren<$ty<'vfs, Vfs>, $crate::NoFilter, Vfs::Path> as $crate::traits::resolve::DynamicHasField>::Inner;
1717
1718 fn resolve_path<P: $crate::traits::vfs::OwnedPathType>(p: P, field: &str) -> P {
1719 <$crate::dir_children::DirChildren<$ty<'vfs, Vfs>, $crate::NoFilter, Vfs::Path> as $crate::traits::resolve::DynamicHasField>::resolve_path(p, field)
1720 }
1721 }
1722
1723 impl<'vfs, Vfs: $crate::traits::vfs::VfsCore $(<Path = $p_ty>)? + 'vfs> $crate::traits::resolve::DynamicHasFieldNoNewtype for $name<'vfs, Vfs> {}
1724 };
1725}
1726
1727/// A structure that represents a directory where only one of the children pass the filter `F`.
1728///
1729/// This is useful if you want to select one specific file, by the [file prefix](Path::file_prefix) /
1730/// [stem](Path::file_stem), but you don't care about the extension.
1731#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1732#[cfg_attr(feature = "assert_eq", derive(assert_eq::AssertEq))]
1733pub struct DirChildSingle<T, F: Filter<P>, P: PathType + ?Sized = Path> {
1734 /// The file name of the child.
1735 file_name: P::PathSegmentOwned,
1736 /// The parsed value of the child.
1737 value: T,
1738 #[cfg_attr(feature = "assert_eq", assert_eq(ignore))]
1739 _phantom: PhantomData<(F, P)>,
1740}
1741
1742impl<'a, T, F, Vfs: vfs::Vfs<'a>> ReadFrom<'a, Vfs> for DirChildSingle<T, F, Vfs::Path>
1743where
1744 T: ReadFrom<'a, Vfs>,
1745 F: Filter<Vfs::Path> + 'a,
1746{
1747 fn read_from(path: &Vfs::Path, vfs: Pin<&'a Vfs>) -> VfsResult<Self, Vfs>
1748 where
1749 Self: Sized,
1750 {
1751 let children = DirChildren::<T, F, Vfs::Path>::read_from(path, vfs)?;
1752 if children.len() != 1 {
1753 return Err(Error::UnexpectedNumberOfChildren {
1754 expected: "1",
1755 found: children.len(),
1756 path: path.owned(),
1757 });
1758 }
1759
1760 let child = children.children.into_iter().next().unwrap();
1761 Ok(DirChildSingle {
1762 file_name: child.file_name,
1763 value: child.value,
1764 _phantom: PhantomData,
1765 })
1766 }
1767}
1768
1769impl<'a, T, F: Filter<Vfs::Path>, Vfs: vfs::WriteSupportingVfs<'a>> WriteTo<'a, Vfs>
1770 for DirChildSingle<T, F, Vfs::Path>
1771where
1772 T: WriteTo<'a, Vfs>,
1773{
1774 fn write_to(&self, path: &Vfs::Path, vfs: Pin<&'a Vfs>) -> VfsResult<(), Vfs> {
1775 let child_path = path.join_segment(&self.file_name);
1776 self.value.write_to(child_path.as_ref(), vfs)
1777 }
1778}
1779
1780impl<T, F: Filter<P>, P: PathType + ?Sized> DirChildSingle<T, F, P> {
1781 /// Creates a new [`DirChildSingle`] with the specified file name and value.
1782 ///
1783 /// # Examples
1784 ///
1785 /// ```rust
1786 /// use std::ffi::OsString;
1787 /// use dir_structure::NoFilter;
1788 /// use dir_structure::dir_children::DirChildSingle;
1789 ///
1790 /// let d = DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned());
1791 /// assert_eq!(d.file_name(), &OsString::from("file.txt"));
1792 /// assert_eq!(d.value(), &"file".to_owned());
1793 /// ```
1794 pub fn new(file_name: impl Into<P::PathSegmentOwned>, value: T) -> Self {
1795 Self {
1796 file_name: file_name.into(),
1797 value,
1798 _phantom: PhantomData,
1799 }
1800 }
1801
1802 /// Gets the file name of the child (or the name of the directory; the last segment in the path).
1803 ///
1804 /// # Examples
1805 ///
1806 /// ```
1807 /// use std::ffi::OsString;
1808 /// use dir_structure::NoFilter;
1809 /// use dir_structure::dir_children::DirChildSingle;
1810 ///
1811 /// let d = DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned());
1812 /// assert_eq!(d.file_name(), &OsString::from("file.txt"));
1813 /// assert_eq!(d.value(), &"file".to_owned());
1814 /// ```
1815 pub fn file_name(&self) -> &P::PathSegmentOwned {
1816 &self.file_name
1817 }
1818
1819 /// Gets the file name of the child (or the name of the directory; the last segment in the path). Mutable version of [`file_name`][Self::file_name].
1820 ///
1821 /// # Examples
1822 ///
1823 /// ```
1824 /// use std::ffi::OsString;
1825 /// use dir_structure::NoFilter;
1826 /// use dir_structure::dir_children::DirChildSingle;
1827 ///
1828 /// let mut d = DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned());
1829 /// assert_eq!(d.file_name_mut(), &mut OsString::from("file.txt"));
1830 /// assert_eq!(d.value_mut(), &mut "file".to_owned());
1831 /// ```
1832 pub fn file_name_mut(&mut self) -> &mut P::PathSegmentOwned {
1833 &mut self.file_name
1834 }
1835
1836 /// Gets the value of the child.
1837 ///
1838 /// # Examples
1839 ///
1840 /// ```
1841 /// use std::ffi::OsString;
1842 /// use dir_structure::NoFilter;
1843 /// use dir_structure::dir_children::DirChildSingle;
1844 ///
1845 /// let d = DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned());
1846 /// assert_eq!(d.value(), &"file".to_owned());
1847 /// ```
1848 pub fn value(&self) -> &T {
1849 &self.value
1850 }
1851
1852 /// Gets the value of the child. Mutable reference version of [`Self::value`].
1853 ///
1854 /// # Examples
1855 ///
1856 /// ```
1857 /// use std::ffi::OsString;
1858 /// use dir_structure::NoFilter;
1859 /// use dir_structure::dir_children::DirChildSingle;
1860 ///
1861 /// let mut d = DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned());
1862 /// assert_eq!(d.value_mut(), &mut "file".to_owned());
1863 /// ```
1864 pub fn value_mut(&mut self) -> &mut T {
1865 &mut self.value
1866 }
1867
1868 /// Converts &[`DirChildSingle`]<T, F> to [`DirChildSingle`]<&T, F>.
1869 ///
1870 /// # Examples
1871 ///
1872 /// ```
1873 /// use std::ffi::OsString;
1874 /// use dir_structure::NoFilter;
1875 /// use dir_structure::dir_children::DirChildSingle;
1876 ///
1877 /// let d = DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned());
1878 /// let d_ref: DirChildSingle<&String, NoFilter> = d.as_ref();
1879 /// assert_eq!(d_ref.file_name(), &OsString::from("file.txt"));
1880 /// assert_eq!(d_ref.value(), &&"file".to_owned());
1881 /// ```
1882 pub fn as_ref(&self) -> DirChildSingle<&T, F, P> {
1883 DirChildSingle {
1884 file_name: self.file_name.clone(),
1885 value: &self.value,
1886 _phantom: PhantomData,
1887 }
1888 }
1889
1890 /// Converts &mut [`DirChildSingle`]<T, F> to [`DirChildSingle`]<&mut T, F>.
1891 ///
1892 /// This clones the [`OsString`](std::ffi::OsString) and [`PathBuf`](std::path::PathBuf) used for the name and path.
1893 ///
1894 /// # Examples
1895 ///
1896 /// ```
1897 /// use std::ffi::OsString;
1898 /// use dir_structure::NoFilter;
1899 /// use dir_structure::dir_children::DirChildSingle;
1900 ///
1901 /// let mut d = DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned());
1902 /// let mut d_mut: DirChildSingle<&mut String, NoFilter> = d.as_mut();
1903 /// d_mut.value_mut().push_str("_modified");
1904 /// assert_eq!(d.value(), &"file_modified".to_owned());
1905 /// ```
1906 pub fn as_mut(&mut self) -> DirChildSingle<&mut T, F, P> {
1907 DirChildSingle {
1908 file_name: self.file_name.clone(),
1909 value: &mut self.value,
1910 _phantom: PhantomData,
1911 }
1912 }
1913
1914 /// Maps the value of the child to a new value.
1915 ///
1916 /// # Examples
1917 ///
1918 /// ```
1919 /// use std::ffi::OsString;
1920 /// use dir_structure::NoFilter;
1921 /// use dir_structure::dir_children::DirChildSingle;
1922 ///
1923 /// let d = DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned());
1924 /// let d2 = d.map(|s| s.to_uppercase());
1925 /// assert_eq!(d2.value(), &"FILE".to_owned());
1926 /// ```
1927 pub fn map<T2, F2>(self, f: F2) -> DirChildSingle<T2, F, P>
1928 where
1929 F2: FnOnce(T) -> T2,
1930 {
1931 DirChildSingle {
1932 file_name: self.file_name,
1933 value: f(self.value),
1934 _phantom: PhantomData,
1935 }
1936 }
1937
1938 /// Map the filter to another [`Filter`] type.
1939 ///
1940 /// # Examples
1941 ///
1942 /// ```
1943 /// use std::ffi::OsString;
1944 /// use dir_structure::NoFilter;
1945 /// use dir_structure::dir_children::DirChildSingle;
1946 /// use dir_structure::traits::vfs::PathType;
1947 ///
1948 /// struct Filt;
1949 ///
1950 /// impl<P: PathType + ?Sized> dir_structure::dir_children::Filter<P> for Filt {
1951 /// fn allows(_path: &P) -> bool {
1952 /// true
1953 /// }
1954 /// }
1955 ///
1956 /// let d = DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned());
1957 /// let d2: DirChildSingle<_, Filt> = d.map_filter::<Filt>();
1958 /// assert_eq!(d2.file_name(), &OsString::from("file.txt"));
1959 /// assert_eq!(d2.value(), &"file".to_owned());
1960 /// ```
1961 pub fn map_filter<F2>(self) -> DirChildSingle<T, F2, P>
1962 where
1963 F2: Filter<P>,
1964 {
1965 DirChildSingle {
1966 file_name: self.file_name,
1967 value: self.value,
1968 _phantom: PhantomData,
1969 }
1970 }
1971}
1972
1973impl<T, F, P: PathType + ?Sized> fmt::Debug for DirChildSingle<T, F, P>
1974where
1975 F: Filter<P>,
1976 T: fmt::Debug,
1977 <P as PathType>::PathSegmentOwned: fmt::Debug,
1978{
1979 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1980 f.debug_struct("DirChildSingle")
1981 .field("file_name", &self.file_name)
1982 .field("value", &self.value)
1983 .finish()
1984 }
1985}
1986
1987impl<T, F, P: PathType + ?Sized> Deref for DirChildSingle<T, F, P>
1988where
1989 F: Filter<P>,
1990{
1991 type Target = T;
1992
1993 fn deref(&self) -> &Self::Target {
1994 &self.value
1995 }
1996}
1997
1998impl<T, F, P: PathType + ?Sized> DerefMut for DirChildSingle<T, F, P>
1999where
2000 F: Filter<P>,
2001{
2002 fn deref_mut(&mut self) -> &mut Self::Target {
2003 &mut self.value
2004 }
2005}
2006
2007/// A similar idea to [`DirChildSingle`], but allows for the absence of a matching entry.
2008#[derive(Clone, PartialEq, Eq)]
2009// #[cfg_attr(feature = "assert_eq", derive(assert_eq::AssertEq))]
2010pub enum DirChildSingleOpt<T, F: Filter<P>, P: PathType + ?Sized = Path> {
2011 /// The entry is absent.
2012 None,
2013 /// The entry is present.
2014 Some(DirChildSingle<T, F, P>),
2015}
2016
2017impl<T, F: Filter<P>, P: PathType + ?Sized> hash::Hash for DirChildSingleOpt<T, F, P>
2018where
2019 T: hash::Hash,
2020 <P as PathType>::PathSegmentOwned: hash::Hash,
2021{
2022 fn hash<H: hash::Hasher>(&self, state: &mut H) {
2023 match self {
2024 DirChildSingleOpt::None => {
2025 0u8.hash(state);
2026 }
2027 DirChildSingleOpt::Some(child) => {
2028 1u8.hash(state);
2029 child.hash(state);
2030 }
2031 }
2032 }
2033}
2034
2035#[cfg(feature = "assert_eq")]
2036impl<T, F: Filter<P>, P: PathType + ?Sized> assert_eq::AssertEq for DirChildSingleOpt<T, F, P>
2037where
2038 T: assert_eq::AssertEq + fmt::Debug,
2039 <P as PathType>::PathSegmentOwned: assert_eq::AssertEq + fmt::Debug,
2040{
2041 fn assert_eq(
2042 &self,
2043 other: &Self,
2044 path: &mut ::assert_eq::AssertPath,
2045 init_left: &impl fmt::Display,
2046 init_right: &impl fmt::Display,
2047 ) {
2048 match (self, other) {
2049 (DirChildSingleOpt::None, DirChildSingleOpt::None) => {}
2050 (DirChildSingleOpt::Some(a), DirChildSingleOpt::Some(b)) => {
2051 let __g = &mut *path.__guard("[Some]");
2052 a.assert_eq(b, &mut *__g.__guard(".0"), init_left, init_right);
2053 }
2054 (a, b) => panic!("DirChildSingleOpt not equal: {:?} != {:?}", a, b),
2055 }
2056 }
2057}
2058
2059impl<T, F: Filter<P>, P: PathType + ?Sized> DirChildSingleOpt<T, F, P> {
2060 /// Creates a new [`DirChildSingleOpt`] with the specified file name and value.
2061 ///
2062 /// # Examples
2063 ///
2064 /// ```rust
2065 /// use std::ffi::OsString;
2066 /// use dir_structure::dir_children::DirChildSingleOpt;
2067 /// use dir_structure::NoFilter;
2068 ///
2069 /// let DirChildSingleOpt::Some(d) = DirChildSingleOpt::<_, NoFilter>::new("file.txt", "file".to_owned()) else {
2070 /// panic!("Expected Some variant");
2071 /// };
2072 /// assert_eq!(d.file_name(), &OsString::from("file.txt"));
2073 /// assert_eq!(d.value(), &"file".to_owned());
2074 /// ```
2075 pub fn new(file_name: impl Into<P::PathSegmentOwned>, value: T) -> Self {
2076 DirChildSingleOpt::Some(DirChildSingle::new(file_name, value))
2077 }
2078
2079 /// Returns `true` if this is a [`DirChildSingleOpt::Some`].
2080 ///
2081 /// # Examples
2082 ///
2083 /// ```
2084 /// use dir_structure::dir_children::DirChildSingleOpt;
2085 /// use dir_structure::dir_children::DirChildSingle;
2086 /// use dir_structure::NoFilter;
2087 ///
2088 /// let opt = DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned()));
2089 /// assert!(opt.is_some());
2090 ///
2091 /// let opt = DirChildSingleOpt::<String, NoFilter>::None;
2092 /// assert!(!opt.is_some());
2093 /// ```
2094 pub fn is_some(&self) -> bool {
2095 matches!(self, DirChildSingleOpt::Some(_))
2096 }
2097
2098 /// Returns `true` if this is a [`DirChildSingleOpt::None`].
2099 ///
2100 /// # Examples
2101 ///
2102 /// ```
2103 /// use dir_structure::dir_children::DirChildSingleOpt;
2104 /// use dir_structure::dir_children::DirChildSingle;
2105 /// use dir_structure::NoFilter;
2106 ///
2107 /// let opt = DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned()));
2108 /// assert!(!opt.is_none());
2109 ///
2110 /// let opt = DirChildSingleOpt::<String, NoFilter>::None;
2111 /// assert!(opt.is_none());
2112 /// ```
2113 pub fn is_none(&self) -> bool {
2114 matches!(self, DirChildSingleOpt::None)
2115 }
2116
2117 /// Converts a &[`DirChildSingleOpt`]<T, F> into a [`DirChildSingleOpt`]<&T, F>.
2118 ///
2119 /// # Examples
2120 ///
2121 /// ```
2122 /// use dir_structure::dir_children::DirChildSingleOpt;
2123 /// use dir_structure::dir_children::DirChildSingle;
2124 /// use dir_structure::NoFilter;
2125 ///
2126 /// let opt = DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned()));
2127 /// let opt_ref = opt.as_ref();
2128 /// assert_eq!(opt_ref, DirChildSingleOpt::Some(DirChildSingle::new("file.txt", &"file".to_owned())));
2129 ///
2130 /// let opt = DirChildSingleOpt::<String, NoFilter>::None;
2131 /// let opt_ref = opt.as_ref();
2132 /// assert_eq!(opt_ref, DirChildSingleOpt::None);
2133 /// ```
2134 pub fn as_ref(&self) -> DirChildSingleOpt<&T, F, P> {
2135 match self {
2136 Self::Some(child) => DirChildSingleOpt::Some(child.as_ref()),
2137 Self::None => DirChildSingleOpt::None,
2138 }
2139 }
2140
2141 /// Converts a &mut [`DirChildSingleOpt`]<T, F> into a [`DirChildSingleOpt`]<&mut T, F>.
2142 ///
2143 /// This clones the internal [`OsString`](std::ffi::OsString) and [`PathBuf`](std::path::PathBuf) used for the name and path.
2144 ///
2145 /// # Examples
2146 ///
2147 /// ```
2148 /// use dir_structure::dir_children::DirChildSingleOpt;
2149 /// use dir_structure::dir_children::DirChildSingle;
2150 ///
2151 /// use dir_structure::NoFilter;
2152 ///
2153 /// let mut opt = DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned()));
2154 /// let mut opt_mut = opt.as_mut();
2155 /// if let DirChildSingleOpt::Some(child) = &mut opt_mut {
2156 /// child.value_mut().push_str("_modified");
2157 /// }
2158 /// assert_eq!(opt, DirChildSingleOpt::Some(DirChildSingle::new("file.txt", "file_modified".to_owned())));
2159 ///
2160 /// let mut opt = DirChildSingleOpt::<String, NoFilter>::None;
2161 /// let mut opt_mut = opt.as_mut();
2162 /// assert_eq!(opt_mut, DirChildSingleOpt::None);
2163 /// ```
2164 pub fn as_mut(&mut self) -> DirChildSingleOpt<&mut T, F, P> {
2165 match self {
2166 Self::Some(child) => DirChildSingleOpt::Some(child.as_mut()),
2167 Self::None => DirChildSingleOpt::None,
2168 }
2169 }
2170
2171 /// Maps the value inside the [`DirChildSingleOpt`] if it exists.
2172 ///
2173 /// # Examples
2174 ///
2175 /// ```
2176 /// use dir_structure::dir_children::DirChildSingleOpt;
2177 /// use dir_structure::dir_children::DirChildSingle;
2178 /// use dir_structure::NoFilter;
2179 ///
2180 /// let opt = DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned()));
2181 /// let opt_mapped = opt.map(|child| child.map(|v| v.to_uppercase()));
2182 /// assert_eq!(opt_mapped, DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "FILE".to_owned())));
2183 ///
2184 /// let opt = DirChildSingleOpt::<String, NoFilter>::None;
2185 /// let opt_mapped = opt.map(|child| child.map(|v| v.to_uppercase()));
2186 /// assert_eq!(opt_mapped, DirChildSingleOpt::None);
2187 /// ```
2188 pub fn map<U>(
2189 self,
2190 f: impl FnOnce(DirChildSingle<T, F, P>) -> DirChildSingle<U, F, P>,
2191 ) -> DirChildSingleOpt<U, F, P> {
2192 match self {
2193 Self::Some(child) => DirChildSingleOpt::Some(f(child)),
2194 Self::None => DirChildSingleOpt::None,
2195 }
2196 }
2197
2198 /// Returns a new [`DirChildSingleOpt`] by applying the function `f` to the value inside
2199 /// the [`DirChildSingleOpt`] if it exists.
2200 ///
2201 /// # Examples
2202 ///
2203 /// ```
2204 /// use dir_structure::dir_children::DirChildSingleOpt;
2205 /// use dir_structure::dir_children::DirChildSingle;
2206 /// use dir_structure::NoFilter;
2207 ///
2208 /// let opt = DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned()));
2209 /// let opt_and_then = opt.and_then(|child| {
2210 /// DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new(child.file_name(), child.value().to_uppercase()))
2211 /// });
2212 /// assert_eq!(opt_and_then, DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "FILE".to_owned())));
2213 ///
2214 /// let opt = DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned()));
2215 /// let opt_and_then = opt.and_then(|child| DirChildSingleOpt::<String, NoFilter>::None);
2216 /// assert_eq!(opt_and_then, DirChildSingleOpt::None);
2217 ///
2218 /// let opt = DirChildSingleOpt::<String, NoFilter>::None;
2219 /// let opt_and_then = opt.and_then(|child| {
2220 /// DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new(child.file_name(), child.value().to_uppercase()))
2221 /// });
2222 /// assert_eq!(opt_and_then, DirChildSingleOpt::<_, NoFilter>::None);
2223 /// ```
2224 pub fn and_then<U, F2: Filter<P2>, P2: PathType + ?Sized>(
2225 self,
2226 f: impl FnOnce(DirChildSingle<T, F, P>) -> DirChildSingleOpt<U, F2, P2>,
2227 ) -> DirChildSingleOpt<U, F2, P2> {
2228 match self {
2229 Self::Some(child) => f(child),
2230 Self::None => DirChildSingleOpt::None,
2231 }
2232 }
2233
2234 /// Returns a new [`DirChildSingleOpt`] by applying the function `f` to the value inside
2235 /// the [`DirChildSingleOpt`] if it exists.
2236 ///
2237 /// # Examples
2238 ///
2239 /// ```
2240 /// use dir_structure::dir_children::DirChildSingleOpt;
2241 /// use dir_structure::dir_children::DirChildSingle;
2242 /// use dir_structure::NoFilter;
2243 ///
2244 /// let opt = DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned()));
2245 /// let opt_or_else = opt.or_else(|| {
2246 /// DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "FILE".to_owned()))
2247 /// });
2248 /// assert_eq!(opt_or_else, DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "file".to_owned())));
2249 ///
2250 /// let opt = DirChildSingleOpt::<String, NoFilter>::None;
2251 /// let opt_or_else = opt.or_else(|| {
2252 /// DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "FILE".to_owned()))
2253 /// });
2254 /// assert_eq!(opt_or_else, DirChildSingleOpt::Some(DirChildSingle::<_, NoFilter>::new("file.txt", "FILE".to_owned())));
2255 ///
2256 /// let opt = DirChildSingleOpt::<String, NoFilter>::None;
2257 /// let opt_or_else = opt.or_else(|| DirChildSingleOpt::<String, NoFilter>::None);
2258 /// assert_eq!(opt_or_else, DirChildSingleOpt::None);
2259 /// ```
2260 pub fn or_else<F2: Filter<P>>(
2261 self,
2262 f: impl FnOnce() -> DirChildSingleOpt<T, F2, P>,
2263 ) -> DirChildSingleOpt<T, F2, P> {
2264 match self {
2265 Self::Some(child) => DirChildSingleOpt::Some(child.map_filter()),
2266 Self::None => f(),
2267 }
2268 }
2269
2270 /// Converts the [`DirChildSingleOpt`] into an `Option`.
2271 ///
2272 /// # Examples
2273 ///
2274 /// ```
2275 /// use dir_structure::dir_children::DirChildSingleOpt;
2276 /// use dir_structure::dir_children::DirChildSingle;
2277 /// use dir_structure::NoFilter;
2278 ///
2279 /// let opt = DirChildSingleOpt::Some(DirChildSingle::new("file.txt", "file".to_owned()));
2280 /// let option = opt.to_option();
2281 /// assert_eq!(option, Some(DirChildSingle::<String, NoFilter>::new("file.txt", "file".to_owned())));
2282 ///
2283 /// let opt = DirChildSingleOpt::<String, NoFilter>::None;
2284 /// let option = opt.to_option();
2285 /// assert_eq!(option, None);
2286 /// ```
2287 pub fn to_option(self) -> Option<DirChildSingle<T, F, P>> {
2288 match self {
2289 DirChildSingleOpt::Some(child) => Some(child),
2290 DirChildSingleOpt::None => None,
2291 }
2292 }
2293
2294 /// Takes the value out of the [`DirChildSingleOpt`] if the predicate `pred` returns `true`.
2295 ///
2296 /// If the predicate returns `false`, or if the [`DirChildSingleOpt`] is `None`, this returns `None`.
2297 ///
2298 /// # Examples
2299 ///
2300 /// ```
2301 /// use dir_structure::dir_children::DirChildSingleOpt;
2302 /// use dir_structure::dir_children::DirChildSingle;
2303 /// use dir_structure::NoFilter;
2304 ///
2305 /// let mut opt = DirChildSingleOpt::<String, NoFilter>::Some(DirChildSingle::new("file.txt", "file".to_owned()));
2306 /// let taken = opt.take_if(|child| child.value() == "file");
2307 /// assert_eq!(taken, DirChildSingleOpt::Some(DirChildSingle::new("file.txt", "file".to_owned())));
2308 /// assert_eq!(opt, DirChildSingleOpt::None);
2309 ///
2310 /// let mut opt = DirChildSingleOpt::<String, NoFilter>::Some(DirChildSingle::new("file.txt", "file".to_owned()));
2311 /// let taken = opt.take_if(|child| child.value() == "other");
2312 /// assert_eq!(taken, DirChildSingleOpt::None);
2313 /// assert_eq!(opt, DirChildSingleOpt::Some(DirChildSingle::new("file.txt", "file".to_owned())));
2314 ///
2315 /// let mut opt = DirChildSingleOpt::<String, NoFilter>::None;
2316 /// let taken = opt.take_if(|child| child.value() == "file");
2317 /// assert_eq!(taken, DirChildSingleOpt::None);
2318 /// assert_eq!(opt, DirChildSingleOpt::None);
2319 /// ```
2320 pub fn take_if(
2321 &mut self,
2322 pred: impl FnOnce(&DirChildSingle<T, F, P>) -> bool,
2323 ) -> DirChildSingleOpt<T, F, P> {
2324 match self {
2325 DirChildSingleOpt::Some(child) if pred(child) => {
2326 mem::replace(self, DirChildSingleOpt::None)
2327 }
2328 _ => DirChildSingleOpt::None,
2329 }
2330 }
2331}
2332
2333impl<T, F, P: PathType + ?Sized> fmt::Debug for DirChildSingleOpt<T, F, P>
2334where
2335 T: fmt::Debug,
2336 F: Filter<P>,
2337 <P as PathType>::PathSegmentOwned: fmt::Debug,
2338{
2339 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2340 match self {
2341 DirChildSingleOpt::Some(child) => f
2342 .debug_tuple("DirChildSingleOpt::Some")
2343 .field(child)
2344 .finish(),
2345 DirChildSingleOpt::None => write!(f, "DirChildSingleOpt::None"),
2346 }
2347 }
2348}
2349
2350impl<'a, T, F, Vfs: vfs::Vfs<'a>> ReadFrom<'a, Vfs> for DirChildSingleOpt<T, F, Vfs::Path>
2351where
2352 T: ReadFrom<'a, Vfs>,
2353 F: Filter<Vfs::Path> + 'a,
2354{
2355 fn read_from(path: &Vfs::Path, vfs: Pin<&'a Vfs>) -> VfsResult<Self, Vfs>
2356 where
2357 Self: Sized,
2358 {
2359 let children = DirChildren::<T, F, Vfs::Path>::read_from(path, vfs)?;
2360 if children.len() == 1 {
2361 let child = children.children.into_iter().next().unwrap();
2362 Ok(DirChildSingleOpt::Some(DirChildSingle {
2363 file_name: child.file_name,
2364 value: child.value,
2365 _phantom: PhantomData,
2366 }))
2367 } else if children.is_empty() {
2368 Ok(DirChildSingleOpt::None)
2369 } else {
2370 Err(Error::UnexpectedNumberOfChildren {
2371 expected: "0 or 1",
2372 found: children.len(),
2373 path: path.owned(),
2374 })
2375 }
2376 }
2377}
2378
2379impl<'a, T, F, Vfs: vfs::WriteSupportingVfs<'a>> WriteTo<'a, Vfs>
2380 for DirChildSingleOpt<T, F, Vfs::Path>
2381where
2382 T: WriteTo<'a, Vfs>,
2383 F: Filter<Vfs::Path>,
2384{
2385 fn write_to(&self, path: &Vfs::Path, vfs: Pin<&'a Vfs>) -> VfsResult<(), Vfs> {
2386 match self {
2387 DirChildSingleOpt::Some(child) => child.write_to(path, vfs),
2388 DirChildSingleOpt::None => Ok(()),
2389 }
2390 }
2391}
2392
2393/// A wrapper around [`DirChildren`] that forces the creation of the directory, even if there are no children to write.
2394#[derive(Clone, PartialEq, Eq)]
2395#[cfg_attr(feature = "assert_eq", derive(assert_eq::AssertEq))]
2396pub struct ForceCreateDirChildren<T, F = NoFilter, P: PathType + ?Sized = Path>
2397where
2398 F: Filter<P>,
2399{
2400 children: DirChildren<T, F, P>,
2401}
2402
2403impl<T, F, P: PathType + ?Sized> fmt::Debug for ForceCreateDirChildren<T, F, P>
2404where
2405 F: Filter<P>,
2406 T: fmt::Debug,
2407 <P as PathType>::PathSegmentOwned: fmt::Debug,
2408{
2409 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2410 f.debug_struct("ForceCreateDirChildren")
2411 .field("children", &self.children)
2412 .finish()
2413 }
2414}
2415
2416impl<T, F, P> ForceCreateDirChildren<T, F, P>
2417where
2418 F: Filter<P>,
2419 P: PathType + ?Sized,
2420{
2421 /// Creates a new [`ForceCreateDirChildren`] with the specified children.
2422 ///
2423 /// # Examples
2424 ///
2425 /// ```rust
2426 /// use dir_structure::dir_children::{ForceCreateDirChildren, DirChildren};
2427 /// use dir_structure::NoFilter;
2428 ///
2429 /// let force_create = ForceCreateDirChildren::new(DirChildren::<String, NoFilter>::new());
2430 ///
2431 /// assert_eq!(force_create.len(), 0);
2432 /// ```
2433 pub fn new(children: DirChildren<T, F, P>) -> Self {
2434 ForceCreateDirChildren { children }
2435 }
2436
2437 /// Creates a new [`ForceCreateDirChildren`] from an iterator of [`DirChild`]s.
2438 ///
2439 /// # Examples
2440 ///
2441 /// ```rust
2442 /// use dir_structure::dir_children::{ForceCreateDirChildren, DirChild, DirChildren};
2443 /// use dir_structure::NoFilter;
2444 ///
2445 /// let children = vec![
2446 /// DirChild::new("file1.txt", "content1".to_owned()),
2447 /// DirChild::new("file2.txt", "content2".to_owned()),
2448 /// ];
2449 /// let force_create = ForceCreateDirChildren::<_, NoFilter>::with_children_from_iter(children);
2450 ///
2451 /// assert_eq!(force_create.len(), 2);
2452 /// ```
2453 pub fn with_children_from_iter<I>(iter: I) -> Self
2454 where
2455 I: IntoIterator<Item = DirChild<T, P>>,
2456 {
2457 Self::new(DirChildren::from_iter(iter))
2458 }
2459}
2460
2461impl<T, F, P: PathType + ?Sized> AsRef<DirChildren<T, F, P>> for ForceCreateDirChildren<T, F, P>
2462where
2463 F: Filter<P>,
2464{
2465 fn as_ref(&self) -> &DirChildren<T, F, P> {
2466 &self.children
2467 }
2468}
2469
2470impl<T, F, P: PathType + ?Sized> AsMut<DirChildren<T, F, P>> for ForceCreateDirChildren<T, F, P>
2471where
2472 F: Filter<P>,
2473{
2474 fn as_mut(&mut self) -> &mut DirChildren<T, F, P> {
2475 &mut self.children
2476 }
2477}
2478
2479impl<T, F, P: PathType + ?Sized> From<DirChildren<T, F, P>> for ForceCreateDirChildren<T, F, P>
2480where
2481 F: Filter<P>,
2482{
2483 fn from(children: DirChildren<T, F, P>) -> Self {
2484 ForceCreateDirChildren { children }
2485 }
2486}
2487
2488impl<T, F, P: PathType + ?Sized> From<ForceCreateDirChildren<T, F, P>> for DirChildren<T, F, P>
2489where
2490 F: Filter<P>,
2491{
2492 fn from(force_create: ForceCreateDirChildren<T, F, P>) -> Self {
2493 force_create.children
2494 }
2495}
2496
2497impl<T, F, P: PathType + ?Sized> FromIterator<DirChild<T, P>> for ForceCreateDirChildren<T, F, P>
2498where
2499 F: Filter<P>,
2500{
2501 fn from_iter<I: IntoIterator<Item = DirChild<T, P>>>(iter: I) -> Self {
2502 ForceCreateDirChildren {
2503 children: DirChildren::from_iter(iter),
2504 }
2505 }
2506}
2507
2508impl<T, F, P: PathType + ?Sized> Deref for ForceCreateDirChildren<T, F, P>
2509where
2510 F: Filter<P>,
2511{
2512 type Target = DirChildren<T, F, P>;
2513
2514 fn deref(&self) -> &Self::Target {
2515 &self.children
2516 }
2517}
2518
2519impl<T, F, P: PathType + ?Sized> DerefMut for ForceCreateDirChildren<T, F, P>
2520where
2521 F: Filter<P>,
2522{
2523 fn deref_mut(&mut self) -> &mut Self::Target {
2524 &mut self.children
2525 }
2526}
2527
2528impl<'a, T, F, Vfs: vfs::Vfs<'a>> ReadFrom<'a, Vfs> for ForceCreateDirChildren<T, F, Vfs::Path>
2529where
2530 T: ReadFrom<'a, Vfs>,
2531 F: Filter<Vfs::Path> + 'a,
2532{
2533 fn read_from(path: &Vfs::Path, vfs: Pin<&'a Vfs>) -> VfsResult<Self, Vfs>
2534 where
2535 Self: Sized,
2536 {
2537 DirChildren::<T, F, Vfs::Path>::read_from(path, vfs)
2538 .map(|children| ForceCreateDirChildren { children })
2539 }
2540}
2541
2542impl<'a, T, F, Vfs: vfs::WriteSupportingVfs<'a>> WriteTo<'a, Vfs>
2543 for ForceCreateDirChildren<T, F, Vfs::Path>
2544where
2545 T: WriteTo<'a, Vfs>,
2546 F: Filter<Vfs::Path>,
2547{
2548 fn write_to(&self, path: &Vfs::Path, vfs: Pin<&'a Vfs>) -> VfsResult<(), Vfs> {
2549 vfs.create_dir_all(path)?;
2550
2551 self.children.write_to(path, vfs)
2552 }
2553}
2554
2555#[cfg(feature = "async")]
2556#[pin_project]
2557#[doc(hidden)]
2558pub struct ForceCreateDirChildrenReadAsyncFuture<'a, T, F, Vfs: VfsAsync>
2559where
2560 T: ReadFromAsync<'a, Vfs> + 'static,
2561 F: Filter<Vfs::Path> + Send + 'static,
2562 T::Future: Future<Output = VfsResult<T, Vfs>> + Send + Unpin,
2563{
2564 #[pin]
2565 inner: DirChildrenReadAsyncFuture<'a, T, F, Vfs>,
2566}
2567
2568#[cfg(feature = "async")]
2569#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
2570impl<'a, T, F, Vfs: VfsAsync> Future for ForceCreateDirChildrenReadAsyncFuture<'a, T, F, Vfs>
2571where
2572 T: ReadFromAsync<'a, Vfs> + Send + Sync + 'static,
2573 F: Filter<Vfs::Path> + Send + 'static,
2574 T::Future: Future<Output = VfsResult<T, Vfs>> + Unpin + 'static,
2575{
2576 type Output = VfsResult<ForceCreateDirChildren<T, F, Vfs::Path>, Vfs>;
2577
2578 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
2579 let this = self.as_mut().project();
2580
2581 match this.inner.poll(cx) {
2582 Poll::Ready(Ok(children)) => Poll::Ready(Ok(ForceCreateDirChildren { children })),
2583 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
2584 Poll::Pending => Poll::Pending,
2585 }
2586 }
2587}
2588
2589#[cfg(feature = "async")]
2590#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
2591impl<'a, T, F, Vfs: VfsAsync + 'a> ReadFromAsync<'a, Vfs>
2592 for ForceCreateDirChildren<T, F, Vfs::Path>
2593where
2594 T: ReadFromAsync<'a, Vfs> + Send + Sync + 'static,
2595 F: Filter<Vfs::Path> + Send + Sync + 'static,
2596 T::Future: Future<Output = VfsResult<T, Vfs>> + Unpin + 'static,
2597{
2598 type Future = ForceCreateDirChildrenReadAsyncFuture<'a, T, F, Vfs>;
2599
2600 fn read_from_async(
2601 path: <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
2602 vfs: Pin<&'a Vfs>,
2603 ) -> Self::Future {
2604 ForceCreateDirChildrenReadAsyncFuture {
2605 inner: DirChildren::read_from_async(path, vfs),
2606 }
2607 }
2608}
2609
2610#[cfg(feature = "async")]
2611#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
2612impl<'a, T, F, Vfs: WriteSupportingVfsAsync + 'static> WriteToAsync<'a, Vfs>
2613 for ForceCreateDirChildren<T, F, Vfs::Path>
2614where
2615 T: WriteToAsync<'a, Vfs> + Send + Sync + 'static,
2616 F: Filter<Vfs::Path> + Send + Sync + 'static,
2617 T::Future: Future<Output = VfsResult<(), Vfs>> + Unpin + 'a,
2618{
2619 type Future = Pin<Box<dyn Future<Output = VfsResult<(), Vfs>> + Send + 'a>>;
2620
2621 fn write_to_async(
2622 self,
2623 path: <<Vfs as VfsCore>::Path as PathType>::OwnedPath,
2624 vfs: Pin<&'a Vfs>,
2625 ) -> Self::Future {
2626 Box::pin(async move {
2627 vfs.create_dir_all(path.clone()).await?;
2628
2629 self.children.write_to_async(path, vfs).await
2630 })
2631 }
2632}
2633
2634#[cfg(feature = "resolve-path")]
2635#[cfg_attr(docsrs, doc(cfg(feature = "resolve-path")))]
2636impl<T, F, P: PathType + ?Sized> DynamicHasField for ForceCreateDirChildren<T, F, P>
2637where
2638 F: Filter<P>,
2639{
2640 type Inner = T;
2641
2642 fn resolve_path<Pt: OwnedPathType>(mut p: Pt, name: &str) -> Pt {
2643 p.push_segment_str(name);
2644 p
2645 }
2646}